Java时间、日期类和时间、日期的格式化

Java标准库有两套处理时间和日期的API:

  • 一套定义在java.util包中,主要有Date、Calendar
  • 一套新的API是在Java 8引入的,定义在java.time包中,主要有LocalDate、LocalTime、LocalDataTime

原因:由于历史遗留原因,旧的API存在很多问题,所以引入了新的API。

Java 8之前的API

Date

java.util.Date是用来表示一个时间和日期的对象。

缺点:

  1. Date总是以当前计算机系统的默认时区为基础进行输出
  2. 很难对日期和时间进行加减、计算两个日期相差几天、计算下个星期日的日期等

常用方法:

  • getYear()返回的年份必须加上1900。

  • getMonth()返回的月份是011分别表示112月,所以要加1。

  • getDate()返回的日期范围是1~31,不能加1。

  • getDay()返回的星期范围是0~6,星期天为0。

为了精确控制时间和日期的格式,可以使用SimpleDateFormat对一个Date进行转换,用预定义的字符串表示格式化:

  • yyyy:年
  • MM:月
  • dd:日
  • HH:小时
  • mm:分钟
  • ss:秒
  • SSS:毫秒

Date类示例:

public class Main
{
    public static void main(String[] args)
    {
        //1、获取当前日期
        Date now = new Date();
        System.out.println(now.getYear() + 1900); //2020    必须加上1900
        System.out.println(now.getMonth() + 1);//8    0-11,必须加上1
        System.out.println(now.getDate());//24    0-31,不能加1
        System.out.println(now.getDay()); //1     0-6,以星期天(0)开始
        System.out.println(now.toString());//Mon Aug 24 21:14:24 CST 2020
        System.out.println(now.toLocaleString());//2020-8-24 21:14:24

        //2、基本的日期比较
        Date other = new Date(now.getTime() + 1);
        System.out.println(now.after(other));//false
        System.out.println(now.before(other));//true

        //3、使用SimpleDateFormat进行日期格式化
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println(format.format(now));//2020-08-24 21:14:24

        //3.1使用自定义日期格式化
        SimpleDateFormat predefineFormat = new SimpleDateFormat("E yyyy-MM-dd");
        System.out.println(predefineFormat.format(now));//星期一 2020-08-24
    }
}

其他格式语法介绍:

  • G:公元
  • E:一周中的周几
  • D:一年中的第几天
  • w:一年中的第几个星期
  • a:上下/下午 标记符
  • k:时(1~24)
  • K:时 在上午或下午(0~11)

其他格式语法示例:

public class Main
{
    public static void main(String[] args)
    {
        //获取当前日期
        Date now = new Date();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println(format.format(now));//2020-08-24 21:32:33
        SimpleDateFormat format1 = new SimpleDateFormat("G E D w a k K yyyy-MM-dd");
        System.out.println(format1.format(now));//公元 星期一 237 35 下午 21 9 2020-08-24
    }
}

Calendar

java.util.Calendar可以用于获取并设置年、月、日、时、分、秒,它和Date比,主要多了一个可以做简单的日期和时间运算的功能。

常用方法:

  • get(Calendar.YEAR):获取指定字段的值,参数为预定义的常量,返回值均为int。年份时不需要加上1900,月份时返回范围0~11。
  • set(Calendar.YEAR,2020):设置指定字段的值。
  • add(Calendar.YEAR,2):增加指定字段的值,可以为负数

参数和返回值均为int类型。

Calendar类示例:

public class Main
{
    public static void main(String[] args)
    {
        //1、获取当前时间(唯一的方法)
        Calendar now = Calendar.getInstance();
        int y = now.get(Calendar.YEAR);//不用再加1900
        int m = now.get(Calendar.MONTH) + 1;//仍要加1
        int d = now.get(Calendar.DAY_OF_MONTH);
        int w = now.get(Calendar.DAY_OF_WEEK);//1-7 星期日为1
        int hh = now.get(Calendar.HOUR_OF_DAY);
        int mm = now.get(Calendar.MINUTE);
        int ss = now.get(Calendar.SECOND);
        int ms = now.get(Calendar.MILLISECOND);
        System.out.println(y + "-" + m + "-" + d + " " + hh + ":" + mm + ":" + ss + "." + ms + "  " + w);
        //输出:2020-8-24 21:35:21.166  2
        
        //2、设置其他的时间
        now.clear();//必须先清除,否则未设置的值(如时、分、秒)会以已有值进行显示
        now.set(Calendar.YEAR, 2018);
        now.set(Calendar.MONTH, 9);//月份会加1
        now.set(Calendar.DAY_OF_MONTH, 1);
        now.set(Calendar.HOUR_OF_DAY, 10);
        now.set(Calendar.MINUTE, 10);
        now.set(Calendar.SECOND, 1);
        //        now.set(2018,9,1,10,10,2); //等同于上面的设置
        System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(now.getTime()));
        //输出:2018-10-01 10:10:01

        //3、简单的时间/日期运算
        Calendar c = Calendar.getInstance();
        c.add(Calendar.YEAR, 1);//可以为负数
        System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(c.getTime()));
        //输出:2021-08-24 21:35:21
    }
}

可以使用Calendar写一个DateUtils类,提供一些公共方法。

DateUtils类示例:

public final class DateUtils
{

    /**
     * 获取星期几
     *
     * @param date 要获取星期的日期
     * @return 星期几,星期日为1,星期一为2,以此类推
     */
    public static int getWeek(Date date)
    {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        return c.get(Calendar.DAY_OF_WEEK);
    }

    /**
     * 获取星期几
     *
     * @return 星期几,星期日为1,星期一为2,以此类推 季度
     */
    public static int getWeek()
    {
        Calendar c = Calendar.getInstance();
        return c.get(Calendar.DAY_OF_WEEK);
    }


    /**
     * 获取季度
     *
     * @param date 要获取季度的日期
     * @return 季度,一季度为0,第二季度为1,第三季度为2,第三季度为3
     */
    public static int getQuarter(Date date)
    {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        return c.get(Calendar.MONTH) / 3;
    }

    /**
     * 获取当前季度
     *
     * @return 季度,一季度为0,第二季度为1,第三季度为2,第三季度为3
     */
    public static int getQuarter()
    {
        Calendar c = Calendar.getInstance();
        return c.get(Calendar.MONTH) / 3;
    }

    /**
     * 增加月
     *
     * @param date  增加前的日期
     * @param month 增加的月数
     * @return 增加后的日期
     */
    public static Date addMonth(Date date, int month)
    {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(Calendar.MONTH, month);

        return c.getTime();
    }


    /**
     * 增加季度
     *
     * @param date    增加前的日期
     * @param quarter 增加的季度数
     * @return 增加后的日期
     */
    public static Date addQuarter(Date date, int quarter)
    {
        return addMonth(date, quarter * 3);
    }


    /**
     * 获取当月的最后一天
     *
     * @param date 日期
     * @return 当月最后一天
     */
    public static Date getMonthEnd(Date date)
    {
        Calendar c = Calendar.getInstance();
        c.setTime(date);

        c.set(Calendar.HOUR_OF_DAY, 0);
        c.set(Calendar.MINUTE, 0);
        c.set(Calendar.SECOND, 0);
        c.set(Calendar.MILLISECOND, 0);
        c.set(Calendar.DATE, 1);
        c.add(Calendar.MONTH, 1);
        c.add(Calendar.DAY_OF_MONTH, -1);
        return c.getTime();
    }
}

Java 8的API

本地日期和时间:LocalDateTimeLocalDateLocalTime;(默认严格按照ISO 8601规定的日期和时间格式进行打印),以上三个类都提供静态方法now()获取当前时间日期/日期/时间对象
时间间隔:Duration
用于取代SimpleDateFormat的格式化类型:DateTimeFormatter

改进点:新API修正了旧API不合理的常量设计
Month的范围用1~12表示1月到12月;
Week的范围用1~7表示周一到周日

LocalDateTime、LocalDate、LocalTime

获取本地的当前日期和时间:

public class Main
{
    public static void main(String[] args)
    {
        //获取当前日期和时间now()
        LocalDateTime now = LocalDateTime.now();
        LocalDate localDate = now.toLocalDate();//转为当前日期
        LocalTime localTime = now.toLocalTime();//转为当前时间
        System.out.println(now);//2020-08-24T22:36:24.071
        System.out.println(localDate);//2020-08-24
        System.out.println(localTime);//22:36:24.071
    }
}

通过of()方法,以指定的日期和时间创建LocalDateTime

public class Main
{
    public static void main(String[] args)
    {
        LocalDate date = LocalDate.of(2020, 10, 1);//2020-10-01
        LocalTime time = LocalTime.of(10, 1, 1);//10:01:01
        LocalDateTime localDateTime = LocalDateTime.of(date, time);
        System.out.println(localDateTime);//2020-10-01T10:01:01
        
        LocalDateTime localDateTime2 = LocalDateTime.of(2020, 10, 1, 10, 1, 1);
        System.out.println(localDateTime2);//2020-10-01T10:01:01
    }
}

因为严格按照ISO 8601的格式,因此,将字符串转换为LocalDateTime就可以传入标准格式:

public class Main
{
    public static void main(String[] args)
    {
        //使用字符串 parse()
        LocalDate parseDate = LocalDate.parse("2019-10-01");
        LocalTime parseTime = LocalTime.parse("10:01:01");
        //ISO 8601规定的日期和时间间隔符为T
        LocalDateTime parseDateTime = LocalDateTime.parse("2019-10-01T10:01:01.111");
        System.out.println(parseDate);
        System.out.println(parseTime);
        System.out.println(parseDateTime);
    }
}

注意ISO 8601规定的日期和时间分隔符是T。标准格式如下:

  • 日期:yyyy-MM-dd
  • 时间:HH:mm:ss
  • 带毫秒的时间:HH:mm:ss.SSS
  • 日期和时间:yyyy-MM-ddTHH:mm:ss
  • 带毫秒的日期和时间:yyyy-MM-ddTHH:mm:ss.SSS

自定义输出格式 DateTimeFormatter

public class Main
{
    public static void main(String[] args)
    {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH-mm-ss");
        System.out.println(formatter.format(LocalDateTime.now())); // 2020/08/24 22-36-24

        LocalDateTime parse = LocalDateTime.parse("2019/10/01 10-01-01", formatter);
        System.out.println(parse);//2019-10-01T10:01:01
    }
}

LocalDateTime提供了对日期和时间进行加减的非常简单的链式调用:

public class Main
{
    public static void main(String[] args)
    {
        // 使用plusXxx()方法进行增加,例如plusDays(7)会把2020-08-24变为2020-08-31
        // 使用minusXxx()方法进行减少,例如minusDays(7)会把2020-08-24变为2020-08-17
        LocalDateTime dateTime = LocalDateTime.of(2020, 8, 24, 10, 1, 1);
        System.out.println("原始时间:" + dateTime);//原始时间:2020-08-24T10:01:01
        //加7天减1小时
        LocalDateTime dt1 = dateTime.plusDays(7).minusHours(1);
        System.out.println("增加7天并减去1小时后:" + dt1);//增加7天并减去1小时后:2020-08-31T09:01:01
        LocalDateTime dt2 = dt1.plusMonths(1);
        System.out.println("增加1个月后:" + dt2);// 增加1个月后:2020-09-30T09:01:01 月份加减时会自动调整日期,例如从2020-08-31减去一个月的结果是2020-09-30
    }
}

对日期和时间进行调整则使用withXxx()方法,例如:withHour(15)会把10:11:12变为15:11:12

  • 调整年:withYear()
  • 调整月:withMonth()
  • 调整日:withDayOfMonth()
  • 调整时:withHour()
  • 调整分:withMinute()
  • 调整秒:withSecond()
public class Main
{
    public static void main(String[] args)
    {
        LocalDateTime dateTime5 = LocalDateTime.of(2020, 8, 31, 10, 1, 1);
        System.out.println("原始时间:" + dateTime5);//原始时间:2020-08-31T10:01:01
        LocalDateTime dateTime5After = dateTime5.withMonth(9);
        System.out.println("调整月份后:" + dateTime5After);//调整月份后:2020-09-30T10:01:01 月份调整时也会自动调整日期
    }
}

Duration和Period

Duration表示两个时刻之间的时间间隔。另一个类似的Period表示两个日期之间的天数:

public class Main
{
    public static void main(String[] args)
    {
        LocalDateTime end = LocalDateTime.of(2020, 10, 1, 10, 1, 1);
        LocalDateTime start = LocalDateTime.now();
        System.out.println("当前时间:" + start);//当前时间:2020-08-24T23:18:41.030

        //时间
        Duration duration = Duration.between(start, end);
        System.out.println("间隔天数:" + duration.toDays());//间隔天数:37
        System.out.println("间隔小时数:" +duration.toHours());//间隔小时数:898
        System.out.println("间隔分钟数:" +duration.toMinutes());//间隔分钟数:53922
        System.out.println("间隔秒数:" +duration.toMillis());//间隔秒数:3235339970

        //日期
        Period period = LocalDate.of(2019, 10, 1).until(LocalDate.of(2020, 10, 10));
        System.out.println("间隔年数:" + period.getYears());//间隔年数:1
        System.out.println("间隔月数:" + period.getMonths());//间隔月数:0
        System.out.println("间隔天数:" + period.getDays());//间隔月数:9
    }
}
posted @ 2020-08-24 23:24  一如昨日  阅读(1237)  评论(0)    收藏  举报