java时间

422 阅读4分钟

概述

  • LocalDate 日期
  • LocalTime 时间
  • LocalDateTime 日期+时间
  • ZonedDateTime 日期+时间+时区
  • Instant 时间戳
  • OffsetTime
  • OffsetDateTime

日期类

LocalDate,YearMonth,MonthDay 和 Year

LocalDate

// 2021-11-20
LocalDate date = LocalDate.of(2021, Month.NOVEMBER, 20);
// 当前指定日期的下一个 星期三
LocalDate nextWed = date.with(TemporalAdjusters.next(DayOfWeek.WEDNESDAY));
// 格式化输出
System.out.println(DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL).format(date));

YearMonth

YearMonth.lengthOfMonth(),返回该月有多少天

YearMonth.lengthOfYear(),返回该年有多少天

// 2021-06: 30
YearMonth date = YearMonth.now();
System.out.printf("%s: %d%n", date, date.lengthOfMonth());
// 2021-02: 28
YearMonth date2 = YearMonth.of(2021, Month.FEBRUARY);
System.out.printf("%s: %d%n", date2, date2.lengthOfMonth());
// 2012-02: 366
YearMonth date3 = YearMonth.of(2012, Month.FEBRUARY);
System.out.printf("%s: %d%n", date3, date3.lengthOfYear());

MonthDay

表示某月的一天

// 2月29号
MonthDay date = MonthDay.of(Month.FEBRUARY, 29);
// 对于 2010 年是否是有效的时间
boolean validLeapYear = date.isValidYear(2010);

Year

// 确定给定年份是否为闰年
boolean validLeapYear = Year.of(2012).isLeap();

日期和时间类

LocalTime

LocalTime类不存储时区或夏令时信息

LocalTime thisSec = LocalTime.now();
System.out.println(thisSec.getHour() + ":" + thisSec.getMinute() + ":" + thisSec.getSecond());     

LocalDateTime

LocalDate 和 LocalTime 的组合,无时区

// now()
System.out.printf("now: %s%n", LocalDateTime.now());

// of(), 1994年4月15号11点30分
System.out.printf("Apr 15, 1994 @ 11:30am: %s%n",
        LocalDateTime.of(1994, Month.APRIL, 15, 11, 30));

// ofInstant(), 基于Instant类,纳秒 + 时区id
System.out.printf("now (from Instant): %s%n",
        LocalDateTime.ofInstant(Instant.now(), ZoneId.systemDefault()));

// plusMonth(), 6月后
System.out.printf("6 months from now: %s%n",
        LocalDateTime.now().plusMonths(6));

// minusMonths(), 6月前
System.out.printf("6 months ago: %s%n",
        LocalDateTime.now().minusMonths(6));

时区和偏移类

// 在中国,下面获取到的就是带时区的北京时间,里面的 offset 就是 +8:00
ZonedDateTime.now()

ZoneId + ZoneOffset

ZoneId: 指定时区标识符,并提供 Instant 和 LocalDateTime 之间转换的规则

ZoneOffset: 指定格林威治/ UTC 时间的时区偏移量

// 获取所有可用的时区
Set<String> allZones = ZoneId.getAvailableZoneIds();

// 本地时间加时区信息 转换成一个ZonedDateTime
LocalDateTime dt = LocalDateTime.now();
ZoneId zone = ZoneId.of(s);
ZonedDateTime zdt = dt.atZone(zone);
// 针对IUTC时间的时区偏移量
ZoneOffset offset = zdt.getOffset();

ZonedDateTime

使用格林威治/ UTC 的时区偏移量处理具有相应时区的日期和时间

结合了 LocalDateTime 与类 了 zoneid 类

表示具有时区的完整日期和时间

// DateTimeFormatter 对象用于格式化 ZonedDateTime 实例
DateTimeFormatter format = DateTimeFormatter.ofPattern("YYYY-MM-dd  HH:mm:ss");

// 时间 + 日期 LocalDateTime + 时区 ZoneId => 时间 + 日期 + 时区 ZonedDateTime
//  2013-07-20  19:30:00
LocalDateTime leaving = LocalDateTime.of(2013, Month.JULY, 20, 19, 30);
ZoneId leavingZone = ZoneId.of("America/Los_Angeles");
ZonedDateTime departure = ZonedDateTime.of(leaving, leavingZone);

// 格式化
String out1 = departure.format(format);

// 切换时区(使用美国洛杉矶出发的时间,然后换算成东京的时区,返回该时区对应的时间)
ZoneId arrivingZone = ZoneId.of("Asia/Tokyo");
ZonedDateTime arrival = departure.withZoneSameInstant(arrivingZone);
// 在该时区的基础上加650分钟
arrival = arrival.plusMinutes(650); 
// 格式化
String out2 = arrival.format(format);

// 夏令时
arrivingZone.getRules().isDaylightSavings(arrival.toInstant());

OffsetDateTime

使用格林威治/ UTC 的相应时区偏移量处理日期和时间,但不包含时区 ID

结合了 LocalDateTime 与类 ZoneOffset 类

// 2017.07.20 19:30
LocalDateTime localDate = LocalDateTime.of(2013, Month.JULY, 20, 19, 30);
ZoneOffset offset = ZoneOffset.of("-08:00");

OffsetDateTime offsetDate = OffsetDateTime.of(localDate, offset);

OffsetTime

使用格林威治/ UTC 的相应时区偏移量处理时间,但不包含时区 ID

ZonedDateTime和OffsetDateTime

// 一个不带任何时区的时间
LocalDateTime date = LocalDateTime.of(2018, 05, 01, 0, 0, 0);

// ZonedDateTime, 2018-05-01T00:00+08:00[GMT+08:00], ZoneId 带了具体的ID
ZonedDateTime d1 = ZonedDateTime.of(date, ZoneId.systemDefault());

// OffsetDateTime, 2018-05-01T00:00+08:00, 偏移没有ID,因为多个ID对应的值有可能是一样的
ZoneOffset offset = ZoneOffset.of("+08:00");
OffsetDateTime d2 = OffsetDateTime.of(date, offset);

常用api

// 么把中国时间变成其他的时间
// 2018-04-30T20:00+04:00[Asia/Yerevan]
// 把该时间转换成指定时区了
d1.withZoneSameInstant(ZoneId.of("Asia/Yerevan"));
// 2018-05-01T00:00+04:00[Asia/Yerevan]
// 只是改变了时区
d1.withZoneSameLocal(ZoneId.of("Asia/Yerevan"));

withZoneSameInstant

调用了 toEpochSecond 把当前的时间纳秒 结合 指定的偏移量换算成新的纳秒

withZoneSameLocal

不会换算时间,只是把时区更改了

Instant

Instant timestamp = Instant.now();
// 增加1h
Instant oneHourLater = Instant.now().plusHours(1);
// until,返回两者直接发生了多长的时间
long secondsFromEpoch = Instant.ofEpochSecond(0L).until(Instant.now(),
                                                        ChronoUnit.SECONDS);

解析和格式化

DateTimeFormatter 类提供了大量预定义的格式化,也可以自己定义

DateTimeFormatter 类是不可变的和线程安全的

parse

// 预定义
String in = "20111203";
LocalDate date = LocalDate.parse(in, DateTimeFormatter.BASIC_ISO_DATE);
// 自定义
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM d yyyy");
LocalDate date = LocalDate.parse(input, formatter);

format

ZoneId leavingZone = ZoneId.systemDefault();
ZonedDateTime departure = ZonedDateTime.of(LocalDateTime.now(), leavingZone);
DateTimeFormatter format = DateTimeFormatter.ofPattern("MMM d yyyy  hh:mm a");
String out = departure.format(format);

dtf.parse("2018-05-08 16:03:55") 返回的对象中 不包含 LocalDate 只包含 LocalTime

// 以下两种方式相等
LocalDateTime.parse("2018-05-08 16:03:55",dtf);
dtf.parse("2018-05-08 16:03:55").query(LocalDateTime::from);

PS: 参考文档,zq99299.github.io/java-tutori…