Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/384.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Joda Time中使用两个时区格式解析日期的模式_Java_Date_Jodatime - Fatal编程技术网

Java Joda Time中使用两个时区格式解析日期的模式

Java Joda Time中使用两个时区格式解析日期的模式,java,date,jodatime,Java,Date,Jodatime,我有一个场景,其中我以各种不同的模式(从第三方电子邮件服务器)获取日期字符串(例如): 2017年3月13日星期一19:00:10+0530(IST) 2017年3月21日星期二09:23:00-0700(PDT) Sun,2017年3月12日14:31:13+0000(UTC) 这意味着,只有时区在改变。我可以很容易地使用Java解析它,例如: String pattern = "EEE, dd MMM yyyy HH:mm:ss Z '('z')'" SimpleDateFormat d

我有一个场景,其中我以各种不同的模式(从第三方电子邮件服务器)获取日期字符串(例如):

  • 2017年3月13日星期一19:00:10+0530(IST)
  • 2017年3月21日星期二09:23:00-0700(PDT)
  • Sun,2017年3月12日14:31:13+0000(UTC)
这意味着,只有时区在改变。我可以很容易地使用Java解析它,例如:

String pattern = "EEE, dd MMM yyyy HH:mm:ss Z '('z')'"
SimpleDateFormat df = new SimpleDateFormat(pattern);
df.parse("Fri, 31 Mar 2017 13:31:14 +0530 (IST)");
但是当使用Joda时间库时,我不能使用相同的模式

String pattern = "EEE, dd MMM yyyy HH:mm:ss Z '('z')'"
DateTimeFormat parser = DateTimeFormat.forPattern(pattern)
parser.parseDateTime("Fri, 31 Mar 2017 13:31:14 +0530 (IST)")
我在这里错过了什么?

tl;博士 见类似内容

使用java.time 仅供参考:该项目目前正在进行中,建议迁移到类

Joda Time中的两个时区格式

2017年3月13日星期一19:00:10+0530(IST)

不,那是零格式

+0530
是一个,距离您的手机有小时和分钟的距离

大陆/地区
的格式指定,例如,或
太平洋/奥克兰
。切勿使用3-4个字母的缩写,如
EST
IST
,因为它们不是真正的时区,也不是标准化的,甚至不是唯一的(!)

由于3-4个字母的缩写无法可靠解析,Joda Time有一项拒绝尝试的政策(如上面Hugo的评论所述)。鉴于我们接下来看到的情况,我怀疑这是一项明智的政策

java.time类将尝试猜测解析此类伪时区名称,但可能不是您想要的值。事实上,它不恰当地解释了您的第一个示例,将
IST
显然解释为以色列标准时间,而不包括印度标准时间、爱尔兰标准时间以及可能更多的时间

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
,它至少为您提供了时间线上的确切时刻。以
即时
的方式调整到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

使用末尾的数字偏移量作为对象进行解析,以指导我们了解该值的确切时刻

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

提取一个对象,以UTC为单位为我们提供相同的时刻

Instant instant = odt.toInstant ();
instant.toString():2017-03-13T13:30:10Z

如果你坚持,你可以调整到你自己的特定时区。但我建议穿上你的衣服时学会用UTC思考。将UTC视为“唯一的真实时间”,所有其他区域都只是该主题的变体

ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( z );
ISO 8601 示例中所示的模式在过去的协议(如RFC1123/RFC822)中很常见

如今,方法是始终使用。在这个现代标准中,格式易于跨各种人类文化阅读,对英语的依赖性较小,易于机器解析,并且设计为明确无误

在生成/解析字符串时,java.time类默认使用ISO 8601。您可以在上面的示例中看到它们生成的输出。请注意,
zoneDateTime
通过在方括号中添加时区名称来扩展标准


顺便说一下,如果您有完全符合RFC 1123的类似输入,请知道java.time提供了一个预定义的格式化程序对象。

根据javadoc()-区域名称:无法解析时区名称('z')。因此,此字段仅用于format/toString()。请看一下
-0700
的偏移量是如何描述为UTC的?据我所知,只有五个半小时的偏移量是印度,但会是负偏移量,而你的是正偏移量。这些是实际值还是没有正确地组合这些示例?@BasilBourque抱歉,示例是错误的。我修正了。第一个是真的吗,IST的偏移量为正?答案很好!非常有用。尽管如此,我将所有的日期/时间保存在数据库中,并记录在UTC中,因为正如您所说,这是一个真实的时间:)我想切掉第一手的最后一部分,但很好奇我是否遗漏了什么,因此提出了一个问题。由于我在各种其他模式中也得到了这个日期字符串(来自Mailgun,所以我被困在了多个模式中),所以我将调整斩波代码,只删除这个特定模式中的最后一部分。再次感谢@ShashankAgrawal您可以使用偏移量和缩写来推断
+0530(IST)
表示印度时间(
Asia/Kolkata
),而不是爱尔兰等时间。但是时区会改变它们的偏移量,而且变化的频率惊人。所以最终你只是在猜测,这样的猜测代码将来可能会被破解。不需要猜测预期的时区,因为仅偏移量就可以到达UTC,这是记录和比较所需的全部。另外,请注意我在最后添加的最后一句话——你说你有类似的输入,如果RFC1123使用预定义的格式化程序的话。我没有理解你的观点,最终你只是在猜测。你能详细解释一下吗?这样我就可以在我错的地方修正我的代码。@ShashankAgrawal至于“猜测”,我根本不是指你的代码。我指的是我关于将
+0530(IST)
映射到印度时间的评论。虽然我们现在所知道的一切都是可能的,但在未来,分区定义和偏移可以也将发生变化。当这些变化在未来发生时,我们今天所做的任何硬编码映射都将被破坏。所以我们只能猜测预期的时区。这就是为什么当有人想要交流时区时,他们应该指定一个。哦,太好了!谢谢你的澄清。
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( z );