当字符串“2017-04-21T17:46:00Z”传递给第一种方法时,生成的格式化日期字符串为“2017年4月21日06:46”。为什么小时移动了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时区运行。
答案 0 :(得分:3)
我已经使用java 7和joda-time 2.7进行了测试(但不是Android' s版本)
这就是我如何重现这个问题:
// 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
是时区"短"名称和zzzz
是时区" long"名称。使用此格式,输出为:
06:46 PM 21 Abr 2017 +0100 BST英国夏令时
因此创建的日期时间是下午6点,比输入提前一小时,而不是您想的十一小时(实际上,如果您将格式更改为HH
而不是hh
,则小时数将为{{ 1}}而不是18
)。
另请注意时区字段:06
。第一部分(+0100 BST British Summer Time
)表示此+0100
比GMT提前一小时,而DateTime
表示它位于British's Daylight Saving Time。
因此,要使您的输出等于您的输入,您有两种选择:
1. 将您的默认时区更改为UTC:
BST British Summer Time
输出将是:
2017年4月21日2017年4月
如果您想将小时数更改为DateTimeZone.setDefault(DateTimeZone.UTC);
System.out.println(formatTimestamp("2017-04-21T17:46:00Z"));
,请更改日期格式,将17:46
替换为hh
2。使用收到HH
的{{1}}构造函数:
DateTime
输出与替代1相同,但在这种情况下,您不需要更改默认时区。
对我来说,替代2更有意义,因为:
答案 1 :(得分:1)
Answer by Hugo似乎是正确且信息丰富的。但仅供参考,Joda-Time项目现在位于maintenance mode,团队建议迁移到java.time类。对于Android,请参阅下面底部的最后一个项目符号。
您的输入字符串采用标准ISO 8601格式。解析时,java.time类使用标准格式。生成字符串。因此无需指定格式化模式。
Instant
类代表UTC中时间轴上的一个时刻,分辨率为nanoseconds(小数部分最多九(9)位)。
String input = "2017-04-21T17:46:00Z" ;
Instant instant = Instant.parse( input ) ;
instant.toString():2017-04-21T17:46:00Z
如果您想要更灵活的格式,请转换为OffsetDateTime
对象,您可以在小时和分钟内指定任何offset-from-UTC。我们想要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 ) ;
输出:2017年4月21日05:46
如果您希望通过区域的挂钟时间(例如Europe/London
或Pacific/Auckland
)看到同一时刻,请应用时区来获取ZonedDateTime
。
以continent/region
的格式指定proper time zone name,例如America/Montreal
,Africa/Casablanca
或Pacific/Auckland
。切勿使用诸如EST
或IST
或BST
之类的3-4字母缩写,因为它们不是真正的时区,不是标准化的,甚至不是唯一的( !)。
ZoneId z = ZoneId.of( "Europe/London" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
请注意,由于夏令时(DST),时间是一小时。
zdt.toString():2017-04-21T18:46 + 01:00 [欧洲/伦敦]
请参阅此code run live at IdeOne.com。
java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.Date
,Calendar
和& SimpleDateFormat
现在位于Joda-Time的maintenance mode项目建议迁移到java.time类。
要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310。
从哪里获取java.time类?