当字符串" 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。使用接收DateTimeZone
的DateTime
构造函数:
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/London
或Pacific/Auckland
(看到同一时刻,请应用一个时区以获取ZonedDateTime
。
以continent/region
的格式指定适当的时区名称,例如America/Montreal
,Africa/Casablanca
或Pacific/Auckland
。切勿使用3-4个字母缩写,例如EST
或IST
或BST
,因为它们不是不是真实时区,而不是标准化,甚至不是唯一的(!(。
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.Date
,Calendar
,&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…。