Подтвердить что ты не робот

Как извлечь эпоху из LocalDate и LocalDateTime?

Как извлечь значение epoch в Long из экземпляров LocalDateTime или 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 с летним временем.

4b9b3361

Ответ 1

В классах LocalDate и LocalDateTime нет информации о часовом поясе или смещении по времени. Это означает, что вы должны сначала указать правильный часовой пояс.

LocalDate

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

"Миллис с момента unix" представляет собой мгновение, поэтому вы должны использовать класс Instant:

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

Ответ 3

Требуемое преобразование требует смещения от 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

Посмотрите этот метод, чтобы увидеть, какие поля поддерживаются. Вы найдете для 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 - конечно - не поддерживается, потому что LocalDateTime не может ссылаться на абсолютную (глобальную) метку времени. Но полезно поле EPOCH_DAY, которое учитывает прошедшие дни с 1970-01-01. Подобные мысли действительны для типа LocalDate (с еще менее поддерживаемыми полями).

Если вы намерены получить несуществующее поле millis-since-unix-epoch, вам также понадобится часовой пояс для преобразования из локального в глобальный. Это преобразование можно сделать гораздо проще, см. Другие SO-сообщения.

Возвращаясь к вашему вопросу и номерам в вашем коде:

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

16105L * 86400 + 71461 = 1391543461 секунд с 1970-01-01T00: 00: 00 (внимание, без часовой пояс) Затем вы можете вычесть смещение часового пояса (следить за возможным умножением на 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();