Java 教程是为 JDK 8 编写的。本页中描述的示例和实践未利用在后续版本中引入的改进。
time zone (时区) 是使用相同标准时间的地球区域。每个时区由标识符描述,通常具有格式 region/city(Asia/Tokyo)和格林威治/ UTC 时间的偏移量。例如,东京的偏移量为 +09:00。
Date-Time API 提供了两个用于指定时区或偏移的类:
格林威治/ UTC 时间的偏差通常在整数小时内定义,但也有例外。以下代码,来自 TimeZoneId
示例,打印使用格林威治/ UTC 偏移的所有时区的列表,这些时区未定义整数小时。
Set<String> allZones = ZoneId.getAvailableZoneIds(); LocalDateTime dt = LocalDateTime.now(); // Create a List using the set of zones and sort it. List<String> zoneList = new ArrayList<String>(allZones); Collections.sort(zoneList); ... for (String s : zoneList) { ZoneId zone = ZoneId.of(s); ZonedDateTime zdt = dt.atZone(zone); ZoneOffset offset = zdt.getOffset(); int secondsOfHour = offset.getTotalSeconds() % (60 * 60); String out = String.format("%35s %10s%n", zone, offset); // Write only time zones that do not have a whole hour offset // to standard out. if (secondsOfHour != 0) { System.out.printf(out); } ... }
此示例将以下列表打印到标准输出:
America/Caracas -04:30 America/St_Johns -02:30 Asia/Calcutta +05:30 Asia/Colombo +05:30 Asia/Kabul +04:30 Asia/Kathmandu +05:45 Asia/Katmandu +05:45 Asia/Kolkata +05:30 Asia/Rangoon +06:30 Asia/Tehran +04:30 Australia/Adelaide +09:30 Australia/Broken_Hill +09:30 Australia/Darwin +09:30 Australia/Eucla +08:45 Australia/LHI +10:30 Australia/Lord_Howe +10:30 Australia/North +09:30 Australia/South +09:30 Australia/Yancowinna +09:30 Canada/Newfoundland -02:30 Indian/Cocos +06:30 Iran +04:30 NZ-CHAT +12:45 Pacific/Chatham +12:45 Pacific/Marquesas -09:30 Pacific/Norfolk +11:30
TimeZoneId 示例还会将所有时区 ID 的列表打印到名为 timeZones
的文件中。
Date-Time API 提供了三个适用于时区的基于时间的类:
你何时使用 OffsetDateTime 而不是 ZonedDateTime?如果你正在编写复杂的软件,根据地理位置为自己的日期和时间计算规则建模,或者如果你将时间戳存储在仅跟踪格林威治/ UTC 时间的绝对偏移的数据库中,那么你可能希望使用 OffsetDateTime。此外,XML 和其他网络格式将日期时间传输定义为 OffsetDateTime 或 OffsetTime。
虽然所有三个类都保持与格林威治/ UTC 时间的偏移,但只有 ZonedDateTime 使用 ZoneRules,这是 java.time.zone 包的一部分,用于确定特定时区的偏移量的变化情况。例如,当将时钟向前移动到夏令时时,大多数时区经历间隙(通常为 1 小时),并且当将时钟移回标准时间时也经历一个间隙,重复在转换之前的最后一小时(译注:即夏令时的解释)。ZonedDateTime 类适用于此场景,而 OffsetDateTime 和 OffsetTime 类无法访问 ZoneRules,它们不适用。
ZonedDateTime 类实际上将 LocalDateTime 类与 ZoneId 类组合在一起。它用于表示具有时区(区域/城市,例如 Europe/Paris)的完整日期(年,月,日)和时间(小时,分钟,秒,纳秒)。
以下代码,来自 Flight
示例,定义了从旧金山到东京的航班起飞时间为 ZonedDateTime 在美国/洛杉矶时区。withZoneSameInstant 和 plusMinutes 方法用于创建 ZonedDateTime 的实例,该实例表示在 650 分钟飞行后在东京的预计到达时间。ZoneRules.isDaylightSavings 方法确定航班抵达东京时是否为夏令时。
DateTimeFormatter 对象用于格式化 ZonedDateTime 实例以进行打印:
DateTimeFormatter format = DateTimeFormatter.ofPattern("MMM d yyyy hh:mm a"); // Leaving from San Francisco on July 20, 2013, at 7:30 p.m. LocalDateTime leaving = LocalDateTime.of(2013, Month.JULY, 20, 19, 30); ZoneId leavingZone = ZoneId.of("America/Los_Angeles"); ZonedDateTime departure = ZonedDateTime.of(leaving, leavingZone); try { String out1 = departure.format(format); System.out.printf("LEAVING: %s (%s)%n", out1, leavingZone); } catch (DateTimeException exc) { System.out.printf("%s can't be formatted!%n", departure); throw exc; } // Flight is 10 hours and 50 minutes, or 650 minutes ZoneId arrivingZone = ZoneId.of("Asia/Tokyo"); ZonedDateTime arrival = departure.withZoneSameInstant(arrivingZone) .plusMinutes(650); try { String out2 = arrival.format(format); System.out.printf("ARRIVING: %s (%s)%n", out2, arrivingZone); } catch (DateTimeException exc) { System.out.printf("%s can't be formatted!%n", arrival); throw exc; } if (arrivingZone.getRules().isDaylightSavings(arrival.toInstant())) System.out.printf(" (%s daylight saving time will be in effect.)%n", arrivingZone); else System.out.printf(" (%s standard time will be in effect.)%n", arrivingZone);
这会产生以下输出:
LEAVING: Jul 20 2013 07:30 PM (America/Los_Angeles) ARRIVING: Jul 21 2013 10:20 PM (Asia/Tokyo) (Asia/Tokyo standard time will be in effect.)
OffsetDateTime 类实际上将 LocalDateTime 类与 ZoneOffset 类组合在一起。它用于表示完整日期(年,月,日)和时间(小时,分钟,秒,纳秒),偏离格林威治/ UTC 时间(+/-小时:分钟,例如 +06:00 或 -08:00)。
以下示例使用 OffsetDateTime 和 TemporalAdjuster.lastDay 方法查找 2013 年 7 月的最后一个星期四。
// Find the last Thursday in July 2013. LocalDateTime localDate = LocalDateTime.of(2013, Month.JULY, 20, 19, 30); ZoneOffset offset = ZoneOffset.of("-08:00"); OffsetDateTime offsetDate = OffsetDateTime.of(localDate, offset); OffsetDateTime lastThursday = offsetDate.with(TemporalAdjusters.lastInMonth(DayOfWeek.THURSDAY)); System.out.printf("The last Thursday in July 2013 is the %sth.%n", lastThursday.getDayOfMonth());
运行此代码的输出是:
The last Thursday in July 2013 is the 25th.
OffsetTime 类实际上将 LocalTime 类与 ZoneOffset 类组合在一起。它用于表示时间(小时,分钟,秒,纳秒),偏离格林威治/ UTC 时间(+/-小时:分钟,例如 +06:00 或 -08:00)。
OffsetTime 类用于与 OffsetDateTime 类相同的情况,但不需要跟踪日期。