我有一个简单的网页界面,以“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'中。我将其从东部时间转换为UTC,增加4小时。然后我尝试创建一个即时对象并解析字符串并获得纪元毫秒,但我获得的异常是:
“文字'2015-10-16T14:00z'无法解析”
使用这个新的Java 8 DateTime API,我认为这个任务很简单,我错过了什么?!
答案 0 :(得分:8)
Yasmani Llanes的answer基本上是正确的。我会解释。
LocalDateTime
!= UTC时刻 LocalDateTime
不是真正的日期时间,它与时间线无关。在将其调整到时区以确定时间线上的点之前,它没有任何实际意义。您的代码LocalDateTime utcTime
,您可以选择变量名称,表明您已经混合了一个" local"日期时间为UTC时刻。它不是。一个是模糊的想法,另一个是真实的。 (好吧,牛顿意义上的真实,而不是爱因斯坦的相对论意义;-))
因此,LocalDateTime::toString
的输出不是Instant.parse
方法所期望的完全形成的字符串。具体而言,它没有与offset-from-UTC和time zone相关的数据。上一段解释了为什么这是一个功能而不是错误。
你想要的是ZonedDateTime
,它基本上是Instant
(UTC时间轴上的一个时刻)加上ZoneId
(时区)。
ZonedDateTime
=Instant
+ZoneId
时区是UTC(小时和分钟)偏移量加上过去,现在和将来调整的一组规则和异常(例如Daylight Saving Time, DST)。
ZoneId
=偏离UTC +调整规则
在java.time框架中浏览LocalDateTime
是正确的,这是让它有点混乱的地方。从逻辑上讲,我们应该能够直接从输入String解析为ZonedDateTime
。但是由于调整规则,存在没有任何时区信息的输入字符串的问题可能对特定区域无效。例如,在春天的时候,我们会提前#34;随着夏令时,美国在凌晨2点前一小时跳了一小时,没有" 02:38"或" 20:54"在那一天。时钟从01:59.59.x跳到03:00:00.0。
我的理解是java.time框架希望通过传递给LocalDateTime
的{{1}}对象来处理这种调整,而不是在解析时让ZonedDateTime
直接处理它。两个步骤:(1)将字符串解析为ZonedDateTime
,(2)将LocalDateTime
对象和LocalDateTime
对象解析为ZoneId
。使用" 20:54"正确处理输入字符串那天,我们需要将其解析为ZonedDateTime
,然后让LocalDateTime
使用指定的时区进行调整(结果为" 03:54",我认为 - 阅读类doc以获取调整行为中使用的细节和逻辑。
因此,我们需要添加到您的代码中,调用ZonedDateTime
。使用您创建的ZonedDateTime
对象,我们需要为LocalDateTime
指定一个ZoneId
对象,以用于完成对ZonedDateTime
的转换。
您说输入字符串位于" Eastern Time"。我不敢告诉你没有这样的事情。 " EST"," EDT"以及其他这样的3-4个字母代码不是官方的,不是标准化的,也不是唯一的。您需要学习使用proper time zone names。也许你的意思是America/New_York
(注意下划线)或America/Montreal
或某些此类区域。我随意去纽约。
请注意我是如何更改您的变量名称的。命名变量对于清晰度和后期维护通常非常重要,但对于日期时间工作更是如此。
顺便说一句,通过字符串交换日期时间值数据的更好方法是使用ZonedDateTime
格式,例如2015-10-15T13:21:09Z
。这些格式包括UTC的偏移量,例如前一句中显示的Z
(祖鲁语,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
转换为时间线上的实际时刻。我们假设输入字符串代表使用纽约时区的ISO 8601中的wall-clock time。所以我们得到了纽约时区的Poughkeepsie对象。
// 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 );
您可以轻松调整到其他时区。我将任意显示ZoneId
以两种方式提供对比:在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
,该类会处理India time等异常所需的调整。
// Get a moment four hours later.
ZonedDateTime later = zdtNewYork.plusHours ( 4 ); // DST and other anomalies handled by ZDT when adding hours.
对于UTC时区,您可以采用两种方式之一。
ZoneOffset
的子类)中定义的方便常量。 Instant
中提取ZonedDateTime
。根据定义,Instant
始终为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。 Upshot:将来JDBC应该能够使用此处显示的java.time数据类型。在此之前,转换为ZoneId
对象。为您提供的便捷转换方法,例如java.sql.Timestamp
。
java.sql.Timestamp ts = java.sql.Timestamp.from( zdtNewYork.toInstant () );
答案 1 :(得分:0)
我相信您尝试解析的文本不是ggmap(Yak_base) +
stat_bin2d(
aes(x = Yak_dat[,2], y = Yak_dat[,1], colour = Yak_Ind, fill = Yak_Ind),
size=.10, bins = 60, alpha = 1/2, data = Yak_dat_fort
) +
geom_polygon(aes(x = Yak_coord[,1], y = Yak_coord[,2]), data = Yak_coord,
colour = 'black', fill = NA, alpha = 0.4,
size = 0.75
) +
labs(x = "Longitude", y = "Latitude") + ggtitle("Yakima Subbasin") +
scale_fill_discrete(
name = "Indicator for Snow", labels = c("No Snow","Snow")
)
应该是的格式。你错过了秒和纳秒。有效的Instant
类似于“2007-12-03T10:15:30.00Z”。
您应该在String
上使用toInstant
。