文档

Java™ 教程
隐藏目录
时区和偏移类
路径: 日期 时间
教训: 标准日历

时区和偏移类

一个时区是地球上使用相同标准时间的区域。每个时区由一个标识符描述,通常采用区域/城市的格式(Asia/Tokyo),以及与格林威治/世界标准时间的偏移量。例如,东京的偏移量为+09:00

ZoneId和ZoneOffset

日期时间API提供了两个类来指定时区或偏移量:

相对于格林威治/世界标准时间的偏移量通常以整小时为单位定义,但也有例外情况。以下代码来自TimeZoneId示例,打印出使用不以整小时为定义的格林威治/世界标准时间偏移量的所有时区的列表。

Set<String> allZones = ZoneId.getAvailableZoneIds();
LocalDateTime dt = LocalDateTime.now();

// 使用区域集合创建一个列表并进行排序。
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);

    // 仅打印没有整小时偏移量的时区到标准输出。
    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的文件中。

日期时间类

日期时间 API 提供了三个基于时间区域的类:

什么情况下应该使用 OffsetDateTime 而不是 ZonedDateTime?如果您正在编写基于地理位置的复杂软件,以模拟自己的日期和时间计算规则,或者如果您正在存储数据库中仅跟踪相对于格林威治/UTC 时间的绝对偏移的时间戳,那么您可能想要使用 OffsetDateTime。此外,XML 和其他网络格式将日期时间传输定义为 OffsetDateTimeOffsetTime

尽管所有三个类都维护了与格林威治/UTC 时间的偏移量,但只有 ZonedDateTime 使用 ZoneRules(位于 java.time.zone 包中)来确定特定时区的偏移量如何变化。例如,大多数时区在将时钟向前调整为夏令时时会经历一个间隔(通常为1小时),而在将时钟调回为标准时间时会经历时间重叠,并且在过渡前的最后一个小时会重复。 ZonedDateTime 类适应了这种情况,而没有访问 ZoneRulesOffsetDateTimeOffsetTime 类则没有。

ZonedDateTime

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

以下代码来自 Flight 示例,定义了从旧金山飞往东京的航班的出发时间,使用美国洛杉矶时区的 ZonedDateTime。使用 withZoneSameInstantplusMinutes 方法创建了一个表示预计到达时间的 ZonedDateTime 实例,航班飞行时间为 650 分钟。 ZoneRules.isDaylightSavings 方法确定飞机到达东京时是否为夏令时。

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

DateTimeFormatter format = DateTimeFormatter.ofPattern("MMM d yyyy  hh:mm a");

// 2013年7月20日晚上7:30从旧金山出发
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("出发时间:  %s (%s)%n", out1, leavingZone);
} catch (DateTimeException exc) {
    System.out.printf("%s 无法格式化!%n", departure);
    throw exc;
}

// 飞行时间为10小时50分钟,即650分钟
ZoneId arrivingZone = ZoneId.of("Asia/Tokyo"); 
ZonedDateTime arrival = departure.withZoneSameInstant(arrivingZone)
                                 .plusMinutes(650);

try {
    String out2 = arrival.format(format);
    System.out.printf("到达时间: %s (%s)%n", out2, arrivingZone);
} catch (DateTimeException exc) {
    System.out.printf("%s 无法格式化!%n", arrival);
    throw exc;
}

if (arrivingZone.getRules().isDaylightSavings(arrival.toInstant())) 
    System.out.printf("  (亚洲/东京将使用夏令时。)%n",
                      arrivingZone);
else
    System.out.printf("  (亚洲/东京将使用标准时间。)%n",
                      arrivingZone);

这将产生以下输出:

出发时间:  Jul 20 2013  07:30 PM (America/Los_Angeles)
到达时间: Jul 21 2013  10:20 PM (Asia/Tokyo)
  (亚洲/东京将使用标准时间。)

OffsetDateTime

OffsetDateTime类实际上结合了LocalDateTime类和ZoneOffset类。它用于表示具有与格林威治/协调世界时(+/-小时:分钟,例如+06:00-08:00)的偏移量的完整日期(年、月、日)和时间(时、分、秒、纳秒)。

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

// 找到2013年7月的最后一个星期四
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("2013年7月的最后一个星期四是第%s天。%n",
                   lastThursday.getDayOfMonth());

运行此代码的输出结果为:

2013年7月的最后一个星期四是25日。

OffsetTime

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

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


上一页:日期和时间类
下一页:即时类