我有一个简单的Web界面,其日期和时间的格式为“ 2009/10/09 11:00”或“ yyyy / MM / dd HH:mm”。时间(从用户的角度来看)为东部时间。
我希望能够使用此字符串,将其转换为UTC时间戳,因此我可以采用此时间戳,并根据指定的时间查询我们的NoSQL数据库。
我的代码如下:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm");
LocalDateTime dateTime = LocalDateTime.parse(startSearchTime, formatter);
System.out.println(dateTime);
LocalDateTime utcTime = dateTime.plusHours(4);
Instant instant = Instant.parse(utcTime.toString());
System.out.println(instant.toEpochMilli());
我从UI获取字符串并将其存储在“ startSearchTime”中。我通过添加4小时将其从东部时间转换为UTC。然后,我尝试创建一个即时对象并解析该字符串并获得纪元毫秒,但我得到的异常是:
“无法解析文本'2015-10-16T14:00z'”
有了这个新的Java 8 DateTime API,我认为这个任务会很容易,我还缺少什么?
Yasmani Llanes的回答基本上是正确的。我会讲解。
LocalDateTime
!= UTC时刻ALocalDateTime
不是真实的日期时间,它与时间线无关。除非您将其调整到一个时区以确定时间线上的一点(即时刻),否则它没有真正的意义。您的代码(LocalDateTime utcTime
带有变量名的选择)表明您已将“本地”日期时间与UTC时刻相混淆。它不是。一个是模糊的想法,另一个是真实的。(嗯,在牛顿意义上是真实的,而不是在爱因斯坦相对论意义上;;)
因此,的输出LocalDateTime::toString
不是该Instant.parse
方法所期望的完整字符串。具体来说,它没有与UTC偏移量或时区有关的数据。上一段解释了为什么这是功能而不是bug。
您想要的ZonedDateTime
基本上是一个Instant
(UTC时间轴上的时刻)加上一个ZoneId
(时区)。
ZonedDateTime
=Instant
+ZoneId
时区是相对于UTC的偏移量(小时和分钟),以及一组针对过去,现在和将来的调整的规则和异常情况(例如,夏时制DST)。
ZoneId
=从UTC偏移+调整规则
您是正确的LocalDateTime
在java.time框架中进行遍历的地方,这有点令人困惑。从逻辑上讲,我们应该能够直接将输入String解析为ZonedDateTime
。但是存在一个问题,即由于调整规则,没有任何时区信息的输入字符串可能不适用于特定的时区。例如,在春季,当我们采用夏时制“提前”时,在美国,凌晨2点向前跳一个小时,则当天没有“ 02:38”或“ 20:54” 。时钟从01:59.59.x跳到03:00:00.0。
我的理解是java.time框架希望通过LocalDateTime
传递给的对象来处理此调整,ZonedDateTime
而不是ZonedDateTime
在解析时直接处理它。分两个步骤:(1)将字符串解析为LocalDateTime
,(2)将LocalDateTime
对象和ZoneId
对象馈给ZonedDateTime
。为了正确处理当天输入为“ 20:54”的字符串,我们需要将其解析为LocalDateTime
,然后要求ZonedDateTime
使用指定的时区进行调整(结果是“ 03:54”,我认为-请阅读课程doc,了解调整行为中使用的详细信息和逻辑)。
因此,我们需要添加到您的代码中,调用ZonedDateTime
。使用LocalDateTime
您创建的对象,我们需要指定一个ZoneId
对象,ZonedDateTime
以用于完成对的转换ZonedDateTime
。
您说输入的字符串是在“东部时间”。恐怕告诉你没有这样的事情。“ EST”,“ EDT”和其他此类3-4个字母代码不是官方的,未标准化的并且也不是唯一的。您需要学习使用正确的时区名称。也许您的意思是America/New_York
(请注意下划线)或America/Montreal
此类区域。我会随便去纽约。
注意我如何更改您的变量名。命名变量通常对于清晰度和以后的维护非常重要,但对于日期时间工作则更为重要。
顺便说一句,通过字符串交换日期时间值的数据的更好方法是使用ISO 8601格式,例如2015-10-15T13:21:09Z
。这些格式包括UTC偏移量,例如Z
前一句中所示的(Zulu,UTC)。java.time框架通过在括号中添加时区名称来明智地扩展了ISO 8601格式。传递没有偏移量或时区信息的日期时间字符串会带来麻烦。
这是Java 8中的一些示例代码。首先,我们将字符串解析为一个LocalDateTime
对象。
// Parse input string into a LocalDateTime object.
String input = "2009/10/09 11:00";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern ( "yyyy/MM/dd HH:mm" );
LocalDateTime localDateTime = LocalDateTime.parse ( input , formatter );
LocalDateTime
通过分配时区,将非晶态转换为时间线上的实际时刻。我们假设输入字符串代表的挂钟时间在波基普西它使用纽约时区。因此,我们获得了ZoneId
纽约时区的一个对象。
// Specify the time zone we expect is implied for this input string.
ZoneId zoneId = ZoneId.of ( "America/New_York" );
ZonedDateTime zdtNewYork = ZonedDateTime.of ( localDateTime , zoneId );
您可以轻松调整到其他时区。我将任意显示印度时间以两种方式形成对比:在UTC之前而不是在UTC之前,并且其偏移量不是整小时(+05:30
)。
// For fun, adjust into India time, five and a half hours ahead of UTC.
ZonedDateTime zdtKolkata = zdtNewYork.withZoneSameInstant ( ZoneId.of ( "Asia/Kolkata" ) );
我们可以进行日期时间计算,例如增加四个小时。因为我们有一个ZonedDateTime
,所以该类处理诸如夏令时之类的异常所需的调整。
// Get a moment four hours later.
ZonedDateTime later = zdtNewYork.plusHours ( 4 ); // DST and other anomalies handled by ZDT when adding hours.
对于UTC时区,您可以选择两种方式之一。
ZoneOffset
(的子类ZoneId
)。Instant
从内ZonedDateTime
。根据Instant
定义,An始终使用UTC。两种方式都代表时间轴上的同一时刻。但是请注意下面的输出中,每种默认情况下在各自的toString
实现中如何使用不同的格式。
// To get the same moment in UTC time zone, either adjust time zone or extract Instant.
ZonedDateTime zdtUtc = zdtNewYork.withZoneSameInstant ( ZoneOffset.UTC );
Instant instant = zdtNewYork.toInstant ();
转储到控制台。
System.out.println ( "input: " + input );
System.out.println ( "localDateTime: " + localDateTime );
System.out.println ( "zdtNewYork: " + zdtNewYork );
System.out.println ( "zdtKolkata: " + zdtKolkata );
System.out.println ( "zdtUtc: " + zdtUtc );
System.out.println ( "instant: " + instant );
System.out.println ( "later: " + later );
运行时。
input: 2009/10/09 11:00
localDateTime: 2009-10-09T11:00
zdtNewYork: 2009-10-09T11:00-04:00[America/New_York]
zdtKolkata: 2009-10-09T20:30+05:30[Asia/Kolkata]
zdtUtc: 2009-10-09T15:00Z
instant: 2009-10-09T15:00:00Z
later: 2009-10-09T15:00-04:00[America/New_York]
至于查询数据库,请搜索StackOverflow,因为已经对其进行了详尽的处理。总结:将来,JDBC应该能够使用此处显示的java.time数据类型。在此之前,请转换为java.sql.Timestamp
对象。为您提供的便捷转换方法,例如java.sql.Timestamp.from( Instant instant )
。
java.sql.Timestamp ts = java.sql.Timestamp.from( zdtNewYork.toInstant () );
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句