在Java中更改时区而不更改时间
我从一个SOAP Web服务接收到一个没有timzone信息的datetime。因此,Axis反序列化器采用UTC。然而,日期时间实际上是在悉尼时间。我通过减去时区偏移量解决了这个问题:在Java中更改时区而不更改时间,java,datetime,calendar,timezone,Java,Datetime,Calendar,Timezone,我从一个SOAP Web服务接收到一个没有timzone信息的datetime。因此,Axis反序列化器采用UTC。然而,日期时间实际上是在悉尼时间。我通过减去时区偏移量解决了这个问题: Calendar trade_date = trade.getTradeDateTime(); TimeZone est_tz = TimeZone.getTimeZone("Australia/Sydney"); long millis = trade_date.getTimeInMillis() - est
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中操作时间的经验吗?如何解决这个问题有更好的办法吗?我可怜那个用Java进行约会的傻瓜 在夏令时转换期间,您所做的几乎肯定会出错。最好的方法可能是创建一个新的日历对象,在其上设置时区,然后分别设置所有字段,例如年、月、日、小时、分钟、秒,从日期对象获取值 编辑:
为了让每个人都开心,您可能应该这样做:
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));
}
日历utcTime=Calendar.getInstance(TimeZone.getTimeZone(“UTC”);
Calendar sydneyTime=Calendar.getInstance(TimeZone.getTimeZone(“澳大利亚/悉尼”);
utcTime.setTime(交易日);
对于(int i=0;iDateTimeZone zone; // TODO : get zone
DateTime fixedTimestamp = new DateTime(year, monthOfYear, dayOfMonth, hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond, zone);
JordaMyType是不可变的,这也是一个好处。 < P>我决定重新解析用正确的时区集合接收的DATESTEN字符串。
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 );
}
}
我通常是这样做的
Calendar trade_date_utc = trade.getTradeDateTime();
TimeZone est_tz = TimeZone.getTimeZone("Australia/Sydney");
Calendar trade_date = Calendar.GetInstance(est_tz);
trade_date.setTimeInMillis( millis );
我想感谢这个人6。这对我来说是一个很好的开始,也是一个我没有考虑的方法。需要一些附加的步骤来把它带到生产代码级别。特别是观察DSTHOBLASH和ZON-OffOffice所需的步骤。我想分享我想出的解决方案。
这将从输入日历对象获取时间,将其复制到输出时间,将新时区设置为输出。这用于从数据库中提取时间并在不更改时间的情况下设置时区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() );
}
公共静态日历设置NewTimeZoneCopyOldTime(日历输入时间,
时区(时区){
如果((inputTime==null)| |(时区==null)){return(null);}
Calendar outputTime=Calendar.getInstance(时区);
对于(int i=0;i
您是否从混乱的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
运行日历测试
2016-06-30 19:09:16.522+0300
1467302956522
2016-06-30 19:09:16.522+0100
146730156522
测试运行:1,失败:0,错误:0,跳过:0,运行时间:0.137秒;@Alexander Pogrebnyak:我已经更新了答案,这样用户就不会被带到黑暗面;-)我总是,永远,并且只通过使用唯一固定的单位来操纵日期(用任何语言)。这个单位是秒(或毫秒)。有59秒或61秒的分钟,也有23小时或25小时的天。有60*60+/-1秒的小时,等等。我的所有日期都存储为(毫秒)秒,从历元开始。这就是它们在数据库中的方式,这就是它们的排序方式。我进行时区/yyyy-mm-dd转换的唯一时间是当需要向用户显示时(或者当使用不理解日期以秒表示的坏API时)。@wizardofods。这是一个合理的建议,但OP清楚地表明,他从web服务(可能是第三方)接收时间戳,并使用第三方库处理该请求。显然,有些事情是他无法直接控制的,使用java.util.Calendar从时区转换到时区肯定不是一件简单的事情。谢谢您的评论。我使用Axis从WSDL文件生成Web服务存根。我正在使用生成的类连接到第三方web服务。实际上,我认为他们应该用时区信息或UTC传输日期时间字段,这正是Axis所期望的。但这不是我的选择。谢谢你链接到JodaTime。但是,我不会为该项目引入新的第三方库。但是我会考虑NEX时间。JoDaTimes非常值得添加第三方库。久经考验的。众所周知,java.util.Date和Calendar类非常麻烦。
@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);
}