【问题标题】:Converting between timezones even when the same changes the date (UTC to UTC)即使相同更改日期(UTC 到 UTC),也可以在时区之间转换
【发布时间】:2014-06-21 10:51:34
【问题描述】:

我一直很困惑为什么下面的代码会导致我的日期从 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 

结果 “2014 年 5 月 24 日星期六 05:00:00 SAST”

【问题讨论】:

    标签: java datetime timezone jodatime


    【解决方案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 对象。当您输出时,本地时区再次影响结果。

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

    但是,更好的解决方案是改用JodaTime's DateTimeFormatter。这样你就不用使用SimpleDateFormatDate了。

    【讨论】:

    • 是的,经过一段时间的努力,我想通了。你是对的。感谢您的回答!
    【解决方案2】:

    我认为在 UTC 客户时区中,南非的 25/05/2014 00:00:00 被视为 24/5 晚上 10 点。最后将时间设置为凌晨 5 点。

    【讨论】:

      【解决方案3】:

      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
      

      【讨论】:

      • 伟大的例子罗勒。谢谢! :)
      • 感谢您的全面回答。我应该在我的问题中包含完整的方法,以回答您对我为什么使用 LocalDateTime 的不确定性。上面的代码是返回 java.util.Date 的方法的一部分。因此使用 LocalDateTime。使用它的原因是因为 DateTime.toDate() 方法返回一个新的 Java 日期对象,该对象由 DateTime 对象的毫秒构造。但是 .withTimeZone() 方法不会更改毫秒,导致返回的 java.util.Date 是没有应用时区的原始日期。
      猜你喜欢
      • 2011-07-11
      • 2013-08-18
      • 1970-01-01
      • 1970-01-01
      • 2021-12-31
      • 2019-11-26
      • 1970-01-01
      • 2019-09-07
      • 2010-09-22
      相关资源
      最近更新 更多