【问题标题】:Java GregorianCalendar change TimeZoneJava GregorianCalendar 更改时区
【发布时间】:2012-08-21 16:08:11
【问题描述】:

我正在尝试设置 HOUR_OF_DAY 字段并更改 GregorianCalendar 日期对象的时区。

GregorianCalendar date = new GregorianCalendar(TimeZone.getTimeZone("GMT+10"));
System.out.println("HOUR: " + date.get(Calendar.HOUR_OF_DAY));
date.set(Calendar.HOUR_OF_DAY, 23);
//date.get(Calendar.HOUR_OF_DAY);
date.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println("HOUR: " + date.get(Calendar.HOUR_OF_DAY));

输出:

HOUR: 16
HOUR: 23

由于某些原因,HOUR_OF_DAY 的值在设置不同的时区后不会改变。但是,如果我取消对 HOUR_OF_DAY 的 date.get 的注释,一切都会正常运行

GregorianCalendar date = new GregorianCalendar(TimeZone.getTimeZone("GMT+10"));
System.out.println("HOUR: " + date.get(Calendar.HOUR_OF_DAY));
date.set(Calendar.HOUR_OF_DAY, 23);
date.get(Calendar.HOUR_OF_DAY); // uncommenting this line will is changing the output
date.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println("HOUR: " + date.get(Calendar.HOUR_OF_DAY));

输出:

HOUR: 16
HOUR: 13

这怎么可能?为什么 .get 方法会改变对象的行为?

【问题讨论】:

    标签: java date timezone


    【解决方案1】:

    GregorianCalendar 类从Calendar 继承其get 方法,具有以下副作用:

    在宽松模式下,所有日历字段都被规范化。

    这意味着当在 Calendar 对象上调用 get 时,将重新计算 time 值和所有字段。这可能会导致一些不可预知的行为,尤其是与 setTimeZone 结合使用时,它有自己的一些 documented buggy behavior

    【讨论】:

      【解决方案2】:

      tl;博士

      OffsetDateTime.now( ZoneOffset.ofHours( 10 )  ).withHour( 23 )
      

      避免使用旧的日期时间类

      包括GregorianCalendar 在内的遗留日期时间类令人困惑。尴尬,糟糕的设计混乱。避开他们。现在被 java.time 类所取代。具体来说,GregorianCalendarZonedDateTime 替换。

      与 UTC 的偏移量

      您显然想要比UTC 早十小时的offset-from-UTC。定义您想要的偏移量。

      ZoneOffset offset = ZoneOffset.ofHours( 10 ) ;
      

      offset.toString(): +10:00

      使用该偏移量以OffsetDateTime 的形式获取当前时刻。

      OffsetDateTime odt = OffsetDateTime.now( offset ) ;
      

      odt.toString(): 2018-02-15T16:44:44.216642+10:00

      您想将小时改写为23

      OffsetDateTime odt23 = odt.withHour( 23 ) ;
      

      odt23.toString(): 2018-02-15T23:44:44.216642+10:00

      时区

      我正在尝试设置 HOUR_OF_DAY 字段并更改 GregorianCalendar 日期对象的时区。

      不,您正在更改 offset-from-UTC,而不是 time zone

      总是更好地使用时区而不是仅仅使用偏移量,如果您确定预期的区域。时区是某个地区的人们使用的偏移量的过去、现在和未来变化的历史。使用时区,您始终可以确定偏移量,但反之则不行。

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

      ZoneId z = ZoneId.of( "Australia/Brisbane" ) ;  
      

      在该区域的人们看到的挂钟时间中捕捉当前时刻。

      ZonedDateTime zdt = ZonedDateTime.now( z ) ;
      

      覆盖一天中的小时。

      ZonedDateTime zdt23 = zdt.withHour( 23 ) ;
      

      关于java.time

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

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

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

      使用符合JDBC 4.2 或更高版本的JDBC driver,您可以直接与您的数据库交换java.time 对象。不需要字符串也不需要 java.sql.* 类。

      从哪里获得 java.time 类?

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-06
        • 2011-02-21
        • 1970-01-01
        • 2021-01-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多