Як отримати мілісекунди з LocalDateTime в Java 8


285

Мені цікаво , якщо є спосіб , щоб отримати поточні мілісекунди , так як 1-1-1970 (епохи) , використовуючи новий LocalDate, LocalTimeабо LocalDateTimeкласи Java 8.

Відомий спосіб нижче:

long currentMilliseconds = new Date().getTime();

або

long currentMilliseconds = System.currentTimeMillis();

6
Що не так System.currentTimeMillis()?
Давуд ібн Карім

16
@DavidWallace Він намагається отримати час дати, а не поточний час?
Anubian Noob

2
"... спосіб отримати поточні мілісекунди ..."
Давуд ібн Карім

мілісекунди від 1-1-1970. Я блукав, чи є спосіб отримати їх за допомогою нових класів Java 8 LocalDate, LocalTime і LocalDateTime, тому що я не знайшов його.
Джордж Сіґуроглоу

1
Моє розуміння мети цих занять полягає в тому, що це розуміння часу, орієнтоване на людину, і currentTimeMillisбуло б неважливим у цьому контексті. Подумайте Календар + Настінні годинники з дійсно хорошою точністю і не турбуйтеся про часові пояси та місцеположення. Тож немає можливості повернутися до "UTC часу" з LocalTime
Gus

Відповіді:


325

Я не зовсім впевнений, що ви маєте на увазі під "поточними мілісекундами", але я припускаю, що це кількість мілісекунд після "епохи", а саме опівночі, 1 січня 1970 року UTC.

Якщо ви хочете знайти кількість мілісекунд з епохи прямо зараз, тоді використовуйте System.currentTimeMillis()як Анубіан Нооб . Якщо так, то немає ніяких причин використовувати будь-який з нових API java.time для цього.

Однак, можливо, у вас вже є LocalDateTimeдесь подібний об’єкт, і ви хочете перетворити його в мілісекунди з епохи. Це неможливо зробити безпосередньо, оскільки LocalDateTimeсімейство об'єктів не має поняття, в якому часовому поясі вони знаходяться. Таким чином, потрібно подавати інформацію про часовий пояс, щоб знайти час відносно епохи, що знаходиться в UTC.

Припустимо, у вас LocalDateTimeтаке:

LocalDateTime ldt = LocalDateTime.of(2014, 5, 29, 18, 41, 16);

Потрібно застосувати інформацію про часовий пояс, вказавши а ZonedDateTime. Я перебуваю в тому ж часовому поясі, що і Лос-Анджелес, тому я б зробив щось подібне:

ZonedDateTime zdt = ldt.atZone(ZoneId.of("America/Los_Angeles"));

Звичайно, це робить припущення про часовий пояс. І можуть бути випадки, наприклад, якщо місцевий час називає час біля переходу на літній час (літній час). Давайте відкладемо їх, але ви повинні знати, що ці випадки існують.

У будь-якому випадку, якщо ви можете отримати дійсне ZonedDateTime, ви можете перетворити це на кількість мілісекунд з епохи, наприклад:

long millis = zdt.toInstant().toEpochMilli();

5
Зверніть увагу , що ZonedDateTime вже є в getEpochSecondметод ( з допомогою ChronoZonedDateTime по замовчуванням ). Не потрібно Instant.
mabi

14
Звичайно, якщо все, що вам потрібно, це секунди, а не мілісекунди.
Стюарт Маркс

1
Ну що ж, я був неточним: ZonedDateTimeтакож Instantз getNanoметодом, так що ви не зможете просто замінити instз zdtв вашому прикладі?
мабі

18
Уникайте математики на нано, використовуючи zdt.get (ChronoField.MILLI_OF_SECOND). Уникайте всієї математики, використовуючи zdt.toInstant (). ToEpochMilli ()
JodaStephen

1
У всякому разі, оскільки ви і @walen прокоментували, я вирішив видалити свої оригінальні повідомлення зараз, щоб уникнути оману людей.
Пер Лундберг

81

Що я роблю, тому не вказую часовий пояс,

System.out.println("ldt " + LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
System.out.println("ctm " + System.currentTimeMillis());

дає

ldt 1424812121078 
ctm 1424812121281

Як ви бачите, номери однакові, за винятком невеликого часу виконання.

На випадок, якщо вам не подобається System.currentTimeMillis, використовуйте Instant.now().toEpochMilli()


3
Ні, Епоха відносно UTC, але ви отримуєте поточний час у вашій місцевій зоні.
Рафаель Мембрівс

2
@ ChristofferHammarström кількість мілісекунд, що минули з епохи, є фактом, незалежним від часового поясу. Це стільки ж мілісекунд, незалежно від того, в який час доби ви його називали. Два результати різні, тому що машині Брайана було потрібно 203 мілісекунди для виконання другої команди.
Флетч

Це нормально використовувати UTC, коли користувач може бути в іншому часовому поясі
GilbertS

2
@GilbertS ви, ймовірно, ніколи не повинні використовувати цей точний код, використовуйте API за призначенням. Час дати завжди має бути UTC, коли він зберігається на комп’ютері або передається іншому користувачеві. Зазвичай він повинен бути представлений користувачеві як місцевий час дати, використовуючи власні налаштування часового поясу.
Брайан

20

Щоб уникнути ZoneId, ви можете:

LocalDateTime date = LocalDateTime.of(1970, 1, 1, 0, 0);

System.out.println("Initial Epoch (TimeInMillis): " + date.toInstant(ZoneOffset.ofTotalSeconds(0)).toEpochMilli());

Отримання 0 як значення, це правильно!


8
ZoneOffset.ofTotalSeconds(0)це те саме, щоZoneOffset.UTC
Антон Новопашин

1
Так, це мене викликало коментар @ коментаря AntonNovopashin. Оскільки вам потрібен UTC, ви все добре (ви можете згадати це у відповіді). BTW ZoneOffset- це підклас ZoneId, тому я б точно не сказав, що ви цього уникали, але поки ви щасливі ...
Ole VV

Перший мій коментар був трохи суворим, але не мав на увазі як образливий. Ви образилися. Вибачте. Я його видалив. Дозвольте запитати навпаки: що може бути нашою причиною того, щоб ми хотіли уникати ZoneId?
Оле ВВ

@ OleV.V Чи добре використовувати UTC. Не лише для людей, що живуть у часовому поясі UTC.
Гілберт

1
@GilbertS Я не думаю, що хтось живе в часовому поясі UTC. Використання UTC для часу, що використовується в часових поясах, рекомендується як хороша практика. Дивіться, наприклад, найкращі практики Java щодо маніпуляції датами / зберігання для географічно різних користувачів . А може, я не зрозумів вашого запитання?
Оле ВВ

15

З Java 8 ви можете телефонувати java.time.Instant.toEpochMilli().

Наприклад дзвінок

final long currentTimeJava8 = Instant.now().toEpochMilli();

дає ті ж результати, що і

final long currentTimeJava1 = System.currentTimeMillis();

1
"дає ті ж результати, що і" ... але забирає більше процесорної потужності та підкреслює сміттєзбірник набагато більше.
ВасильНовіков

1
Я хотів би бачити вищезазначене кількісно (особливо для звичайного використання - наприклад, не для деяких критичних для роботи в реальному часі додатків ...)
Brian Agnew

11

Ви також можете використовувати java.sql.Timestampмілісекунди.

LocalDateTime now = LocalDateTime.now();
long milliSeconds = Timestamp.valueOf(now).getTime();
System.out.println("MilliSeconds: "+milliSeconds);

Ви ігноруєте вирішальну потребу в часовому поясі. Я не рекомендую робити це таким чином. Також Timestampклас давно застарів і наповнений проблемами дизайну, тому я вважаю за краще уникати цього, особливо коли ми можемо використовувати класи на java.timeзразок LocalDateTime.
Оле ВВ

@ OleV.V. Просто цікаво з дизайнерськими проблемами Timestamp, чи можете ви поділитися статтею з цього приводу? Це допомагає мені також уникати використання Timestampмого коду. Дякую!
Налам

1
Коротше кажучи, він реалізований як підклас, Dateале часто не може бути оброблений як Date. Більшість методів, успадкованих від Dateодного конструктора, і застарілі. Його toStringметод використовує часовий пояс JVM, який багато хто плутає, оскільки одне і те ж Timestampдрукується по-різному на різних комп'ютерах ( приклад ).
Оле ВВ

Це ідеально підходить для тестування одиниць. Просто замініть зараз наLocalDate.of(year, month, day)
G_V

Це має бути прийнятою відповіддю для вирішення значень "завжди UTC".
LeYAUable


3

Якщо у вас є годинник Java 8, ви можете використовувати його clock.millis()(хоча він рекомендує використовувати, clock.instant()щоб отримати миттєвий Java 8, оскільки він є більш точним).

Навіщо використовувати годинник Java 8? Таким чином, у вашому DI-рамках ви можете створити годинник:

@Bean
public Clock getClock() {
    return Clock.systemUTC();
}

а потім у своїх тестах ви можете легко знущатися над ним:

@MockBean private Clock clock;

або ви можете мати інший квасоля:

@Bean
public Clock getClock() {
    return Clock.fixed(instant, zone);
}

що допомагає з тестами, які незмірно стверджують дати та часи.


1
  default LocalDateTime getDateFromLong(long timestamp) {
    try {
        return LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), ZoneOffset.UTC);
    } catch (DateTimeException tdException) {
      //  throw new 
    }
}

default Long getLongFromDateTime(LocalDateTime dateTime) {
    return dateTime.atOffset(ZoneOffset.UTC).toInstant().toEpochMilli();
}

0

Чому ніхто не згадав метод LocalDateTime.toEpochSecond():

LocalDateTime localDateTime = ... // whatever e.g. LocalDateTime.now()
long time2epoch = localDateTime.toEpochSecond(ZoneOffset.UTC);

Це здається набагато коротшим, що багато запропонованих відповідей вище ...


це те, що я шукав. Ця прийнята відповідь давала мені воллі.
Брілл Паппін

Прийміть його лише в API 26: {
Брілл Паппін

1
Бо це дає лише секунди. Дивно, що toEpochMilliметоду немає , беручи до уваги той факт, що ви можете вказати навіть наносекунди в LocalDateTime: є метод LocalDateTime.of(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond).
izogfif
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.