Як витягти епоху з LocalDate та LocalDateTime?


102

Як отримати значення епохи 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 для місцевого часу "04.02.2014 19:51:01". Мій часовий пояс - Europe/OsloUTC + 1, літній час.


Поясніть, будь ласка, очікуваний номер 1396468261. Я отримую без корекції часового поясу: 1391543461 (див. Редагування у моїй відповіді). 57 днів різниці!
Мено Хохшильд

@MenoHochschild Я оновив своє запитання інформацією про часовий пояс і виправив фактичне значення з GTM до localtime. Чи є простіший спосіб отримати епоху якоїсь LocalDateTimeіншої, ніж її вручну обчислити?

Повертаючись із паузи, дивіться моє оновлення.
Мено Хохшильд

Відповіді:


147

Класи LocalDateі LocalDateTimeне містять інформації про часовий пояс або зміщення часу , і секунди з часу епохи були б неоднозначними без цієї інформації. Однак об'єкти мають кілька методів перетворення їх у об'єкти дати / часу за допомогою часових поясів, передаючи ZoneIdекземпляр.

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
Чи можливо уникнути використання ZoneId або використання з налаштованим, постійним екземпляром ZoneId (+0, що означає GMT)? Я запитую це, тому що хочу, щоб усі розрахунки були нормалізовані до нього. Крім того, як я можу зробити протилежне: перетворити з епохи час у LocalDate / LocalDateTime (також без ZoneId або з GMT)?
андроїд розробник

2
Не звертай уваги. Знайдено:ZoneId.ofOffset("UTC", ZoneOffset.ofHours(0))
андроїд розробник

7
Більш простий підхід призначений лише long epoch = time.toEpochSecond(ZoneOffset.UTC)для випадків UTC, або коли ви вже знаєте часовий пояс, або long epoch = time.toEpochSecond(ZoneId.systemDefault());якщо ви хочете пройти цей маршрут.
Маркус

Це може здатися смішним, але як щодо переходу з епохи в LocalDate, LocalTime & LocalDateTime
samuel Owino

Неважливо, я думаю, що я його знайшов; Instant.ofEpochMilli(responseTime).atZone(ZoneId.systemDefault()).toLocalTime()
Самуель Оуїно

27

'Millis since unix epoch' являє собою мить, тому вам слід використовувати клас Instant:

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

його неправильно використовувати, ZoneId.systemDefault()оскільки unix epoch посилається на 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(з ще менш підтримуваними полями).

Якщо ви маєте намір отримати неіснуюче поле milis-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();

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);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.