日期时间对象没有“格式”
如何识别日期格式?
日期时间对象没有“格式”。每个类都定义了自己的内部存储日期时间值的机制。这种机制通常不关我们的事。类的 API,该类做出的承诺,才是最重要的。
您可能将日期时间对象生成的文本与日期时间对象本身混为一谈。日期时间类可以将文本作为其实例化的一部分进行解析。日期时间类可以生成文本来表示它们的值。但是文本和对象是分开的和不同的。
避免Calendar
如果我打印出一个日历对象,我会得到:
Calendar::toString 方法只是其许多内部字段的数据转储。显然仅用于调试,否则无用。
Calendar 类及其常用子类GregorianCalendar 现在都为legacy。几年前,随着 JSR 310 的采用,它们被 java.time 类所取代。永远不要使用它们。 GregorianCalendar 被专门替换为 ZonedDateTime。
避免Date
如果我打印出一个 Date 对象,我会得到:
Date::toString 方法的谎言。该方法在生成文本时动态应用 JVM 的当前默认时区。 java.util.Date 实际上代表 UTC 中的一个时刻,而不是在 toString 的结果中看到的时区。这个反功能是从不使用Date 的众多原因之一。
java.util.Date 类已替换为 java.time.Instant,它也代表 UTC 中的一个时刻,但分辨率更高,为纳秒而不是毫秒。
ISO 8601
但是我正在检查生成的 XML 并观察到这种格式:
2014-02-28T08:00:00.000Z
该文本的格式在ISO 8601 标准中定义。该标准被巧妙地设计为以文本形式表示各种日期时间值以进行数据交换。该标准取代了早期定义不明确的日期时间文本格式,例如在早期电子邮件协议中看到的。
java.time 类在解析/生成字符串时默认使用ISO 8601 格式。
UTC 当前时刻
要以 UTC 格式捕捉当前时刻,请使用 Instant。
Instant instant = Instant.now() ; // Capture the current moment in UTC.
生成以标准 ISO 8601 格式表示该值的文本。末尾的Z 表示UTC,发音为“Zulu”。
2020-01-23T12:34:56.123456Z
解析这样的字符串。
Instant instant = Instant.parse( "2020-01-23T12:34:56.123456Z" );
时区
通过特定地区、时区的人们使用的挂钟时间查看同一时刻。
ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
通过将时区名称附加在方括号中,以明智地扩展 ISO 8601 标准的格式生成字符串。
String output = zdt.toString() ;
看到这个code run live at IdeOne.com。
instant.toString(): 2020-01-23T12:34:56.123456Z
zdt.toString(): 2020-01-23T07:34:56.123456-05:00[美国/蒙特利尔]
Java 中的日期时间类型
关于java.time
java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.Date、Calendar 和 SimpleDateFormat。
要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310。
Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。
您可以直接与您的数据库交换 java.time 对象。使用符合JDBC 4.2 或更高版本的JDBC driver。不需要字符串,不需要java.sql.* 类。
从哪里获得 java.time 类?
ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如Interval、YearWeek、YearQuarter 和more。