我从没有timzone信息的SOAP Web服务接收日期时间。因此,Axis解串器采用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中操纵时间的经验?关于如何解决这个问题的更好的想法?
答案 0 :(得分:18)
我怜悯那些必须用Java做日期的傻瓜。
在夏令时过渡期间,您所做的几乎肯定会出错。最好的方法是创建一个新的Calendar对象,在其上设置Timezone,然后单独设置所有字段,如年,月,日,小时,分钟,秒,从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));
}
然后你不会使用任何弃用的方法。
答案 1 :(得分:5)
我要感谢此人的回应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() );
}
答案 2 :(得分:3)
但是,我不确定这个解决方案 也需要夏令时 帐户。我认为应该,因为 所有操作都是在UTC时间。
是的,您应该考虑夏令时,因为它会影响到UTC的偏移。
在Java中操纵时间的任何经验?关于如何解决这个问题的更好的想法?
Joda-Time是一个更好的时间API。也许下面的代码片段可能会有所帮助:
DateTimeZone zone; // TODO : get zone
DateTime fixedTimestamp = new DateTime(year, monthOfYear, dayOfMonth, hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond, zone);
JodaTime类型是不可变的,这也是一种好处。
答案 3 :(得分:2)
我通常这样做
Calendar trade_date_utc = trade.getTradeDateTime();
TimeZone est_tz = TimeZone.getTimeZone("Australia/Sydney");
Calendar trade_date = Calendar.GetInstance(est_tz);
trade_date.setTimeInMillis( millis );
答案 4 :(得分:1)
@Test
public void tzTest() {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS Z");
TimeZone tz1 = TimeZone.getTimeZone("Europe/Moscow");
Calendar cal1 = Calendar.getInstance(tz1);
long l1 = cal1.getTimeInMillis();
df.setTimeZone(tz1);
System.out.println(df.format(cal1.getTime()));
System.out.println(l1);
TimeZone tz2 = TimeZone.getTimeZone("Africa/Douala");
Calendar cal2 = Calendar.getInstance(tz2);
long l2 = l1 + tz1.getRawOffset() - tz2.getRawOffset();
cal2.setTimeInMillis(l2);
df.setTimeZone(tz2);
System.out.println(df.format(cal2.getTime()));
System.out.println(l2);
assertNotEquals(l2, l1);
}
运行CalendarTest
2016-06-30 19:09:16.522 +0300
1467302956522
2016-06-30 19:09:16.522 +0100
1467310156522
测试运行:1,失败:0,错误:0,跳过:0,经过的时间:0.137秒
答案 5 :(得分:0)
您是否从该混乱的Web服务获得ISO 8601样式字符串?如果是这样,Joda-Time 2.3库使这很容易。
如果您获得的ISO 8601字符串没有任何时区偏移,则将时区对象传递给DateTime构造函数。
DateTimeZone timeZone = DateTimeZone.forID( "Australia/Sydney" );
String input = "2014-01-02T03:00:00"; // Note the lack of time zone offset at end.
DateTime dateTime = new DateTime( input, timeZone );
转储到控制台...
System.out.println( "dateTime: " + dateTime );
跑步时......
dateTime: 2014-01-02T03:00:00.000+11:00
答案 6 :(得分:-1)
我决定重新分析使用正确的时区设置收到的日期时间字符串。这也应该考虑夏令时:
public class DateTest {
private static SimpleDateFormat soapdatetime = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
/**
* @param args
*/
public static void main(String[] args) {
TimeZone oztz = TimeZone.getTimeZone("Australia/Sydney");
TimeZone gmtz = TimeZone.getTimeZone("GMT");
Calendar datetime = Calendar.getInstance( gmtz );
soapdatetime.setTimeZone( gmtz );
String soap_datetime = soapdatetime.format( datetime.getTime() );
System.out.println( soap_datetime );
soapdatetime.setTimeZone( oztz );
datetime.setTimeZone( oztz );
try {
datetime.setTime(
soapdatetime.parse( soap_datetime )
);
} catch (ParseException e) {
e.printStackTrace();
}
soapdatetime.setTimeZone( gmtz );
soap_datetime = soapdatetime.format( datetime.getTime() );
System.out.println( soap_datetime );
}
}