Java_日期时间下(14)

java.time 包

java.util 包处理时间的 API 很差,所以一般都采用第三方的 Joda-Time

Java 8 新增的 java.time 包中整合了很多 Joda-Time 的特性,Joda-Time 的 官网 也说了 Java 8 之后就转去用 java.time 吧

LocalDate、LocalTime、LocalDateTime

LocalDate、LocalTime、LocalDateTime 是为了方便人阅读,now 方法使用的是系统默认时区

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
public class Test {
  public static void main(String[] args) {
    //LocalDate date = LocalDate.now();
    //LocalDate data = LocalDate.parse("2019-06-09");
    LocalDate date = LocalDate.of(2019, 6, 9);
    System.out.println(date);                 //2019-06-09
    System.out.println(date.getYear());       //2019
    System.out.println(date.getMonth());      //JUNE
    System.out.println(date.getMonthValue()); //6
    System.out.println(date.getDayOfMonth()); //9
    System.out.println(date.getDayOfWeek());  //SUNDAY
    System.out.println(date.isLeapYear());    //false
    //还可以传入TemporalField参数给get获取信息
    System.out.println(date.get(ChronoField.YEAR));         //2019
    System.out.println(date.get(ChronoField.DAY_OF_MONTH)); //9
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
public class Test {
  public static void main(String[] args) {
    //LocalTime time = LocalTime.now();
    //LocalTime time = LocalTime.parse("21:54:10");
    LocalTime time = LocalTime.of(21, 54, 10);
    System.out.println(time);             //21:54:10
    System.out.println(time.getHour());   //21
    System.out.println(time.getMinute()); //54
    System.out.println(time.getSecond()); //10
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
public class Test {
  public static void main(String[] args) {
    //LocalDateTime dt = LocalDateTime.now();
    LocalDate date = LocalDate.of(2019, 6, 9);
    LocalTime time = LocalTime.of(21, 54, 10);
    LocalDateTime dt1 = LocalDateTime.of(2019, Month.JUNE, 9, 21, 54, 10);
    LocalDateTime dt2 = LocalDateTime.of(date, time);
    LocalDateTime dt3 = date.atTime(time);
    LocalDateTime dt4 = time.atDate(date);
    System.out.println(dt1);               //2019-06-09T21:54:10
    System.out.println(dt1.toLocalDate()); //2019-06-09
    System.out.println(dt1.toLocalTime()); //21:54:10
  }
}

基本的修改日期时间的 API

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
public class Test {
  public static void main(String[] args) {
    LocalDateTime dt = LocalDateTime.of(2019, Month.JUNE, 9, 21, 54, 10);
    dt.withYear(2020);
    //修改之后返回一个新对象
    System.out.println(dt.withMonth(9));   //2019-09-09T21:54:10
    dt.with(ChronoField.MONTH_OF_YEAR, 9);
    dt.withDayOfMonth(20);
    dt.plusHours(1);                       
    dt.minusMinutes(10);
    dt.plus(1, ChronoUnit.MONTHS);
    //加减的方法定义在Temporal接口中,ChronoUnit枚举是TemporalUnit的实现类
    System.out.println(dt.getDayOfWeek()); //SUNDAY
    System.out.println(dt.getSecond());    //10
    //不会修改原对象
    System.out.println(dt);                //2019-06-09T21:54:10
  }
}

TemporalAdjuster

可以向 with 方法传入一个 TemporalAdjuster 对象处理日期,可以使用预定义的 TemporalAdjuster

1
2
3
4
5
6
public class Test {
  public static void main(String[] args) {
    LocalDateTime dt = LocalDateTime.of(2019, Month.JUNE, 9, 21, 54, 10);
    System.out.println(dt.with(lastDayOfMonth())); //2019-06-30T21:54:10
  }
}

也可以自定义 TemporalAdjuster,例如,根据当前日期计算下一个工作日

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
public class Test {
  public static void main(String[] args) {
    LocalDate date = LocalDate.now();
    NextWorkingDay nextWorkingDay = new NextWorkingDay();
    System.out.println(date.with(nextWorkingDay)); //2019-06-10
  }
}
class NextWorkingDay implements TemporalAdjuster {
  @Override
  public Temporal adjustInto(Temporal temporal) {
    DayOfWeek dow = DayOfWeek.of(temporal.get(ChronoField.DAY_OF_WEEK));
    int dayToAdd = 1;
    if (dow == DayOfWeek.FRIDAY) {
      dayToAdd = 3;
    } else if (dow == DayOfWeek.SATURDAY) {
      dayToAdd = 2;
    }
    return temporal.plus(dayToAdd, ChronoUnit.DAYS);
  }
}

内部类的方式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
public class Test {
  public static void main(String[] args) {
    LocalDate date = LocalDate.now();
    System.out.println(date.with(new TemporalAdjuster() {
      @Override
      public Temporal adjustInto(Temporal temporal) {
        DayOfWeek dow = DayOfWeek.of(temporal.get(ChronoField.DAY_OF_WEEK));
        int dayToAdd = 1;
        if (dow == DayOfWeek.FRIDAY) {
          dayToAdd = 3;
        } else if (dow == DayOfWeek.SATURDAY) {
          dayToAdd = 2;
        }
        return temporal.plus(dayToAdd, ChronoUnit.DAYS);
      }
    })); //2019-06-10
  }
}

Lambda 表达式的方式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
public class Test {
  public static void main(String[] args) {
    LocalDate date = LocalDate.now();
    System.out.println(date.with(temporal -> {
      DayOfWeek dow = DayOfWeek.of(temporal.get(ChronoField.DAY_OF_WEEK));
      int dayToAdd = 1;
      if (dow == DayOfWeek.FRIDAY) dayToAdd = 3;
      else if (dow == DayOfWeek.SATURDAY) dayToAdd = 2;
      return temporal.plus(dayToAdd, ChronoUnit.DAYS);
    })); //2019-06-10
  }
}

TemporalAdjuster 的静态工厂方式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
public class Test {
  public static void main(String[] args) {
    LocalDate date = LocalDate.now();
    TemporalAdjuster nextWorkingDay = TemporalAdjusters.ofDateAdjuster(
      temporal -> {
        DayOfWeek dow = DayOfWeek.of(temporal.get(ChronoField.DAY_OF_WEEK));
        int dayToAdd = 1;
        if (dow == DayOfWeek.FRIDAY) dayToAdd = 3;
        else if (dow == DayOfWeek.SATURDAY) dayToAdd = 2;
        return temporal.plus(dayToAdd, ChronoUnit.DAYS);
      });
    System.out.println(date.with(nextWorkingDay)); //2019-06-10
  }
}

Instant

Instant 为了方便机器计算,now 方法使用的是 UTC 时间 Clock.systemUTC().instant()

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class Test {
  public static void main(String[] args) {
    //Instant是纳秒级别的,起始时间为GMT
    Instant.ofEpochSecond(3);
    //1970-01-01T00:00:03Z
    System.out.println(Instant.ofEpochSecond(3));
    //Java 8支持的数字下划线
    //1970-01-01T00:00:05Z
    //加2亿纳秒,即加2秒
    System.out.println(Instant.ofEpochSecond(3, 2_000_000_000));
    //1970-01-01T00:00:01Z
    //减2亿纳秒
    System.out.println(Instant.ofEpochSecond(3, -2_000_000_000));
    //2019-06-09T14:22:55.559Z
    System.out.println(Instant.now());
    //增加8小时,2019-06-09T22:22:55.560Z
    System.out.println(Instant.now().plusMillis(TimeUnit.HOURS.toMillis(8)));

    Instant now = Instant.now().plusMillis(TimeUnit.HOURS.toMillis(8));
    System.out.println("秒数 " + now.getEpochSecond()); //秒数 1560118975
    System.out.println("毫秒数 " + now.toEpochMilli()); //毫秒数 1560118975560

    LocalDateTime localDateTime = LocalDateTime.now();
    //LocalDateTime转Instant
    Instant localDateTime2Instant = localDateTime
      .atZone(ZoneId.systemDefault()).toInstant();
    //毫秒数 1560118975560
    System.out.println("毫秒数 " + localDateTime2Instant.toEpochMilli());
  }
}

Period、Duration

Period 表示两个日期的差,Duration 表示两个时间的差,不能计算 LocalDateTime 和 Instant 的差

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
public class Test {
  public static void main(String[] args) {
    LocalDate start = LocalDate.of(2019, 6, 9);
    LocalDate end = LocalDate.of(2020, 5, 19);
    //between()方法返回两个日期之差
    Period period = Period.between(start, end);
    System.out.println(period.getYears());  //0
    System.out.println(period.getMonths()); //11
    System.out.println(period.getDays());   //10
    //如果isNegative()返回false,则表示start早于end
    System.out.println(period.isNegative()); //false

    Period oneDay1 = period.ofDays(1);
    //参数依次为年月日数
    Period oneDay2 = period.of(0, 0, 1);
    System.out.println(oneDay1.getDays()); //1
    System.out.println(oneDay2.getDays()); //1
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
public class Test {
  public static void main(String[] args) {
    LocalTime start  = LocalTime.of(21, 54, 10);
    LocalTime end = LocalTime.of(21, 55, 20);
    Duration duration = Duration.between(start, end);
    System.out.println(duration.getSeconds()); //70
    System.out.println(duration.isNegative()); //false

    Duration oneMin1 = Duration.ofMinutes(1);
    Duration oneMin2 = Duration.of(1, ChronoUnit.MINUTES);
    System.out.println(oneMin1.getSeconds()); //60
    System.out.println(oneMin2.getSeconds()); //60
  }
}

DateTimeFormatter

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
public class Test {
  public static void main(String[] args) {
    LocalDateTime dt = LocalDateTime.now();
    //使用预定义的DateTimeFormatter
    //20190609
    System.out.println(dt.format(DateTimeFormatter.BASIC_ISO_DATE));
    //2019-06-09
    System.out.println(dt.format(DateTimeFormatter.ISO_LOCAL_DATE));
    //2019-06-09
    System.out.println(LocalDate.parse("20190609", DateTimeFormatter.BASIC_ISO_DATE));

    //自定义DateTimeFormatter
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    //2019-06-09 23:56:34
    System.out.println(dt.format(formatter));
    //2019-06-09T23:56:34
    System.out.println(LocalDateTime.parse("2019-06-09 23:56:34", formatter));
  }
}

ZoneId

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
public class Test {
  public static void main(String[] args) {
    ZoneId rome1 = ZoneId.of("Asia/Shanghai");
    //将旧的TimeZone转换为ZoneId
    ZoneId zoneId2 = TimeZone.getTimeZone("Asia/Chongqing").toZoneId();
    LocalDate date = LocalDate.now();
    ZonedDateTime zdt = date.atStartOfDay(rome1);
    System.out.println(zdt); //2019-06-10T00:00+08:00[Asia/Shanghai]

    Instant instant = Instant.now();
    ZonedDateTime zdt2 = instant.atZone(zoneId2);
    System.out.println(zdt2); 
    //2019-06-10T00:27:55.281+08:00[Asia/Chongqing]
  }
}

以上内容是玉山整理的笔记,如有错误还请指出