Use*_*337 4 java timestamp epoch datetime-parsing java-time
我的格式有时间戳2017-18-08 11:45:30.345.
我想将它转换为纪元时间,所以我在下面做:
String timeDateStr = "2017-18-08 11:45:30.345";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-dd-MM HH:mm:ss.SSS");
ZonedDateTime zdt = ZonedDateTime.parse(timeDateStr, dtf);
System.out.println(zdt.toInstant().toEpochMilli());
Run Code Online (Sandbox Code Playgroud)
我收到以下错误:
java.time.format.DateTimeParseException:无法解析文本'2017-18-08 11:45:30.345':无法从TemporalAccessor获取ZonedDateTime
我也尝试过不同的格式,但仍然会出错.
小智 7
注意:最初问题有输入2017-18-08 12:60:30.345(60在分钟字段中),然后它被编辑(时间从更改12:60为11:45),但我决定保持这个答案讨论原始输入(12:60),因为它也适用于编辑版本(11:45).
ZonedDateTime需要时区或偏移量,但输入String没有它(它只有日期和时间).
输入中还有另一个细节:
60,不接受:有效值从0到59(实际上有一种方法可以接受这个,请参阅下面的"宽容解析")hh是mid-hour-am-pm字段,因此它还需要完全解析AM/PM指示符.由于您没有它,您应该使用该HH模式所以模式必须是yyyy-dd-MM HH:mm:ss.SSS,输入不能60作为分钟值(除非你使用宽松解析,我将在下面解释)并且你不能直接解析它到a,ZonedDateTime因为它没有时区/偏移代号.
一种替代方法是将其解析为a LocalDateTime,然后定义此日期所在的时区/偏移量.在下面的例子中,我假设它是UTC:
// change 60 minutes to 59 (otherwise it doesn't work)
String timeDateStr = "2017-18-08 12:59:30.345";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-dd-MM HH:mm:ss.SSS");
// parse to LocalDateTime
LocalDateTime dt = LocalDateTime.parse(timeDateStr, dtf);
// assume the LocalDateTime is in UTC
Instant instant = dt.toInstant(ZoneOffset.UTC);
System.out.println(instant.toEpochMilli());
Run Code Online (Sandbox Code Playgroud)
这将输出:
1503061170345
这是相当于2017-18-08 12:59:30.345在UTC.
如果您希望在另一个时区中使用该日期,则可以使用ZoneId该类:
// get the LocalDateTime in some timezone
ZonedDateTime z = dt.atZone(ZoneId.of("Europe/London"));
System.out.println(z.toInstant().toEpochMilli());
Run Code Online (Sandbox Code Playgroud)
输出是:
1503057570345
请注意,结果是不同的,因为相同的本地日期/时间Instant在每个时区中表示不同(在世界的每个部分中,本地日期/时间2017-18-08 12:59:30.345发生在不同的时刻).
另请注意,API使用IANA时区名称(始终采用格式Region/City,如America/Sao_Paulo或Europe/Berlin).避免使用3个字母的缩写(如CST或PST),因为它们不明确且不标准.
您可以通过调用获取可用时区列表(并选择最适合您系统的时区)ZoneId.getAvailableZoneIds().
您也可以使用系统默认的时区有ZoneId.systemDefault(),但这随时都可能被改变,甚至在运行,所以最好是明确地使用特定的一个.
还可以选择将其转换LocalDateTime为偏移量(如-05:00或+03:00):
// get the LocalDateTime in +03:00 offset
System.out.println(dt.toInstant(ZoneOffset.ofHours(3)).toEpochMilli());
Run Code Online (Sandbox Code Playgroud)
输出将等于偏移中的本地日期/时间+03:00(比UTC早3小时):
1503050370345
正如@MenoHochschild在评论中提醒我的那样,你可以使用lenient parsing 60在minutes字段中接受(使用java.time.format.ResolverStyle类):
String timeDateStr = "2017-18-08 12:60:30.345";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-dd-MM HH:mm:ss.SSS")
// use lenient parsing
.withResolverStyle(ResolverStyle.LENIENT);
// parse to LocalDateTime
LocalDateTime dt = LocalDateTime.parse(timeDateStr, dtf);
Run Code Online (Sandbox Code Playgroud)
在这种情况下,60分钟调整到下一个小时,LocalDateTime将是:
2017-08-18T 13 : 00 :30.345
如果您决定使用UTC或固定偏移量(使用ZoneOffset类),则可以忽略此部分.
但是,如果您决定使用时区(带ZoneId课程),则还必须处理DST(夏令时)问题.我将使用我居住的时区作为示例(America/Sao_Paulo).
在圣保罗,DST开始于10月15日日 2017年:在午夜,时钟对应的小时轮班着从午夜到凌晨1点.因此,此时区内不存在00:00至00:59之间的所有当地时间.如果我在此间隔中创建本地日期,则会将其调整为下一个有效时刻:
ZoneId zone = ZoneId.of("America/Sao_Paulo");
// October 15th 2017 at midnight, DST starts in Sao Paulo
LocalDateTime d = LocalDateTime.of(2017, 10, 15, 0, 0, 0, 0);
ZonedDateTime z = d.atZone(zone);
System.out.println(z);// adjusted to 2017-10-15T01:00-02:00[America/Sao_Paulo]
Run Code Online (Sandbox Code Playgroud)
当夏令时结束:在2月18日日午夜2018,时钟移回 1小时后,从午夜到23 PM的17 个.因此,从23:00到23:59的所有当地时间都存在两次(在DST和非DST中),您必须决定您想要哪一个:
// February 18th 2018 at midnight, DST ends in Sao Paulo
// local times from 23:00 to 23:59 at 17th exist twice
LocalDateTime d = LocalDateTime.of(2018, 2, 17, 23, 0, 0, 0);
// by default, it gets the offset before DST ends
ZonedDateTime beforeDST = d.atZone(zone);
System.out.println(beforeDST); // before DST end: 2018-02-17T23:00-02:00[America/Sao_Paulo]
// get the offset after DST ends
ZonedDateTime afterDST = beforeDST.withLaterOffsetAtOverlap();
System.out.println(afterDST); // after DST end: 2018-02-17T23:00-03:00[America/Sao_Paulo]
Run Code Online (Sandbox Code Playgroud)
请注意,DST结束前后的日期具有不同的偏移量(-02:00和-03:00).这会影响epochMilli的价值.
您必须检查DST何时开始并以您选择的时区结束,并相应地检查调整.