tl;博士
String input = "Mon, 13 Mar 2017 19:00:10 +0530 (IST)";
int index = input.indexOf ( " (" ); // Searching for SPACE + LEFT PARENTHESIS.
String inputModified = input.substring ( 0 , index ); // "Mon, 13 Mar 2017 19:00:10 +0530"
Instant instant =
OffsetDateTime.parse (
inputModified ,
DateTimeFormatter.ofPattern( "EEE, d MMM uuuu HH:mm:ss Z" )
).toInstant()
;
查看类似的code run live at IdeOne.com。
使用 java.time
仅供参考:Joda-Time 项目现在位于 maintenance mode,建议迁移到 java.time 类。
Joda-Time 中的两个时区格式
2017 年 3 月 13 日星期一 19:00:10 +0530 (IST)
不,那是 零 time zone 格式。
+0530 是一个offset-from-UTC,与UTC 相距数小时和数分钟。
以continent/region 的格式指定proper time zone name,例如America/Montreal、Africa/Casablanca 或Pacific/Auckland。切勿使用 3-4 个字母的缩写,例如 EST 或 IST,因为它们不是真正的时区,没有标准化,甚至不是唯一的(!)。
由于无法可靠地解析 3-4 个字母的缩写,Joda-Time 有拒绝尝试的政策(如上面 Hugo 的评论中所述)。鉴于我们接下来看到的情况,我怀疑这是一个明智的政策。
java.time 类将尝试猜测解析此类伪时区名称,但可能不是您的预期值。实际上,它不恰当地解释了您的第一个示例,显然将 IST 解释为 Israel Standard Time 选项包括 India Standard Time、Ireland Standard Time em>,可能还有更多。
String input = "Mon, 13 Mar 2017 19:00:10 +0530 (IST)";
DateTimeFormatter f = DateTimeFormatter.ofPattern( "EEE, d MMM uuuu HH:mm:ss Z '('z')'") ;
ZonedDateTime zdt = ZonedDateTime.parse ( input , f );
zdt.toString(): 2017-03-13T19:00:10+02:00[亚洲/耶路撒冷]
所以我建议你去掉最后的虚假缩写块。将剩余的文本解析为OffsetDateTime,这至少可以为您提供时间轴上的准确时刻。将 Instant 调整为 UTC,因为您的大部分工作通常应在 UTC 中完成,包括您的日志记录。
使用String::substring 去掉缩写。请注意,我们在子字符串搜索中包含左括号前的空格,因为我们要删除字符和之后的所有内容。
String input = "Mon, 13 Mar 2017 19:00:10 +0530 (IST)";
int index = input.indexOf ( " (" ); // Searching for SPACE + LEFT PARENTHESIS.
String inputModified = input.substring ( 0 , index );
输入修改时间:2017 年 3 月 13 日星期一 19:00:10 +0530
使用末尾的数字偏移量解析为OffsetDateTime 对象,以指导我们了解该值的确切时刻。
DateTimeFormatter f = DateTimeFormatter.ofPattern( "EEE, d MMM uuuu HH:mm:ss Z" );
OffsetDateTime odt = OffsetDateTime.parse ( inputModified , f );
odt.toString(): 2017-03-13T19:00:10+05:30
提取一个 Instant 对象,以在 UTC 中为我们提供相同的时刻。
Instant instant = odt.toInstant ();
instant.toString(): 2017-03-13T13:30:10Z
如果您坚持,您可以调整到自己的特定时区。但我建议在佩戴 Programmer hat 时学习以 UTC 进行思考。将 UTC 视为“真正的时间”,所有其他时区都只是该主题的变体。
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( z );
ISO 8601
您的示例中显示的那种模式在过去的协议中很常见,例如 RFC 1123 / RFC 822。
如今,方法是始终使用ISO 8601。在这个现代标准中,格式易于在各种人类文化中阅读,对英语的依赖较少,易于机器解析,并且设计明确。
java.time 类在生成/解析字符串时默认使用 ISO 8601。您可以在我上面的示例中看到它们生成的输出。请注意,ZonedDateTime 通过在方括号中附加时区名称来扩展标准。
顺便说一句,如果您有完全符合 RFC 1123 的类似输入,请知道 java.time 提供了一个预定义的格式化程序对象 DateTimeFormatter.RFC_1123_DATE_TIME。