如何从LocalDate和LocalDateTime中提取纪元?


102

如何LongLocalDateTime或的实例提取纪元值LocalDate?我已经尝试了以下方法,但是它给了我其他结果:

LocalDateTime time = LocalDateTime.parse("04.02.2014  19:51:01", DateTimeFormatter.ofPattern("dd.MM.yyyy  HH:mm:ss"));
System.out.println(time.getLong(ChronoField.SECOND_OF_DAY)); // gives 71461
System.out.println(time.getLong(ChronoField.EPOCH_DAY)); // gives 16105

我想要的只是1391539861本地datetime 的值"04.02.2014 19:51:01"。我的时区是Europe/Oslo夏令时的UTC + 1。


请解释您的预期电话号码1396468261。我没有进行时区校正:1391543461(请参见我的答复中的编辑)。相差57天!
Meno Hochschild 2014年

@MenoHochschild我已使用时区信息更新了我的问题,并将GTM的实际值更正为​​本地时间。LocalDateTime除了手动计算之外,还有没有其他更容易获得时代的方法?

从暂停中回来,请参阅我的更新。
Meno Hochschild 2014年

Answers:


147

这些类LocalDateLocalDateTime不包含有关时区time offset的信息,而自从纪元以来的秒数如果没有这些信息将是模棱两可的。但是,这些对象有几种通过传递ZoneId实例将它们转换为具有时区的日期/时间对象的方法。

本地日期

LocalDate date = ...;
ZoneId zoneId = ZoneId.systemDefault(); // or: ZoneId.of("Europe/Oslo");
long epoch = date.atStartOfDay(zoneId).toEpochSecond();

LocalDateTime

LocalDateTime time = ...;
ZoneId zoneId = ZoneId.systemDefault(); // or: ZoneId.of("Europe/Oslo");
long epoch = time.atZone(zoneId).toEpochSecond();

2
是否可以避免使用ZoneId或与自定义的,恒定的ZoneId实例(为+0,表示GMT)一起使用?我之所以这样问,是因为我希望所有计算都可以归一化。另外,我该如何做相反:从纪元时间转换为LocalDate / LocalDateTime(也没有ZoneId或使用GMT)?
Android开发人员

2
没关系。找到了:ZoneId.ofOffset("UTC", ZoneOffset.ofHours(0))
android开发人员

7
一个更简单的方法仅long epoch = time.toEpochSecond(ZoneOffset.UTC)适用于UTC案例,或者您已经知道时区的位置,或者long epoch = time.toEpochSecond(ZoneId.systemDefault());您想走那条路线。
马库斯

这听起来可能很荒谬,但如何从纪元转换回LocalDate,
LocalTime

没关系,我想我找到了; Instant.ofEpochMilli(responseTime).atZone(ZoneId.systemDefault()).toLocalTime()
塞缪尔·奥维诺

27

“自unix纪元以来的Millis”代表一个瞬间,因此您应该使用Instant类:

private long toEpochMilli(LocalDateTime localDateTime)
{
  return localDateTime.atZone(ZoneId.systemDefault())
    .toInstant().toEpochMilli();
}

它使用不正确,ZoneId.systemDefault()因为Unix纪元是指UTC
ACV

10

您需要进行的转换需要与UTC / Greewich的偏移量或时区。

如果你有一个偏移,有一个专门的方法LocalDateTime此任务:

long epochSec = localDateTime.toEpochSecond(zoneOffset);

如果你只有一个ZoneId,那么你可以得到ZoneOffset来自ZoneId

ZoneOffset zoneOffset = ZoneId.of("Europe/Oslo").getRules().getOffset(ldt);

但是您可能会发现通过ZonedDateTime更简单的转换:

long epochSec = ldt.atZone(zoneId).toEpochSecond();

4
如果您只关心UTC,那么long epochSec = localDateTime.toEpochSecond(ZoneOffset.UTC);
ruhong

2

查看此方法以查看支持哪些字段。您将找到LocalDateTime

NANO_OF_SECOND 
NANO_OF_DAY 
MICRO_OF_SECOND 
MICRO_OF_DAY 
MILLI_OF_SECOND 
MILLI_OF_DAY 
SECOND_OF_MINUTE 
SECOND_OF_DAY 
MINUTE_OF_HOUR 
MINUTE_OF_DAY 
HOUR_OF_AMPM 
CLOCK_HOUR_OF_AMPM 
HOUR_OF_DAY 
CLOCK_HOUR_OF_DAY 
AMPM_OF_DAY 
DAY_OF_WEEK 
ALIGNED_DAY_OF_WEEK_IN_MONTH 
ALIGNED_DAY_OF_WEEK_IN_YEAR 
DAY_OF_MONTH 
DAY_OF_YEAR 
EPOCH_DAY 
ALIGNED_WEEK_OF_MONTH 
ALIGNED_WEEK_OF_YEAR 
MONTH_OF_YEAR 
PROLEPTIC_MONTH 
YEAR_OF_ERA 
YEAR 
ERA 

当然,不支持INSTANT_SECONDS字段,因为a LocalDateTime不能引用任何绝对(全局)时间戳。但是有帮助的是字段EPOCH_DAY,该字段统计从1970-01-01开始的经过天数。类似的想法适用于该类型LocalDate(具有更少支持的字段)。

如果要获取不存在的millis-since-unix-epoch字段,则还需要时区以将本地类型转换为全局类型。这种转换可以简单得多,请参阅其他SO-posts

回到您的问题和代码中的数字:

The result 1605 is correct
  => (2014 - 1970) * 365 + 11 (leap days) + 31 (in january 2014) + 3 (in february 2014)
The result 71461 is also correct => 19 * 3600 + 51 * 60 + 1

自1970-01-01T00:00:00以来的16105L * 86400 + 71461 = 1391543461秒(注意,无时区)然后您可以减去时区偏移量(请注意,如果以毫秒为单位,则可能乘以1000)。

给定时区信息后更新:

local time = 1391543461 secs
offset = 3600 secs (Europe/Oslo, winter time in february)
utc = 1391543461 - 3600 = 1391539861

作为具有两种等效方法的JSR-310代码:

long secondsSinceUnixEpoch1 =
  LocalDateTime.of(2014, 2, 4, 19, 51, 1).atZone(ZoneId.of("Europe/Oslo")).toEpochSecond();

long secondsSinceUnixEpoch2 =
  LocalDate
    .of(2014, 2, 4)
    .atTime(19, 51, 1)
    .atZone(ZoneId.of("Europe/Oslo"))
    .toEpochSecond();

1
感谢您的解释。通过使用LocalDateTime time = LocalDateTime.parse("04.02.2014 19:51:01", DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss"));然后获得正确的结果Long epoch = time.atZone(ZoneId.of("Europe/Oslo")).toEpochSecond();

1

人类可读的日期转换为纪元

long epoch = new java.text.SimpleDateFormat("MM/dd/yyyyHH:mm:ss").parse("01/01/1970 01:00:00").getTime() / 1000;

纪元转换为人类可读的日期

String date = new java.text.SimpleDateFormat("MM/dd/yyyyHH:mm:ss").format(new java.util.Date (epoch*1000));

对于其他语言转换器:https//www.epochconverter.com


0

这是不使用时间的区域的一种方法:

LocalDateTime now = LocalDateTime.now();
long epoch = (now.getLong(ChronoField.EPOCH_DAY) * 86400000) + now.getLong(ChronoField.MILLI_OF_DAY);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.