Java 将字符串转换为 Instant
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/50299639/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Converting string to Instant
提问by Venky
I am trying to covert datetime in string to instant using java 8 or utils package.
我正在尝试使用 java 8 或 utils 包将字符串中的日期时间转换为即时。
For eg.
例如。
String requestTime = "04:30 PM, Sat 5/12/2018";
to
到
Instant reqInstant should result in 2018-05-12T20:30:00.000Z
reqString is in America/Toronto timezone.
reqString 位于美国/多伦多时区。
This is what I tried
这是我试过的
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();
The above code results in "2018-05-12T23:30:00Z"
.
上面的代码导致"2018-05-12T23:30:00Z"
.
Any help is appreciated.
任何帮助表示赞赏。
采纳答案by Basil Bourque
tl;dr
tl;博士
- Fix your formatting pattern for unpadded month & day.
- Use only java.timeclasses, never the legacy classes.
- 修复未填充的月份和日期的格式模式。
- 只使用java.time类,不要使用遗留类。
Contrived example:
人为的例子:
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
2018-05-12T20:30:00Z
Use single-digit formatting pattern
使用个位数格式模式
You used MM
in your formatting pattern, to mean any single-digit value (months January-September) will appear with a padded leading zero.
您MM
在格式化模式中使用,表示任何一位数的值(一月至九月的月份)都将带有填充的前导零。
But your input lacks that padded leading zero. So use a single M
.
但是您的输入缺少填充的前导零。所以使用单个M
.
Ditto for day-of-month I expect: d
rather than dd
.
同样适用于我期望的月份:d
而不是dd
.
Use only java.time
只使用java.time
You are using troublesome flawed old date-time classes (Date
& SimpleDateFormat
) that were supplanted years ago by the java.timeclasses. The new classes entirely supplant the old. No need to mix the legacy and modern.
您正在使用多年前被java.time类取代的麻烦的有缺陷的旧日期时间类 ( Date
& SimpleDateFormat
) 。新班级完全取代了旧班级。无需混合传统和现代。
LocalDateTime
LocalDateTime
Parse as a LocalDateTime
because your input string lacks any indicator of time zoneor offset-from-UTC. Such a value is nota moment, is nota point on the timeline. It is only a set of potentialmoments along a range of about 26-27 hours.
解析为 aLocalDateTime
因为您的输入字符串缺少任何时区指示符或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
ldt.toString(): 2018-05-12T16:30
ZonedDateTime
ZonedDateTime
If you know for certain that input was intended to represent a moment using the wall-clock time used by the people of the Toronto Canada region, apply a ZoneId
to get a ZonedDateTime
object.
如果您确定该输入旨在使用加拿大多伦多地区的人们使用的挂钟时间来表示某个时刻,请应用 aZoneId
来获取ZonedDateTime
对象。
Assigning a time zone gives meaning to your unzoned LocalDateTime
. Now we have a moment, a point on the timeline.
分配时区赋予未分区的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]
zdt.toString(): 2018-05-12T16:30-04:00[美国/多伦多]
Instant
Instant
To see that same moment as UTC, extract an Instant
. Same moment, different wall-clock time.
要查看与UTC相同的时刻,请提取Instant
. 同一时刻,不同的挂钟时间。
Instant instant = zdt.toInstant() ;
instant.toString(): 2018-05-12T20:30:00Z
Instant.toString(): 2018-05-12T20:30:00Z
About java.time
关于java.time
The java.timeframework is built into Java 8 and later. These classes supplant the troublesome old legacydate-time classes such as java.util.Date
, Calendar
, & SimpleDateFormat
.
该java.time框架是建立在Java 8和更高版本。这些类取代了麻烦的旧的遗留日期时间类,例如java.util.Date
, Calendar
, & SimpleDateFormat
。
The Joda-Timeproject, now in maintenance mode, advises migration to the java.timeclasses.
现在处于维护模式的Joda-Time项目建议迁移到java.time类。
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
要了解更多信息,请参阅Oracle 教程。并在 Stack Overflow 上搜索许多示例和解释。规范是JSR 310。
You may exchange java.timeobjects directly with your database. Use a JDBC drivercompliant with JDBC 4.2or later. No need for strings, no need for java.sql.*
classes.
您可以直接与您的数据库交换java.time对象。使用符合JDBC 4.2或更高版本的JDBC 驱动程序。不需要字符串,不需要类。java.sql.*
Where to obtain the java.time classes?
从哪里获得 java.time 类?
- Java SE 8, Java SE 9, Java SE 10, and later
- Built-in.
- Part of the standard Java API with a bundled implementation.
- Java 9 adds some minor features and fixes.
- Java SE 6and Java SE 7
- Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
- Android
- Later versions of Android bundle implementations of the java.time classes.
- For earlier Android (<26), the ThreeTenABPproject adapts ThreeTen-Backport(mentioned above). See How to use ThreeTenABP….
- Java SE 8、Java SE 9、Java SE 10及更高版本
- 内置。
- 具有捆绑实现的标准 Java API 的一部分。
- Java 9 添加了一些小功能和修复。
- Java SE 6和Java SE 7
- 多的java.time功能后移植到Java 6和7在ThreeTen-反向移植。
- 安卓
- java.time 类的更高版本的 Android 捆绑实现。
- 对于早期的 Android(<26),ThreeTenABP项目采用了ThreeTen-Backport(上面提到过)。请参阅如何使用ThreeTenABP ...。
The ThreeTen-Extraproject extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval
, YearWeek
, YearQuarter
, and more.
该ThreeTen-额外项目与其他类扩展java.time。该项目是未来可能添加到 java.time 的试验场。你可能在这里找到一些有用的类,比如Interval
,YearWeek
,YearQuarter
,和更多。
回答by Vadim
It seems like Time Zone in your computer(server) is US Pacific DST (GMT-7), but you expect to have result for US Eastern DST (GMT-4).
您的计算机(服务器)中的时区似乎是美国太平洋夏令时 (GMT-7),但您希望得到美国东部夏令时 (GMT-4) 的结果。
Instant.toString() returns UTC (GMT+0) DateTime in ISO-8601 format. ('Z' at the end means UTC).
Instant.toString() 以 ISO-8601 格式返回 UTC (GMT+0) DateTime。(末尾的“Z”表示 UTC)。
SimpleDateFormat threats DateTime String in default Time Zone of computer when it is not specified. And your input does not specify time zone.
SimpleDateFormat 威胁计算机默认时区中的 DateTime 字符串(未指定时)。并且您的输入未指定时区。
So, you need to do something about in what time zone your input is.
因此,您需要对输入的时区进行处理。
PS. on mine machine in Eastern DST your code gives me result exactly as you expected.
附注。在东部夏令时的我的机器上,您的代码完全符合您的预期。