时区和偏移类

原文: https://docs.oracle.com/javase/tutorial/datetime/iso/timezones.html

时区是使用相同标准时间的地球区域。每个时区由标识符描述,并且通常具有格式区域/城市亚洲/东京)和格林威治/ UTC 时间的偏移。例如,东京的偏移是+09:00

ZoneId 和 ZoneOffset

Date-Time API 提供了两个用于指定时区或偏移的类:

  • ZoneId指定时区标识符,并提供在InstantLocalDateTime之间进行转换的规则。
  • ZoneOffset指定从格林威治/ UTC 时间偏移的时区。

格林威治/ UTC 时间的偏差通常以整个小时定义,但也有例外。以下代码来自 `TimeZoneId `示例,打印使用格林威治/ UTC 偏移的所有时区列表,这些时区未在整个小时内定义。

  1. Set<String> allZones = ZoneId.getAvailableZoneIds();
  2. LocalDateTime dt = LocalDateTime.now();
  3. // Create a List using the set of zones and sort it.
  4. List<String> zoneList = new ArrayList<String>(allZones);
  5. Collections.sort(zoneList);
  6. ...
  7. for (String s : zoneList) {
  8. ZoneId zone = ZoneId.of(s);
  9. ZonedDateTime zdt = dt.atZone(zone);
  10. ZoneOffset offset = zdt.getOffset();
  11. int secondsOfHour = offset.getTotalSeconds() % (60 * 60);
  12. String out = String.format("%35s %10s%n", zone, offset);
  13. // Write only time zones that do not have a whole hour offset
  14. // to standard out.
  15. if (secondsOfHour != 0) {
  16. System.out.printf(out);
  17. }
  18. ...
  19. }

此示例将以下列表打印到标准输出:

  1. America/Caracas -04:30
  2. America/St_Johns -02:30
  3. Asia/Calcutta +05:30
  4. Asia/Colombo +05:30
  5. Asia/Kabul +04:30
  6. Asia/Kathmandu +05:45
  7. Asia/Katmandu +05:45
  8. Asia/Kolkata +05:30
  9. Asia/Rangoon +06:30
  10. Asia/Tehran +04:30
  11. Australia/Adelaide +09:30
  12. Australia/Broken_Hill +09:30
  13. Australia/Darwin +09:30
  14. Australia/Eucla +08:45
  15. Australia/LHI +10:30
  16. Australia/Lord_Howe +10:30
  17. Australia/North +09:30
  18. Australia/South +09:30
  19. Australia/Yancowinna +09:30
  20. Canada/Newfoundland -02:30
  21. Indian/Cocos +06:30
  22. Iran +04:30
  23. NZ-CHAT +12:45
  24. Pacific/Chatham +12:45
  25. Pacific/Marquesas -09:30
  26. Pacific/Norfolk +11:30

TimeZoneId示例还会将所有时区 ID 的列表打印到名为 `timeZones `的文件中。

日期时间类

Date-Time API 提供了三个适用于时区的基于时间的类:

  • ZonedDateTime使用相应时区处理日期和时间,时区偏离格林威治/ UTC。
  • OffsetDateTime使用与格林威治/ UTC 相对应的时区偏移处理日期和时间,没有时区 ID。
  • OffsetTime处理与格林威治/ UTC 相对应的时区偏移的时间,没有时区 ID。

你何时会使用OffsetDateTime而不是ZonedDateTime ?如果您正在编写复杂的软件,根据地理位置为自己的日期和时间计算规则建模,或者如果您将时间戳存储在仅跟踪格林威治/ UTC 时间的绝对偏移的数据库中,那么您可能希望使用OffsetDateTime 。此外,XML 和其他网络格式将日期时间传输定义为OffsetDateTimeOffsetTime

虽然所有三个类都保持与格林威治/ UTC 时间的偏移,但只有ZonedDateTime使用 ZoneRulesjava.time.zone的一部分包,用于确定特定时区的偏移量如何变化。例如,当将时钟向前移动到夏令时时,大多数时区经历间隙(通常为 1 小时),并且当将时钟移回标准时间和重复转换之前的最后一小时时,时间重叠。 ZonedDateTime类适应这种情况,而无法访问ZoneRulesOffsetDateTimeOffsetTime类则不适用。

ZonedDateTime

ZonedDateTime 类实际上将 LocalDateTime类与 ZoneId类组合在一起。它用于表示时区(区域/城市,例如Europe / Paris )的完整日期(年,月,日)和时间(小时,分钟,秒,纳秒)。

来自 `Flight `示例的以下代码定义了从旧金山飞往东京的航班起飞时间ZonedDateTime美国/洛杉矶时区。带有 ZoneSameInstant 和plusMinutes方法的用于创建ZonedDateTime的实例,该实例表示 650 分钟飞行后在东京的预计到达时间。ZoneRules.isDaylightSavings方法确定航班抵达东京时是否为夏令时。

DateTimeFormatter对象用于格式化ZonedDateTime实例以进行打印:

  1. DateTimeFormatter format = DateTimeFormatter.ofPattern("MMM d yyyy hh:mm a");
  2. // Leaving from San Francisco on July 20, 2013, at 7:30 p.m.
  3. LocalDateTime leaving = LocalDateTime.of(2013, Month.JULY, 20, 19, 30);
  4. ZoneId leavingZone = ZoneId.of("America/Los_Angeles");
  5. ZonedDateTime departure = ZonedDateTime.of(leaving, leavingZone);
  6. try {
  7. String out1 = departure.format(format);
  8. System.out.printf("LEAVING: %s (%s)%n", out1, leavingZone);
  9. } catch (DateTimeException exc) {
  10. System.out.printf("%s can't be formatted!%n", departure);
  11. throw exc;
  12. }
  13. // Flight is 10 hours and 50 minutes, or 650 minutes
  14. ZoneId arrivingZone = ZoneId.of("Asia/Tokyo");
  15. ZonedDateTime arrival = departure.withZoneSameInstant(arrivingZone)
  16. .plusMinutes(650);
  17. try {
  18. String out2 = arrival.format(format);
  19. System.out.printf("ARRIVING: %s (%s)%n", out2, arrivingZone);
  20. } catch (DateTimeException exc) {
  21. System.out.printf("%s can't be formatted!%n", arrival);
  22. throw exc;
  23. }
  24. if (arrivingZone.getRules().isDaylightSavings(arrival.toInstant()))
  25. System.out.printf(" (%s daylight saving time will be in effect.)%n",
  26. arrivingZone);
  27. else
  28. System.out.printf(" (%s standard time will be in effect.)%n",
  29. arrivingZone);

这会产生以下输出:

  1. LEAVING: Jul 20 2013 07:30 PM (America/Los_Angeles)
  2. ARRIVING: Jul 21 2013 10:20 PM (Asia/Tokyo)
  3. (Asia/Tokyo standard time will be in effect.)

OffsetDateTime

OffsetDateTime 类实际上将 LocalDateTime类与 ZoneOffset类组合在一起。它用于表示完整日期(年,月,日)和时间(小时,分钟,秒,纳秒),偏离格林威治/ UTC 时间(+/-小时:分钟,例如+06: 00-08:00 )。

以下示例使用OffsetDateTimeTemporalAdjuster.lastDay方法查找 2013 年 7 月的最后一个星期四。

  1. // Find the last Thursday in July 2013.
  2. LocalDateTime localDate = LocalDateTime.of(2013, Month.JULY, 20, 19, 30);
  3. ZoneOffset offset = ZoneOffset.of("-08:00");
  4. OffsetDateTime offsetDate = OffsetDateTime.of(localDate, offset);
  5. OffsetDateTime lastThursday =
  6. offsetDate.with(TemporalAdjusters.lastInMonth(DayOfWeek.THURSDAY));
  7. System.out.printf("The last Thursday in July 2013 is the %sth.%n",
  8. lastThursday.getDayOfMonth());

运行此代码的输出是:

  1. The last Thursday in July 2013 is the 25th.

OffsetTime

OffsetTime 类实际上将 LocalTime类与 ZoneOffset类组合在一起。它用于表示时间(小时,分钟,秒,纳秒),偏离格林威治/ UTC 时间(+/-小时:分钟,例如+06:00-08: 00 )。

OffsetTime类用于与OffsetDateTime类相同的情况,但不需要跟踪日期。