在 Java 中更改时区而不更改时间

2022-09-03 10:11:13

我从 SOAP Web 服务接收到一个日期时间,但没有 timzone 信息。因此,轴反序列化程序假定 UTC。但是,日期时间实际上是悉尼时间。我通过减去时区偏移量解决了这个问题:

Calendar trade_date = trade.getTradeDateTime();
TimeZone est_tz = TimeZone.getTimeZone("Australia/Sydney");
long millis = trade_date.getTimeInMillis() - est_tz.getRawOffset();
trade_date.setTimeZone( est_tz );
trade_date.setTimeInMillis( millis );

但是,我不确定此解决方案是否也考虑了夏令时。我认为应该这样做,因为所有操作都在UTC时间。在Java中操作时间的任何经验?关于如何解决这个问题的更好主意?


答案 1

我怜悯那个不得不在Java中约会的傻瓜。

你所做的几乎肯定会在夏令时过渡时出错。最好的方法可能是创建一个新的 Calendar 对象,在其上设置时区,然后分别设置所有字段,以便年、月、日、小时、分钟、秒,从 Date 对象获取值。

编辑:
为了让每个人都开心,你应该这样做:

Calendar utcTime = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
Calendar sydneyTime = Calendar.getInstance(TimeZone.getTimeZone("Australia/Sydney");
utcTime.setTime(trade_date);
for (int i = 0; i < Calendar.FIELD_COUNT; i++) {
  sydneyTime.set(i, utcTime.get(i));
}

然后,您将不会使用任何已弃用的方法。


答案 2

我要感谢这个人的回应6。这对我来说是一个很好的开始,也是我没有考虑过的方法。需要执行一些其他步骤才能将其提升到生产代码级别。特别注意DST_OFFSET和ZONE_OFFSET所需的步骤。我想分享我想出的解决方案。

这会从输入的 Calendar 对象获取时间,将其复制到输出时间,将新时区设置为输出。当从数据库中逐字获取时间并在不更改时间的情况下设置时区时,将使用它。

public static Calendar setNewTimeZoneCopyOldTime( Calendar inputTime, 
        TimeZone timeZone ) {
    if( (inputTime == null) || (timeZone == null) ) { return( null ); }

    Calendar outputTime = Calendar.getInstance( timeZone );
    for( int i = 0; i < Calendar.FIELD_COUNT; i++ ) {
        if( (i != Calendar.ZONE_OFFSET) && (i != Calendar.DST_OFFSET) ) { 
            outputTime.set(i, inputTime.get(i));
        }
    }

    return( (Calendar) outputTime.clone() );
}