【问题标题】:Joda Time parse a date with timezone and retain that timezoneJoda Time 使用时区解析日期并保留该时区
【发布时间】:2013-05-23 14:02:25
【问题描述】:

我想解析使用特定时区创建的日期,将其转换为格式并返回。转换有效,但时区偏移量始终设置为 +0000,并根据需要添加/减去时差。我怎样才能让它格式化并保持正确的偏移量?

我预计:2012-11-30T12:08:56.23+07:00

但是得到这个:2012-11-30T05:08:56.23+00:00

实施:

public static final String ISO_8601_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSZZ";

public static String formatDateToISO8601Standard(Date date) {
    DateTime dateTime = new DateTime(date);
    DateTimeFormatter df = DateTimeFormat.forPattern(ISO_8601_DATE_FORMAT);
    return dateTime.toString(df);
}

测试类:

private static final String DATE_WITH_TIMEZONE = "30 11 2012 12:08:56.235 +0700";
private static final String EXPECTED_DATE_WITH_TIMEZONE = "2012-11-30T12:08:56.23+07:00";

@Test public void testFormattingDateWithSpecificTimezone() throws Exception {
    String result = JodaDateUtil.formatDateToISO8601Standard(createDate(DATE_WITH_TIMEZONE));
    assertEquals("The date was not converted correctly", EXPECTED_DATE_WITH_TIMEZONE, result); }

private Date createDate(String dateToParse) throws ParseException {
    DateTimeFormatter df = DateTimeFormat.forPattern("dd MM yyyy HH:mm:ss.SSS Z");
    DateTime temp = df.parseDateTime(dateToParse);
    Date date = temp.toDate();
    return date; }

【问题讨论】:

    标签: java date jodatime


    【解决方案1】:

    基本上,一旦您 [在您的 createDate() 方法中] 解析日期字符串,您就失去了原始区域。 Joda-Time 将允许您使用任何区域格式化日期,但您需要保留原始区域。

    在您的 createDate() 方法中,DateTimeFormatter"df" 可以返回字符串上的区域。您需要使用withOffsetParsed() 方法。然后,当您拥有DateTime 时,请致电getZone()。如果您将此区域保存在某处或以某种方式将其传递给您的格式化例程,那么您可以通过创建 DateTimeFormatter "withZone" 并将该区域指定为您想要的格式来使用它。

    作为演示,这里有一些单一方法中的示例代码。希望它可以帮助您按照您希望的方式更改代码。

      public static void testDate() 
      {
        DateTimeFormatter df = DateTimeFormat.forPattern("dd MM yyyy HH:mm:ss.SSS Z");
        DateTime temp = df.withOffsetParsed().parseDateTime("30 11 2012 12:08:56.235 +0700");
        DateTimeZone theZone = temp.getZone();
    
        Date date = temp.toDate();
    
        DateTime dateTime = new DateTime(date);
        DateTimeFormatter df2 = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSZZ");
        DateTimeFormatter df3 = df2.withZone(theZone);
    
        System.out.println(dateTime.toString(df2));
        System.out.println(dateTime.toString(df3));
    
      }
    

    【讨论】:

      【解决方案2】:

      试试这个。

      ISODateTimeFormat.dateTimeParser().parseDateTime(dateString), 
      

      然后将其转换为您想要的格式。

      【讨论】:

      • 改用这个ISODateTimeFormat.dateTimeParser().withOffsetParsed().parseDateTime(dateString);
      【解决方案3】:

      tl;博士

      OffsetDateTime.parse ( 
          "30 11 2012 12:08:56.235 +0700" , 
          DateTimeFormatter.ofPattern ( "dd MM uuuu HH:mm:ss.SSS X" , Locale.US )
      ).toString() 
      

      2012-11-30T12:08:56.235+07:00

      详情

      接受的答案是正确的。一旦转换为 java.util.Date 对象,您就会丢失时区信息。这很复杂,因为java.util.Date::toString 在生成字符串时会混淆地应用当前默认时区。

      避免使用这些旧的日期时间类,例如 java.util.Date。它们设计不良,令人困惑且麻烦。现在是遗留的,被 java.time 项目所取代。 Joda-Time 项目现在也被 java.time 类所取代。

      java.time

      将该输入字符串解析为 OffsetDateTime 对象,因为它包含与 UTC 的偏移量但缺少时区。调用DateTimeFormatter.ofPattern 指定与您的输入字符串匹配的自定义格式。将该格式化程序对象传递给OffsetDateTime.parse

      String input = "30 11 2012 12:08:56.235 +0700" ;
      DateTimeFormatter f = DateTimeFormatter.ofPattern ( "dd MM uuuu HH:mm:ss.SSS X" , Locale.US );
      OffsetDateTime odt = OffsetDateTime.parse ( input , f );
      

      odt:toString(): 2012-11-30T12:08:56.235+07:00

      要查看 UTC 中的同一时刻,请提取 InstantInstant 类代表UTC 中时间线上的时刻,分辨率为nanoseconds(最多九 (9) 位小数)。

      Instant instant = odt.toInstant();
      

      instant.toString(): 2012-11-30T05:08:56.235Z

      您可以应用任何时区来查看时间轴上的同一时刻、同一点。

      ZonedDateTime zdtKolkata = odt.toInstant ().atZone ( ZoneId.of ( "Asia/Kolkata" ) );
      

      zdtKolkata.toString(): 2012-11-30T10:38:56.235+05:30[亚洲/加尔各答]

      根本不需要混入旧的日期时间类。坚持使用 java.time。如果您必须使用一些尚未更新为 java.time 类型的旧代码,请查看添加到旧类的新方法以与 java.time 进行转换。

      java.util.Date 的等价物是 Instant,两者都是 UTC 中 1970-01-01T00:00:00Z 的计数自纪元。但是小心数据丢失,因为 java.time 类支持纳秒级分辨率,但旧类仅限于毫秒。

      java.util.Date utilDate = java.util.Date.from( instant );
      

      实时代码

      live working code in IdeOne.com


      关于java.time

      java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.Date.Calendarjava.text.SimpleDateFormat

      Joda-Time 项目现在位于 maintenance mode,建议迁移到 java.time。

      要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310

      从哪里获得 java.time 类?

      ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

      【讨论】:

      • 这些方法在哪里?我没有看到它们: 1. DateTimeFormatter.ofPattern ("dd MM uuuu HH:mm:ss.SSS X" );你是说 forPattern() 吗? 2. OffsetDateTime odt = OffsetDateTime.parse 我只看到OffsetDateTimeField,没有静态解析方法
      • @CACuzcatlan 我添加了指向类文档的链接。并添加了指向 IdeOne.com 中实时工作代码的链接。
      • 谢谢。我刚刚意识到我很困惑,因为我在 JodaTime 中寻找那些但它们在 java.time 中
      • @CACuzcatlan 仅供参考,Joda-Time 项目建议迁移到 java.time 类。您实际上可以在项目中同时使用两者,但要小心 import 语句以避免类名和方法名冲突(如您所见)。
      【解决方案4】:

      使用格式 val formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss.SSSZZ")

      【讨论】:

        猜你喜欢
        • 2010-11-22
        • 1970-01-01
        • 2013-10-07
        • 1970-01-01
        • 2011-06-05
        • 2014-08-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多