在时区之间进行转换,即使同一时区更改了日期(UTC到UTC)



我一直很困惑,为什么下面的代码会导致我的日期从25日更改为24日

SimpleDateFormat sd = new SimpleDateFormat("dd/MM/yyyy");
DateTimeZone customerZone = DateTimeZone.forTimeZone(TimeZone.getTimeZone("UTC"));
DateTimeZone serverZone = DateTimeZone.UTC;
Date date = sd.parse("25/05/2014");
DateTime source = new DateTime(date).withZone(customerZone).withHourOfDay(5);
LocalDateTime ldate = new LocalDateTime(source, serverZone);
System.out.println(ldate.toDate()); //expected to be Sat May 25 05:00:00 

结果

您没有为SimpleDateFormat设置时区,因此它默认为您的环境的时区,我猜是"Africa/Johannesburg",因为您的结果中有SAST。

所以当你做这部分时:

SimpleDateFormat sd = new SimpleDateFormat("dd/MM/yyyy");
Date date = sd.parse("25/05/2014");

date天体将在SAST的午夜,即UTC的前一天晚上10点。其余部分从这里开始,因为您从那时起就在使用UTC。

同样,在最后,您调用toDate,这将产生一个Date对象。当您输出该结果时,本地时区也会影响结果。

可以考虑在SimpleDateFormat对象上调用setTimeZone。这样至少可以使开头部分正确。但是,您还应该使用format方法来输出最终字符串。

然而,更好的解决方案是使用JodaTime的DateTimeFormatter。那么你就不需要使用SimpleDateFormatDate了。

我认为南非的25/05/2014 00:00:00被看作是UTC客户时区的24/5,晚上10点。最后将时间设置为上午5点

Matt Johnson的答案是正确的。当您省略一个时区时,将应用JVM的默认时区。我建议总是指定时区,而不是依赖于隐式默认值,即使通过显式调用getDefault()完成。

<标题>纯Joda-Time h1> 供参考,这里是一个更好的方法来做这项工作的一些示例代码。这种方法只使用Joda-Time。混合jdk - time和java.util。正如你的问题所示,日期/日历会导致混乱和痛苦。此外,java.util。Date、。calendar和SimpleDateFormat类是出了名的麻烦,应该避免使用。 顺便说一下,不需要调用getTimeZone并传递TimeZone对象。Joda-Time有一个内置的UTC常量:DateTimeZone.UTC
DateTimeFormatter formatter = DateTimeFormat.forPattern( "dd/MM/yyyy" ); // Usually I specify a Locale as well. But in this case, no need (no names of days or months).
DateTimeZone customerTimeZone = DateTimeZone.UTC;
String input = "25/05/2014";
DateTime customerDateTime = formatter.withZone( customerTimeZone ).parseDateTime( input );
DateTime customerDateTimeAtFive = customerDateTime.withHourOfDay( 5 );  // Using customerTimeZone.

不知道为什么你故意通过转换到LocalDateTime丢失时区信息。如果目标是在服务器上处理UTC的日期-时间值,则不需要丢失时区。服务器端代码应该使用显式分配给UTC时区的DateTime对象。你可以这样调整时区:

DateTime serverDateTime = customerDateTimeAtFive.withZone( DateTimeZone.UTC );

但无论如何,如果你坚持(与问题中的代码相同)…

DateTimeZone serverTimeZone = DateTimeZone.UTC;
LocalDateTime localDateTime = new LocalDateTime( customerDateTimeAtFive, serverTimeZone ); // I don't see the point of using LocalDateTime, but here goes anyways.

转储到控制台

System.out.println( "customerTimeZone: " + customerTimeZone );
System.out.println( "input: " + input );
System.out.println( "customerDateTime: " + customerDateTime );
System.out.println( "customerDateTimeAtFive: " + customerDateTimeAtFive );
System.out.println( "serverDateTime: " + serverDateTime );
System.out.println( "serverTimeZone: " + serverTimeZone );
System.out.println( "localDateTime: " + localDateTime );

运行时。

customerTimeZone: UTC
input: 25/05/2014
customerDateTime: 2014-05-25T00:00:00.000Z
customerDateTimeAtFive: 2014-05-25T05:00:00.000Z
serverDateTime: 2014-05-25T05:00:00.000Z
serverTimeZone: UTC
localDateTime: 2014-05-25T05:00:00.000

最新更新