【问题标题】:Why setting timezone on the Java calendar object has no effect? [duplicate]为什么在 Java 日历对象上设置时区没有效果? [复制]
【发布时间】:2018-05-30 06:06:53
【问题描述】:

考虑以下代码 sn-ps。

    TimeZone tz = TimeZone.getTimeZone("GMT");
    System.out.println(tz);

    Calendar cal = Calendar.getInstance();
    cal.set(2017, Calendar.DECEMBER, 25);

    System.out.println("before setting time zone: " + cal.getTime());
    cal.setTimeZone(tz);

    System.out.println("after setting time zone: " + cal.getTime());

结果如下:

sun.util.calendar.ZoneInfo[id="GMT",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null]
before setting time zone: Mon Dec 25 22:39:53 EST 2017 
after setting time zone: Mon Dec 25 22:39:53 EST 2017

时区更改后,为什么打印输出的日期仍然显示 EST?不应该是格林威治标准时间吗?

【问题讨论】:

  • 您将区域设置为cal 而不是cal.getTime()。后者只是 java.util.Date 类型,您无法设置区域(其方法 java.util.Date.toString() 仅使用系统 tz)。
  • 意识到cal.getTime() 给你一个java.util.Date 这个著名的博客条目可能会有所帮助:All about java.util.Date

标签: java date datetime calendar timezone


【解决方案1】:

tl;博士

LocalDate.of( 2017 , Month.DECEMBER , 25 )
         .atStartOfDay( ZoneId.of( "America/New_York" ) )

避免使用旧的日期时间类

您正在使用非常麻烦的旧日期时间类,这些类现在已成为遗留问题。

要直接回答您的问题,Calendar::getTime 方法会返回 Date。在这些类的众多设计缺陷中,Date::toString 在生成字符串时会动态应用 JVM 的当前默认时区。这样你的EST就出现了。

永远不要使用这些类。仅使用它们的替代品,即行业领先的 java.time 类。

java.time

LocalDate 类表示没有时间和时区的仅日期值。

LocalDate xmas2017 = LocalDate.of( 2017 , Month.DECEMBER , 25 ) ;

如果您需要日期时间,即一天中的第一个时刻,您必须指定一个时区。时区对于确定日期至关重要。对于任何给定的时刻,日期在全球范围内因区域而异。例如,Paris France 中午夜后几分钟是新的一天,而 Montréal Québec 中仍然是“昨天”。

continent/region 的格式指定proper time zone name,例如America/MontrealAfrica/CasablancaPacific/Auckland切勿使用 3-4 个字母的缩写,例如 ESTIST,因为它们不是真正的时区,没有标准化,甚至不是唯一的 (!)。

永远不要假设一天从 00:00 开始。在某些区域,Daylight Saving Time (DST) 等异常意味着一天可能在其他时间开始,例如 01:00:00。让 java.time 确定一天中的第一个时刻。

申请ZoneId 以获得ZonedDateTime

ZoneId z = ZoneId.of( "America/New_York" ) ;
ZonedDateTime zdtNewYork = xmas2017.atStartOfDay( z ) ;

请注意,印度的圣诞节比纽约早得多。

ZonedDateTime zdtKolkta = xmas2017.atStartOfDay( ZoneId.of( "Asia/Kolkata" ) ) ;

这就是为什么精灵的 物流 部门将圣诞老人送至Kiribati 进行第一批送货。这些岛屿的圣诞节最早,时区比世界标准时间早 14 小时。驯鹿从那里开始向东飞去,追逐一个接一个的午夜,随着地球在新一天的阳光下旋转。

如果您想将同一时刻调整为 UTC,请提取始终为 UTC 的 Instant

Instant instant = zdt.toInstant() ;

关于java.time

java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.DateCalendarSimpleDateFormat

Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310

从哪里获得 java.time 类?

ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-10
    • 1970-01-01
    • 2021-11-11
    • 2019-03-27
    • 2018-07-06
    相关资源
    最近更新 更多