我有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());
我收到以下错误:
java.time.format.DateTimeParseException:Text' 2017-18-08 11:45:30.345'无法解析:无法从TemporalAccessor获取ZonedDateTime
我也尝试了不同的格式但仍然出错。
答案 0 :(得分:7)
注意:originally问题的输入为2017-18-08 12:60:30.345
(分钟字段中为60
),然后是it was edited( 时间已从12:60
更改为11:45
),但我决定保留此答案,讨论原始输入(12:60
),因为它也适用于已编辑的版本(11:45
)。
ZonedDateTime
需要时区或偏移量,但输入String
没有它(它只有日期和时间)。
输入中还有另一个细节:
60
,不接受:有效值为0到59(实际上有一种接受方法,请参阅下面的“Lenient parsing”)< / LI>
hh
是clock-hour-of-am-pm field,因此它还需要完全解析AM / PM指示符。如您没有,则应使用HH
模式所以模式必须是yyyy-dd-MM HH:mm:ss.SSS
,输入不能有60
作为分钟值(除非你使用宽松解析,我将在下面解释)并且你不能直接解析它到ZonedDateTime
,因为它没有时区/偏移指示符。
另一种方法是将其解析为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());
这将输出:
1503061170345
这相当于UTC中的2017-18-08 12:59:30.345
。
如果您希望在另一个时区中使用日期,则可以使用ZoneId
类:
// get the LocalDateTime in some timezone
ZonedDateTime z = dt.atZone(ZoneId.of("Europe/London"));
System.out.println(z.toInstant().toEpochMilli());
输出结果为:
1503057570345
请注意,结果不同,因为相同的本地日期/时间代表每个时区中不同的Instant
(在世界的每个部分,本地日期/时间2017-18-08 12:59:30.345
发生在不同的时区时刻)。
另请注意,API使用IANA timezones names(始终采用Region/City
格式,如America/Sao_Paulo
或Europe/Berlin
。
避免使用3个字母的缩写(例如CST
或PST
),因为它们是ambiguous and not standard。
您可以致电ZoneId.getAvailableZoneIds()
获取可用时区列表(并选择最适合您系统的时区)。
您也可以将系统的默认时区与ZoneId.systemDefault()
一起使用,但即使在运行时也可以在不事先通知的情况下进行更改,因此最好明确指出使用特定的时区。
还可以选择将LocalDateTime
转换为offset(例如-05:00
或+03:00
):
// get the LocalDateTime in +03:00 offset
System.out.println(dt.toInstant(ZoneOffset.ofHours(3)).toEpochMilli());
输出将等于偏移+03:00
中的本地日期/时间(比UTC早3小时):
1503050370345
作为@MenoHochschild reminded me in the comments,您可以使用宽松解析来接受分钟字段中的60
(使用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);
在这种情况下,将60分钟调整到下一个小时,LocalDateTime
将是:
2017-08-18T的 13:00 强>:30.345
如果您决定使用UTC或固定偏移量(使用ZoneOffset
类),则可以忽略此部分。
但是如果你决定使用时区(ZoneId
类),你还必须处理DST (Daylight Saving Time)个问题。我将以我所居住的时区为例(America/Sao_Paulo
)。
在圣保罗,DST于2017年10月15日 th 开始:在午夜,时钟从午夜向凌晨1点移动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]
当夏令时结束时:2018年2月18日 th 午夜,时钟从<午夜到晚上23点<强>返回 1小时 17 th < / SUP> 即可。因此,从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]
请注意,DST结束前后的日期具有不同的偏移量(-02:00
和-03:00
)。这会影响epochMilli的价值。
您必须检查DST何时开始并以您选择的时区结束,并相应地检查调整。
答案 1 :(得分:2)
更正了有关yyyy-dd-MM的代码。微小的值也可能是1-59而不是60.你提供了60.这是解决问题的另一种简单方法。只需使用DateFormat类。
String timeDateStr = "2017-18-08 12:59:30.345";
DateFormat df = new SimpleDateFormat("yyyy-dd-MM hh:mm:ss.SSS", Locale.ENGLISH);
try {
Date d = df.parse(timeDateStr);
System.out.println(d.toInstant().toEpochMilli());
} catch (ParseException e) {
e.printStackTrace();
}
答案 2 :(得分:0)
我在nagendra547的回答中做了一些改变
请访问以下代码: -
String timeDateStr = "2017-18-08 12:59:30.345";
DateFormat df = new SimpleDateFormat("yyyy-dd-mm hh:mm:ss.SSS", Locale.ENGLISH);
try {
Date d = df.parse(timeDateStr);
System.out.println(d.toInstant().toEpochMilli());
} catch (ParseException e) {
e.printStackTrace();
}
答案 3 :(得分:0)
您的代码将因以下3个原因而失败。
2017-18-08 12:60:30.345
)与您使用的格式化程序不匹配。它应该是 yyyy-MM-dd HH:mm:ss.SSS 而不是 yyyy-dd-MM hh:mm:ss.SSS ZonedDateTime
运行。因此,您需要先创建LocalDateTime
,然后将ZoneId
传递给它。代码应如下所示:
String timeDateStr = "2017-18-08 12:59:30.345";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-dd-MM HH:mm:ss.SSS");
LocalDateTime date = LocalDateTime.parse(timeDateStr, dtf);
ZonedDateTime zdt = date.atZone(ZoneId.of("Europe/London"));
System.out.println(zdt.toInstant().toEpochMilli());