如何将时间戳字符串转换为纪元时间? [英] How to convert timestamp string to epoch time?

查看:474
本文介绍了如何将时间戳字符串转换为纪元时间?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的格式时间戳 2017-18-08 11:45:30.345

我想把它转换为纪元时间,所以我在下面做:

I have time stamp in format 2017-18-08 11:45:30.345.
I want to convert it to epoch time, so I am doing below:

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:无法解析文本'2017-18-08 11:45:30.345':无法从TemporalAccessor获取ZonedDateTime

java.time.format.DateTimeParseException: Text '2017-18-08 11:45:30.345' could not be parsed: Unable to obtain ZonedDateTime from TemporalAccessor

我也尝试了不同的格式但仍然出错。

I also tried different formats but still getting errors.

推荐答案

注意最初问题的输入 2017-18-08 12:60:30.345 (含 60 在分钟字段中),然后它已被编辑时间 12:60 更改为 11:45 ),但我决定保留此答案讨论原始输入( 12:60 ),因为它也适用于编辑版本( 11:45 )。

Note: originally the question had the input 2017-18-08 12:60:30.345 (with 60 in the minutes field), then it was edited (the time changed from 12:60 to 11:45), but I decided to keep this answer discussing about the original input (12:60), as it also works for the edited version (11:45).

ZonedDateTime 需要时区或偏移,但输入字符串没有它(它只有日期和时间)。

ZonedDateTime needs a timezone or offset, but the input String doesn't have it (it has only date and time).

输入中还有另一个细节:

There are also another details in the input:


  • 分钟值 60 ,不接受:有效值为从0到59(实际上有一种方法可以接受这个,请参阅Lenient解析以下)

  • hh clock-hour-am-pm 字段,所以它还需要完全解决AM / PM指示符。如你没有,你应该使用 HH 模式

  • the minute value is 60, which is not accepted: the valid values are from 0 to 59 (actually there's a way to accept this, see "Lenient parsing" below)
  • the hh is the clock-hour-of-am-pm field, so it also needs the AM/PM designator to be fully resolved. As you don't have it, you should use the HH pattern instead

所以模式必须是 yyyy-dd-MM HH:mm:ss.SSS ,输入不能 60 作为分钟值(除非你使用宽松解析,我将在下面解释)并且你不能直接将它解析为 ZonedDateTime ,因为它没有时区/偏移指示符。

So the pattern must be yyyy-dd-MM HH:mm:ss.SSS, the input can't have 60 as the minutes value (unless you use lenient parsing, which I'll explain below) and you can't direclty parse it to a ZonedDateTime because it doesn't have a timezone/offset designator.

一种方法是将其解析为 LocalDateTime 然后定义在哪个时区/抵消这个日期是。在下面的示例中,我假设它位于 UTC

One alternative is to parse it to a LocalDateTime and then define in which timezone/offset this date is. In the example below, I'm assuming it's in 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

1503061170345

相当于 2017-18-08 12:59:30.345 UTC

如果你想在另一个时区中使用日期,你可以使用 ZoneId 类:

If you want the date in another timezone, you can use the ZoneId class:

// get the LocalDateTime in some timezone
ZonedDateTime z = dt.atZone(ZoneId.of("Europe/London"));
System.out.println(z.toInstant().toEpochMilli());

输出为:


1503057570345

1503057570345

请注意结果不同,因为相同的本地日期/时间代表不同的每个时区的即时(在世界各地,本地日期/时间 2017-18-08 12:59:30.345 发生在另一个瞬间)。

Note that the result is different, because the same local date/time represents a different Instant in each timezone (in each part of the world, the local date/time 2017-18-08 12:59:30.345 happened in a different instant).

另请注意,API使用 IANA时区名称(始终采用地区/城市格式,如 America / Sao_Paulo 欧/柏林)。
避免使用3个字母的缩写(例如 CST PST ),因为它们

Also note that API uses IANA timezones names (always in the format Region/City, like America/Sao_Paulo or Europe/Berlin). Avoid using the 3-letter abbreviations (like CST or PST) because they are ambiguous and not standard.

您可以获得可用时区列表(和通过调用 ZoneId.getAvailableZoneIds()来选择最适合您系统的那个。

You can get a list of available timezones (and choose the one that fits best your system) by calling ZoneId.getAvailableZoneIds().

您也可以使用系统的默认时区 ZoneId.systemDefault(),但即使在运行时也可以在不事先通知的情况下进行更改,因此最好明确使用特定的一个。

You can also use the system's default timezone with ZoneId.systemDefault(), but this can be changed without notice, even at runtime, so it's better to explicity use a specific one.

还可以选择将 LocalDateTime 转换为抵消(例如 -05:00 +03:00 ):

There's also the option to convert the LocalDateTime to an offset (like -05:00 or +03:00):

// get the LocalDateTime in +03:00 offset
System.out.println(dt.toInstant(ZoneOffset.ofHours(3)).toEpochMilli());

输出将等于偏移 +中的本地日期/时间03:00 (比UTC早3小时):

The output will be equivalent to the local date/time in the offset +03:00 (3 hours ahead of UTC):


1503050370345

1503050370345






宽松解析



作为@MenoHochschild在评论中提醒我,你可以使用宽松的解析来接受分钟字段中的 60 (使用 java.time.format.ResolverStyle 类):


Lenient parsing

As @MenoHochschild reminded me in the comments, you can use lenient parsing to accept 60 in the minutes field (using the java.time.format.ResolverStyle class):

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 将是:

In this case, 60 minutes are adjusted to the next hour, and the LocalDateTime will be:


2017-08-18T 13:00 :30.345






夏令时



如果您决定使用UTC或固定偏移量(使用 ZoneOffset 类),您可以忽略此部分。


Daylight Saving Time

If you decide to use UTC or a fixed offset (using ZoneOffset class), you can ignore this section.

但是如果您决定使用时区( ZoneId 类),您还必须照顾夏令时(夏令时)问题。我将使用我居住的时区作为示例( America / Sao_Paulo )。

But if you decide to use a timezone (with ZoneId class), you must also take care of DST (Daylight Saving Time) issues. I'm gonna use the timezone I live in as example (America/Sao_Paulo).

在圣保罗, DST于2017年10月15日 th 开始:在午夜,时钟从午夜到凌晨1点向前1小时前进。因此,此时区内不存在00:00至00:59之间的所有当地时间。如果我在此时间间隔内创建了本地日期,则会将其调整为下一个有效时间:

In São Paulo, DST starts at October 15th 2017: at midnight, clocks shift 1 hour forward from midnight to 1 AM. So all local times between 00:00 and 00:59 don't exist in this timezone. If I create a local date in this interval, it's adjusted to the next valid moment:

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点从<午夜到晚上的 17 即可。所以从23:00到23:59的所有当地时间都存在两次(在夏令时和非DST中),你必须决定你想要哪一个:

When DST ends: in February 18th 2018 at midnight, clocks shift back 1 hour, from midnight to 23 PM of 17th. So all local times from 23:00 to 23:59 exist twice (in DST and in non-DST), and you must decide which one you want:

// 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的价值。

Note that the dates before and after DST ends have different offsets (-02:00 and -03:00). This affects the value of epochMilli.

您必须检查DST何时开始并以您选择的时区结束,并相应地检查调整。

You must check when DST starts and ends in the timezone you choose and check the adjustments accordingly.

这篇关于如何将时间戳字符串转换为纪元时间?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆