【问题标题】:SimpleDateFormat parse method mysterySimpleDateFormat 解析方法之谜
【发布时间】:2018-10-16 19:48:13
【问题描述】:

我知道SimpleDateFormat.parse 依赖于日历 API,它依赖于本地 JVM 时区(计算机)。假设 JVM 时区是 IST。

SimpleDateFormat srcDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
srcDateFormat.setTimeZone(TimeZone.getTimeZone("EST"));
Date objDt = srcDateFormat.parse("2018-10-16 11:28:25"); //Time : 21:58:25 

从输出看来,它从 EST 转换为 IST(JVM 本地时区)。

SimpleDateFormat srcDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
srcDateFormat.setTimeZone(TimeZone.getTimeZone("IST"));
Date objDt = srcDateFormat.parse("2018-10-16 11:28:25"); //Time : 11:28:25 

在这种情况下,它保持时间不变。在这种情况下,我将时区设置为与 JVM 本地时区相同。

请帮助我理解parse 方法的行为。不过,我很想知道这种行为背后的原因。 我知道java.util.Datejava.text.SimpleDateFormat 遗留类现在已经过时了。

参考资料:

【问题讨论】:

  • 这与 parse() 方法无关。它是关于 Date 的 toString() 方法,它总是使用默认时区格式化日期。就像,即使您使用法语数字格式将字符串 "1,23" 解析为双精度,并打印双精度,它也将始终打印为 1.23,因为格式化双精度的默认方式是使用英文格式(即使用点而不是逗号作为小数分隔符)。
  • 我认为 java.util.Date 不包含任何时区信息。您的示例与区域设置更相关。
  • 这正是它的 toString() 方法需要选择一个时区来将其转换为字符串的原因。并且选择的时区是默认时区。就像 toString 方法必须选择一个语言环境来将双精度转换为字符串,而选择的是英语语言。
  • 如果上述观点为真,那么在第二种情况下,为什么它没有再次转换为 IST?日期字符串中没有时区相关信息。
  • 嗯,默认时区是 IST,您使用 IST 时区解析时间 11:28:25,当您打印日期时,使用默认 IST 时区,您会得到 11:28: 25.这是正确的时间,在 IST 时区。不知道你认为它应该是什么,也不知道为什么。

标签: java date datetime timezone simpledateformat


【解决方案1】:

首先,您是正确的,DateSimpleDateFormat 是遗留类,现在已过时。所以我建议你不要使用它们,而是使用现代 Java 日期和时间 API java.time。在众多优点中,时区之间的转换更加明确,我希望这能帮助您理解代码的作用。

其次,你做错了很多事情,或者至少做得不够好:

  1. 不要将日期时间存储为字符串。始终将它们存储为 Java 中的日期时间对象。当您这样做时,您将永远不需要将日期时间字符串从一个区域转换为另一个区域。 Instant(来自 java.time 的一个类)是一个时间点,据我所知,您应该在这里使用它。
  2. 不要依赖三个字母的时区缩写。其中很多都是模棱两可的,包括 IST 和 EST,后者不是真正的时区,所以你在一年中的这个时候得到什么(当 America/New_York 区域使用 EDT 而不是 EST),我不不知道。
  3. 再说一遍,使用现代课程,而不是过时的课程。

出于好奇发生了什么?

一个老式的Date 代表一个独立于时区的时间点(在内部它将其值存储为自纪元以来的毫秒数,但这是一个我们不需要知道或关心的实现细节) .

在您的第一个示例中,您的字符串被解析为对应于 16:28:25 UTC、印度 21:58:25、纽约 12:28:25 或牙买加 11:28:25 的时间点.我提到牙买加是因为它是少数几个全年使用东部标准时间 (EST) 的地方之一。大多数使用 EST 的地方只在冬天这样做,而不是在一年中的这个时候。当您在调试器中查看Date 时,调试器会在Date 上调用toString 以获取显示给您的字符串。 toString 反过来使用 JVM 的时区来生成字符串。在您的情况下,它是亚洲/加尔各答,这就是您得到 21:58:25 的原因。

在第二种情况下,相同的字符串被解析为对应于 UTC 05:58:25、印度 11:28:25、纽约 01:58:25 或 00:58:25 的时间点牙买加。您的调试器再次调用toString,它再次使用您的 JVM 的时区并转换回 11:28:25 IST。当您在同一时区解析和打印时,您将获得一天中的同一时间。

链接

【讨论】:

  • 感谢@Ole VV。我明白你的意思了。由于 java.util.Date 的 toString,我感到困惑。
猜你喜欢
  • 2011-08-20
  • 1970-01-01
  • 2011-01-26
  • 1970-01-01
  • 1970-01-01
  • 2013-05-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多