为什么Jodatime TimeZone转移日期时间



当字符串" 2017-04-21T17:46:00z"传递到第一个方法中,由此产生的格式化日期字符串为" 06:46 2017年4月21日"。为什么小时搬到11个小时?JSON中的HTTP服务器应用程序提供了输入字符串。我以为Z后缀是指Zulu,即GMT。

private static final String DATE_TIME_FORMAT = "hh:mm dd MMM yyyy";
public static String formatTimestamp(String dateTimestamp) {
    DateTime dateTime = getDateTimeFromTimestamp(dateTimestamp);
    DateTimeFormatter fmt = DateTimeFormat.forPattern(DATE_TIME_FORMAT);
    return fmt.print(dateTime);
}
private static DateTime getDateTimeFromTimestamp(String dateTimestamp) {
    return new DateTime(dateTimestamp);
}

我怀疑它与时区有关,但尚不清楚如何或在哪里。该代码正在英国的Android设备,GMT TimeZone。(但不是Android的版本(

这就是我可以重现问题的方式:

// changing my default timezone (because I'm not in UK)
DateTimeZone.setDefault(DateTimeZone.forID("Europe/London"));
// calling your method
System.out.println(formatTimestamp("2017-04-21T17:46:00Z"));

输出为

06:46 21 ABR 2017

要检查出什么问题,我将日期格式更改为:

DATE_TIME_FORMAT2 = "hh:mm a dd MMM yyyy Z z zzzz";

如果 a表示" am或pm",则 Z是时区偏移/id, z是时区" short"名称,而 zzzz是时区"长"名称。使用此格式,输出为:

06:46 PM 21 ABR 2017 0100 BST英国夏季时间

因此,DateTime创建的时间为6pm,提前一小时提前一个小时,而不是您想象的11个小时(实际上,如果将格式更改为HH而不是hh,则小时将为18,而不是06(。

(。

还请注意时区字段:+0100 BST British Summer Time。第一部分(+0100(意味着此DateTime比GMT提前一小时,而BST British Summer Time意味着它在英国的日光节省时间。


因此,要使输出等于输入,您有2个替代方案:

1。将默认时区更改为UTC:

DateTimeZone.setDefault(DateTimeZone.UTC);
System.out.println(formatTimestamp("2017-04-21T17:46:00Z"));

输出将是:

05:46 2017年4月21日

如果您想更改为17:46的时间,请更改日期格式,用HH

替换hh

2。使用接收DateTimeZoneDateTime构造函数:

private static DateTime getDateTimeFromTimestamp(String dateTimestamp) {
    // creates a DateTime in UTC
    return new DateTime(dateTimestamp, DateTimeZone.UTC);
}

输出将与替代1相同,但是在这种情况下,您不需要更改默认时区。

对我来说,替代2更有意义,因为:

  • 您不需要更改默认时区(这可能会在应用程序的其他部分造成一些混乱(
  • 您已经知道,该代码处理的所有日期都在UTC时间(由于" Z"最终(

使用Java.Time

雨果的答案似乎是正确且内容丰富的。但是仅供参考,Joda Time项目现在处于维护模式,团队建议迁移到Java.Time课程。对于Android,请参见下面底部的最后一颗子弹。

您的输入字符串以标准ISO 8601格式为单位。java.Time类使用标准格式时进行解析&生成字符串。因此无需指定格式模式。

Instant类代表UTC中时间表上的瞬间,其分辨率为纳秒(小数分数的9(9(位数(。

String input = "2017-04-21T17:46:00Z" ;
Instant instant = Instant.parse( input ) ;

instant.tostring((:2017-04-21T17:46:00z

对于更灵活的格式(例如您想要的(,如果您可以在小时和几分钟内指定任何偏移量,请转换为OffsetDateTime对象。我们需要UTC本身(零偏移(,以便我们可以使用常量的ZoneOffset.UTC

OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;

odt.tostring((:2017-04-21T17:46Z

定义格式模式以匹配您所需的格式。请注意,您必须指定Locale来确定(a(人类语言,用于翻译日期,月份名称等的人类语言,以及(b(决定缩写,资本化,标点,分离器等问题的文化规范。

DateTimeFormatter f = DateTimeFormatter.ofPattern( "hh:mm dd MMM yyyy" , Locale.US ) ;
String output = odt.format( f ) ;

输出:05:46 2017年4月21日

如果您想通过区域的墙壁锁定时间(例如Europe/LondonPacific/Auckland(看到同一时刻,请应用一个时区以获取ZonedDateTime

continent/region的格式指定适当的时区名称,例如America/MontrealAfrica/CasablancaPacific/Auckland。切勿使用3-4个字母缩写,例如ESTISTBST,因为它们不是不是真实时区,而不是标准化,甚至不是唯一的(!(。

ZoneId z = ZoneId.of( "Europe/London" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

请注意,由于节日储蓄时间(DST(,时间是一个小时的时间。

zdt.tostring((:2017-04-21T18:46 01:00 [欧洲/伦敦]

请参阅此代码在IDEONE.com上进行直播。

关于java.time

Java.Time框架内置在Java 8及更高版本中。这些类取代了麻烦的旧旧日期时间类,例如java.util.DateCalendar,&SimpleDateFormat

现在处于维护模式的Joda Time项目建议迁移到Java.Time类。

要了解更多信息,请参阅Oracle教程。并搜索堆栈溢出以获取许多示例和解释。规格是JSR 310。

从哪里获得Java.Time课程?

  • Java SE 8 Java SE 9 ,然后
    • 内置。
    • 标准Java API的一部分,具有捆绑的实现。
    • Java 9添加了一些次要功能和修复。
  • Java SE 6 Java SE 7
    • 大部分Java.Time功能都回到Java 6&7在 Threeten-Backport
  • Android
    • threetenabp project aptapts threeten-backport (上面提到(Android专门。
    • 参见如何使用Threetenabp…

相关内容

  • 没有找到相关文章

最新更新