我正在尝试使用 Java 8 或实用程序包将字符串中的日期时间转换为 Instant 实例。
例如,
String requestTime = "04:30 PM, Sat 5/12/2018";
到
Instant reqInstant should result in 2018-05-12T20:30:00.000Z
reqString 在 America/Toronto 中时区。
这是我尝试过的
String strReqDelTime = "04:30 PM, Sat 5/12/2018";
Date date = new SimpleDateFormat("hh:mm a, EEE MM/dd/yyyy").parse(requestTime);
Instant reqInstant = date.toInstant();
以上代码生成“2018-05-12T23:30:00Z”。
我该怎么做?
最佳答案
tl;dr
- 修复未填充的月份和日期的格式设置模式。
- 仅使用 java.time 类,绝不使用遗留类。
人为的例子:
LocalDateTime.parse( // Parse as an indeterminate `LocalDate`, devoid of time zone or offset-from-UTC. NOT a moment, NOT a point on the timeline.
"04:30 PM, Sat 5/12/2018" , // This input uses a poor choice of format. Whenever possible, use standard ISO 8601 formats when exchanging date-time values as text. Conveniently, the java.time classes use the standard formats by default when parsing/generating strings.
DateTimeFormatter.ofPattern("hh:mm a, EEE M/d/uuuu", Locale.US) // Use single-character `M` & `d` when the number lacks a leading padded zero for single-digit values.
) // Returns a `LocalDateTime` object.
.atZone( // Apply a zone to that unzoned `LocalDateTime`, giving it meaning, determining a point on the timeline.
ZoneId.of("America/Toronto") // Always specify a proper time zone with `Contintent/Region` format, never a 3-4 letter pseudo-zone such as `PST`, `CST`, or `IST`.
) // Returns a `ZonedDateTime`. `toString` → 2018-05-12T16:30-04:00[America/Toronto].
.toInstant() // Extract a `Instant` object, always in UTC by definition.
.toString() // Generate a String in standard ISO 8601 format representing the value within this `Instant` object. Note that this string is *generated*, not *contained*.
2018-05-12T20:30:00Z
使用个位数格式化模式
您在格式化模式中使用了 MM
,这意味着任何一位数值(1 月至 9 月)都将以填充的前导零显示。
但是您的输入缺少填充的前导零。所以使用单个 M
。
同上,我期望的日期是:d
而不是 dd
。
仅使用java.time
您正在使用多年前被 java.time 类取代的麻烦的有缺陷的旧日期时间类(Date
和 SimpleDateFormat
) .新类(class)完全取代旧类(class)。没有必要将传统和现代混为一谈。
本地日期时间
解析为 LocalDateTime
因为您的输入字符串缺少 time zone 的任何指示符或 offset-from-UTC .这样的值不是一个时刻,不是时间轴上的一个点。这只是大约 26-27 小时范围内的一组潜在时刻。
String input = "04:30 PM, Sat 5/12/2018";
DateTimeFormatter f = DateTimeFormatter.ofPattern("hh:mm a, EEE M/d/uuuu", Locale.US); // Specify locale to determine human language and cultural norms used in translating that input string.
LocalDateTime ldt = LocalDateTime.parse(input, f);
ldt.toString(): 2018-05-12T16:30
ZonedDateTime
如果您确定输入旨在表示使用加拿大多伦多地区人们使用的挂钟时间的时刻,请应用 ZoneId
以获得 ZonedDateTime
对象。
分配时区为未分区的 LocalDateTime
赋予意义。现在我们有时间,时间轴上的一个点。
ZoneId z = ZoneId.of("America/Toronto");
ZonedDateTime zdt = ldt.atZone(z); // Give meaning to that `LocalDateTime` by assigning the context of a particular time zone. Now we have a moment, a point on the timeline.
zdt.toString(): 2018-05-12T16:30-04:00[America/Toronto]
即时
看到与 UTC 相同的时刻, 提取一个 Instant
.同一时刻,不同的挂钟时间。
Instant instant = zdt.toInstant();
instant.toString(): 2018-05-12T20:30:00Z
关于java.time
java.time框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧类 legacy日期时间类,例如 java.util.Date
, Calendar
, & SimpleDateFormat
.
Joda-Time项目,现在在maintenance mode , 建议迁移到 java.time类。
要了解更多信息,请参阅 Oracle Tutorial .并在 Stack Overflow 中搜索许多示例和解释。规范为 JSR 310 .
您可以直接与您的数据库交换java.time 对象。使用JDBC driver符合 JDBC 4.2或以后。不需要字符串或 java.sql.*
类。
我们在哪里可以获得 java.time 类?
- Java SE 8 , Java SE 9 , Java SE 10 , 后来
- 内置。
- 带有捆绑实现的标准 Java API 的一部分。
- Java 9 添加了一些次要功能和修复。
- Java SE 6和 Java SE 7
- 许多 java.time 功能在 ThreeTen-Backport 中被反向移植到 Java 6 和 7 .
- Android
- 更高版本的 Android 捆绑了 java.time 类的实现。
- 对于早期的 Android (<26),ThreeTenABP项目适应 ThreeTen-Backport(如上所述)。参见 How to use ThreeTenABP… .
ThreeTen-Extra项目用附加类扩展 java.time。该项目是 future 可能添加到 java.time 的试验场。您可能会在这里找到一些有用的类,例如 Interval
, YearWeek
, YearQuarter
, 和 more .
关于java - 将字符串转换为 'Instant',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50299639/