Java8新特性(五):日期和时间

289 阅读5分钟

日期和时间

前言

  • Date如果不格式化,打印出的日期可读性差
		Tue Sep 10 09:34:04 CST 2019
  • 使用SimpleDateFormat对时间进行格式化,但SimpleDateFormat是线程不安全的。阿里巴巴开发手册中禁用static修饰SimpleDateFormat

    • 在多线程环境下,当多个线程同时使用相同的SimpleDateFormat对象(如static修饰)的话,如调用format方法时,多个线程会同时调用calender.setTime方法,导致time被别的线程修改,因此线程是不安全的。此外,parse方法也是线程不安全的,parse方法实际调用的是CalenderBuilder的establish来进行解析,其方法中主要步骤不是原子操作。

    • 解决方案:

      1、将SimpleDateFormat定义成局部变量

      2、 加一把线程同步锁:synchronized(lock)

      3、使用ThreadLocal,每个线程都拥有自己的SimpleDateFormat对象副本。如:

  • Java有两套日期和时间的API:

    • 旧的Date、Calendar和TimeZone;
    • 新的LocalDateTime、ZonedDateTime、ZoneId等;
    • 分别位于java.util和java.time包中。
  • 从Java 8开始,java.time包提供了新的日期和时间API,主要涉及的类型有:

    • 本地日期和时间:LocalDateTime,LocalDate,LocalTime;
    • 带时区的日期和时间:ZonedDateTime;
    • 时刻:Instant;
    • 时区:ZoneId,ZoneOffset;
    • 时间间隔:Duration;
    • 以及一套新的用于取代SimpleDateFormat的格式化类型DateTimeFormatter。

和旧的API相比,新API严格区分了时刻、本地日期、本地时间和带时区的日期时间,并且,对日期和时间进行运算更加方便。

  • 此外,新API修正了旧API不合理的常量设计:
    • Month的范围用1~12表示1月到12月;
    • Week的范围用1~7表示周一到周日。 最后,新API的类型几乎全部是不变类型(和String类似),可以放心使用不必担心被修改。

LocalDateTime

初始化一个LocalDateTime

      LocalDateTime localDateTime = LocalDateTime.now();
      LocalDateTime localDateTime1 = LocalDateTime.of(2019, Month.SEPTEMBER, 10, 14, 46, 56);
      LocalDate localDate =LocalDate.now() ;
      LocalTime localTime =LocalTime.now() ;
      LocalDateTime localDateTime2 = LocalDateTime.of(localDate, localTime);
      System.out.println("now:"+localDateTime);
      System.out.println("of:"+localDateTime1);
      System.out.println("LocalDateTime of:"+localDateTime2);
	  //结果
      now:2020-12-12T20:33:55.325
      of:2019-09-10T14:46:56
      LocalDateTime of:2020-12-12T20:33:55.326

LocalDateTime = LocalDate + LocalTime

      LocalDate localDate =LocalDate.now() ;
      LocalTime localTime =LocalTime.now() ;
      LocalDateTime localDateTime3 = localDate.atTime(localTime);
      LocalDateTime localDateTime4 = localTime.atDate(localDate);
      System.out.println("atDate:"+localDateTime4);
      System.out.println("atTime:"+localDateTime3);
      //结果
      atTime:2020-12-12T20:33:55.326
      atDate:2020-12-12T20:33:55.326

LocalDateTime中获取LocalDate ,LocalTime

     LocalDateTime localDateTime = LocalDateTime.now();
    LocalDate localDate2 = localDateTime.toLocalDate();
    LocalTime localTime2 = localDateTime.toLocalTime();
    System.out.println("toLocalDate:"+localDate2);
    System.out.println("toLocalTime:"+localTime2);
      //结果
    toLocalDate:2020-12-12
	toLocalTime:20:33:55.325

LocalDate

初始化-获取当前年月日

    LocalDate localDate = LocalDate.now();
    //2020-12-12

初始化-获取指定年月日

    LocalDate localDateOf = LocalDate.of(2019, 9, 10);
	//2019-09-10

获取年份

     LocalDate localDate = LocalDate.now();
     int year = localDate.getYear();//2020
     int year1 = localDate.get(ChronoField.YEAR);//2020

获取月份

LocalDate localDate = LocalDate.now();
Month month = localDate.getMonth(); //DECEMBER
int month1 = localDate.get(ChronoField.MONTH_OF_YEAR);//12

获取当前日是当前月的第几天

LocalDate localDate = LocalDate.now();//2020-12-12
int day = localDate.getDayOfMonth();
int day1 = localDate.get(ChronoField.DAY_OF_MONTH);
//当前年的第几天
LocalDate localDate2 = LocalDate.of(2020, 12, 31);
int day2 = localDate2.get(ChronoField.DAY_OF_YEAR);
//day: 12
//day1: 12
//day2: 366

获取当前日是当前周的第几天

LocalDate localDate = LocalDate.now();//2020-12-12
DayOfWeek dayOfWeek = localDate.getDayOfWeek();
int dayOfWeek1 = localDate.get(ChronoField.DAY_OF_WEEK);
//dayOfWeek: SATURDAY
//dayOfWeek1: 6

LocalTime

初始化

LocalTime localTime = LocalTime.of(18, 51, 10);
LocalTime localTime1 = LocalTime.now();
LocalTime localTime2 = LocalTime.of(13, 51, 10,200);
System.out.println("localTime:"+ localTime);
System.out.println("localTime1:"+ localTime1);
System.out.println("localTime2:"+ localTime2);

//localTime:18:51:10
//localTime1:21:00:00.998
//localTime2:13:51:10.000000200

获取小时

LocalTime localTime = LocalTime.of(18, 51, 10);
int hour = localTime.getHour();
int hour1 = localTime.get(ChronoField.HOUR_OF_DAY);
//0-11
int hour2 = localTime.get(ChronoField.HOUR_OF_AMPM);
System.out.println("getHour:"+hour);
System.out.println("HOUR_OF_DAY:"+hour1);
System.out.println("HOUR_OF_AMPM:"+hour2);
// getHour:18
//HOUR_OF_DAY:18
// HOUR_OF_AMPM:6

获取分钟

LocalTime localTime = LocalTime.of(18, 51, 10);
int minute = localTime.getMinute();
int minute1 = localTime.get(ChronoField.MINUTE_OF_HOUR);
Long minute2 = localTime.getLong(ChronoField.MICRO_OF_DAY);
System.out.println("getMinute:"+minute);
System.out.println("MINUTE_OF_HOUR:"+minute1);
System.out.println("MICRO_OF_DAY:"+minute2);

//getMinute:51
// MINUTE_OF_HOUR:51
// MICRO_OF_DAY:67870000000

获取秒

LocalTime localTime = LocalTime.of(18, 51, 10);
int second = localTime.getSecond();
int second1 = localTime.get(ChronoField.SECOND_OF_MINUTE);
System.out.println("getSecond:"+second);
System.out.println("SECOND_OF_MINUTE:"+second1);

//getSecond:10
 //SECOND_OF_MINUTE:10

Instant

在java.util.Date类与LocalDate、LocalDateTime类之间转换中 均可以通过Instant作为中间类完成转换,Instant的使用还是比较方便的,下面介绍Instant的使用。

Instant instant = Instant.now();
//获取秒数
long currentSecond = instant.getEpochSecond();
System.out.println(currentSecond);
//获取毫秒数
long currentMilli = instant.toEpochMilli();
System.out.println(currentMilli);
//获取毫秒数
System.out.println(System.currentTimeMillis());

//1607778302
//1607778302067
//1607778302067

日期时间进行运算

LocalDate、LocalTime、LocalDateTime、Instant为不可变对象,修改这些对象对象会返回一个副本

增加一年

LocalDateTime localDateTime = LocalDateTime.of(2019, Month.SEPTEMBER, 10,14, 46, 56);
System.out.println("of:" + localDateTime.toString());

//增加一年
localDateTime = localDateTime.plusYears(1);
System.out.println("plusYears:" + localDateTime);
localDateTime = localDateTime.plus(1, ChronoUnit.YEARS);
System.out.println("plus:" + localDateTime);

// of:2019-09-10T14:46:56
// plusYears:2020-09-10T14:46:56
//  plus:2021-09-10T14:46:56

减少一个月

LocalDateTime localDateTime = LocalDateTime.of(2019, Month.SEPTEMBER, 10,14, 46, 56);
localDateTime = localDateTime.minusMonths(1);
System.out.println("minusMonths:" + localDateTime);
localDateTime = localDateTime.minus(1, ChronoUnit.MONTHS);
System.out.println("minus:" + localDateTime);

//minusMonths:2019-08-10T14:46:56
//minus:2019-07-10T14:46:56

### 修改年为2019
LocalDateTime localDateTime = LocalDateTime.of(2019, Month.SEPTEMBER, 10,14, 46, 56);
System.out.println("of:" + localDateTime.toString());
    //修改年为2019
localDateTime = localDateTime.withYear(2020);
System.out.println("withYear:" + localDateTime);
//修改为2022
localDateTime = localDateTime.with(ChronoField.YEAR, 2022);
System.out.println("with:" + localDateTime);

//of:2019-09-10T14:46:56
//withYear:2020-09-10T14:46:56
// with:2022-09-10T14:46:56

firstDayOfYear()

LocalDate localDate = LocalDate.now();
LocalDate localDate1 = localDate.with(firstDayOfYear());
System.out.println("firstDayOfYear:" + localDate1);
//firstDayOfYear:2020-01-01

格式化时间

LocalDate localDate = LocalDate.now();
String s1 = localDate.format(DateTimeFormatter.BASIC_ISO_DATE);
String s2 = localDate.format(DateTimeFormatter.ISO_LOCAL_DATE);
System.out.println("BASIC_ISO_DATE:" + s1);
System.out.println("ISO_LOCAL_DATE:" + s2);

// BASIC_ISO_DATE:20201212
//ISO_LOCAL_DATE:2020-12-12

自定义格式化(DateTimeFormatter)

和SimpleDateFormat相比,DateTimeFormatter是线程安全的

DateTimeFormatter dateTimeFormatter = (DateTimeFormatter).ofPattern("dd/MM/yyyy");
String s3 = localDate.format(dateTimeFormatter);
System.out.println("ofPattern:" + s3);
//ofPattern:12/12/2020

解析时间

LocalDate localDate11 = LocalDate.parse("20190910", DateTimeFormatter.BASIC_ISO_DATE);
LocalDate localDate12 = LocalDate.parse("2019-09-10", DateTimeFormatter.ISO_LOCAL_DATE);
System.out.println("parse BASIC_ISO_DATE:" + localDate11);
System.out.println("parse ISO_LOCAL_DATE:" + localDate12);

// parse BASIC_ISO_DATE:2019-09-10
//parse ISO_LOCAL_DATE:2019-09-10

常用

将LocalDateTime字段以指定格式化日期的方式返回给前端

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
protected LocalDateTime gmtModified;

对前端传入的日期进行格式化

@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
protected LocalDateTime gmtModified;

源码下载

本文章例子源码

Java8新特性系列