java:timezone getTimeZone(“GMT-0700”)’timezone useDaylight不正确

java: timezone getTimeZone(“GMT-0700”)' timezone useDaylight incorrect

我想知道洛杉矶的时区信息,现在10/10/2017是夏令时,但是我在洛杉矶的时区有两种不同的结果。

1
2
3
4
5
6
7
8
9
10
public class TimeZoneDemo2 {
  public static void main(String[] args) {
    TimeZone timeZoneLosAngeles =
    TimeZone.getTimeZone("America/Los_Angeles");
    System.out.println(timeZoneLosAngeles);

    TimeZone timeZoneGmtMinus07 = TimeZone.getTimeZone("GMT-07:00");
    System.out.println(timeZoneGmtMinus07);
  }
}

结果是:

sun.util.calendar.ZoneInfo[id="America/Los_Angeles",offset=-28800000,dstSavings=3600000,useDaylight=true,transitions=185,lastRule=java.util.SimpleTimeZone[id=America/Los_Angeles,offset=-28800000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]]

sun.util.calendar.ZoneInfo[id="GMT-07:00",offset=-25200000,dstSavings=0,useDaylight=false,transitions=0,lastRule=null]

我的问题是:有关"美国/洛杉矶"获得的时区夏令时信息。为什么不在"GMT-0700"获得的时区信息中包括夏令时信息(usedaylight=false)?


I want to get the time zone information for Los Angeles, now 10/10/2017 is daylight saving time

所以你应该问"美国/洛杉矶"区域。这就是它的目的。

"GMT-07:00"区域是一个固定的偏移区域-仅当您想表示"一个永久落后于UTC 7小时的时区"时才适用。这不适用于洛杉矶。

还有很多其他时区,有时是在UTC-7——为什么你认为格林威治标准时间07:00是"洛杉矶观察到的时区"?

换句话说,Java正在做正确的事情——这是你对"GMT-0700"区域意味着什么不正确的期望。


乔恩·斯基特的回答是正确的,应该被接受。您不能从与UTC的偏移量可靠地确定时区,因为许多时区可能同时共享偏移量。此外,一个区域的偏移量可能随时间而变化。

下面是一些代码示例,它们使用比问题中所看到的更现代的类来解决这个问题。

java.time时间

您使用的是麻烦的旧日期时间类,这些类现在是遗留类,而不是java.time类。

如其他人所说,如果您知道预期时区,请始终优先使用该时区,而不是仅使用与UTC的偏移量。偏移量只是UTC之前或之后的小时、分钟和秒数。时区是一个地区人民使用的偏移量的变化历史。时区知道这种偏移量变化的过去、现在和(暂时)未来。

ZoneIdZoneOffset类取代了TimeZone

continent/region格式指定适当的时区名称,如America/MontrealAfrica/CasablancaPacific/Auckland。切勿使用3-4字母缩写,如ESTIST,因为它们不是真正的时区,不标准,甚至不是唯一的(!).

1
ZoneId z = ZoneId.of("America/Los_Angeles" ) ;  // Or"Africa/Tunis","Pacific/Auckland", etc.

从该区域的透镜中获得当前时刻。

1
ZonedDateTime zdt = ZonedDateTime.now( z ) ;  // Fetch current moment for that zone.

提取相同的时刻,但调整为UTC。

1
Instant instant = zdt.toInstant() ;  // Extract the same moment but in UTC.

把那一刻调整到另一个区域。

1
ZonedDateTime zdtKolkata = instant.atZone( ZoneId.of("Asia/Kolkata" ) ) ;  // Determine same moment, same point on timeline, but in another time zone.

所有这三个对象都表示时间线上非常相同的同时点,但使用不同的墙时钟时间查看。

请参见该地区人民当时使用的偏移量。

1
ZoneOffset offset = z.getRules().getOffset( instant ) ;  // Get the offset in place at that moment for that time zone.

你会发现,在2018年,在那一年的一部分时间里,America/Los_Angeles的抵消将是-07:00(比UTC晚几个小时)。在今年的另一部分,抵消将是-08:00(比UTC晚8小时)。这种抵消的变化是由于政客们决定遵守夏令时(DST)。

关于java.time

JavaTimeFr框架是在Java 8和之后构建的。这些类取代了麻烦的旧遗留日期时间类,如java.util.DateCalendarSimpleDateFormat

现在处于维护模式的joda time项目建议迁移到java.time类。

要了解更多信息,请参阅Oracle教程。以及搜索堆栈溢出以获得许多示例和解释。规格为JSR 310。

在哪里获取java.time类?

  • Java SE 8、Java SE 9及以后
    • 内置。
    • 标准JAVA API的一部分与捆绑实现。
    • Java 9增加了一些次要的特性和修复。
  • Java SE 6和Java SE 7
    • 大部分JavaTimeActudio都被移植到TealEnter后端的Java 6和7中。
  • 安卓
    • java.time类的Android包实现的更高版本。
    • 对于早期的android,threetenabp项目适应threeten backport(如上所述)。看看如何使用三连珠……

threeten额外项目使用额外的类扩展java.time。这个项目是将来可能添加到java.time的一个试验场。您可以在这里找到一些有用的类,如IntervalYearWeekYearQuarter等等。