我一直很困惑为什么以下代码导致我的日期从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
结果 " Sat May 24 05:00:00 SAST 2014"
答案 0 :(得分:1)
我认为在UTC客户时区,南非的25/05/2014 00:00:00被视为24/5,10:00。最后,小时设定为上午5点。
答案 1 :(得分:1)
您尚未为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
个对象。输出时,本地时区再次影响结果。
您可以考虑在setTimeZone
对象上调用SimpleDateFormat
。这至少会使开始部分正确。但是您也应该使用format
方法输出最终字符串。
但是,更好的解决方案是使用JodaTime's DateTimeFormatter
代替。然后,您根本不必使用SimpleDateFormat
或Date
。
答案 2 :(得分:1)
answer by Matt Johnson是正确的。省略时区时,将应用JVM的默认时区。我建议始终指定时区而不是依赖隐式默认值,即使通过显式调用getDefault()
来完成。
仅供参考,这里有一些示例代码,可以更好地完成这项工作。这种方式仅使用Joda-Time。正如您的问题所示,混合使用Joda-Time和java.util.Date/Calendar会导致混乱和痛苦。此外,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