Как получить миллисекунды из 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 Он пытается получить время Дата, а не текущее время?
Анубиан Нуб
2
«... способ получить текущие миллисекунды ...»
Дауд ибн Карим
миллисекунды считая с 1-1-1970. Я бродил, если есть метод, чтобы получить их, используя новые классы Java 8 LocalDate, LocalTime и LocalDateTime, потому что я не нашел один.
Джордж Сиггуроглу
1
Мое понимание цели этих занятий состоит в том, что это «ориентированное на человека» понимание времени, и currentTimeMillisоно не имеет значения в этом контексте. Подумайте Календарь + Настенные часы с действительно хорошей точностью, и не беспокойтесь о часовых поясах и местности. Так что нет способа вернуться к «UTC Time» из LocalTime
Гас

Ответы:

325

Я не совсем уверен, что вы имеете в виду под «текущими миллисекундами», но я предполагаю, что это число миллисекунд со времени «эпохи», а именно полуночи, 1 января 1970 года по Гринвичу.

Если вы хотите узнать количество миллисекунд с начала эпохи , то используйте, 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.
Маби
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
Нет, Epoch относится к UTC, но вы получаете текущее время из вашей локальной зоны.
Рафаэль Мембривс
2
@ ChristofferHammarström количество миллисекунд, прошедших с начала эпохи, не зависит от часового пояса. Это одинаковое количество миллисекунд, независимо от того, в какое время дня вы это называете. Два результата отличаются, потому что машине Брайана потребовалось 203 миллисекунды для выполнения второй команды.
Флетч
Можно ли использовать UTC, когда пользователь может
находиться
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
Да, это был мой голос @ Комментарий АнтонНовопашина. Так как вам нужно UTC, вы в порядке (вы можете упомянуть об этом в ответе). Кстати ZoneOffset, это подкласс ZoneId, поэтому я бы точно не сказал, что вы этого избежали, но пока вы счастливы ...
Оле В.В.
Мой первый комментарий был немного резким, но не был оскорбительным. Вы обиделись. Я прошу прощения. Я удалила его. Позвольте мне спросить об обратном: что может быть причиной того, что мы хотим избежать ZoneId?
Оле В.В.
@ OleV.V Можно ли использовать UTC? Не только для людей, живущих в часовом поясе UTC.
ГилбертС
1
@GilbertS Я не думаю, что кто-то живет в часовом поясе UTC. Рекомендуется использовать UTC для часов, которые используются в разных часовых поясах. См., Например, Java Best Practice for Manipulation / Storage для географически разнообразных пользователей . А может я не понял твой вопрос?
Оле В.В.
15

С Java 8 можно звонить java.time.Instant.toEpochMilli().

Например, звонок

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

дает те же результаты, что и

final long currentTimeJava1 = System.currentTimeMillis();
Marteng
источник
1
"дает те же результаты, что и" ... но потребляет больше ресурсов процессора и гораздо больше нагружает сборщик мусора.
VasiliNovikov
1
Я хотел бы видеть вышеописанное количественно (особенно для обычного использования - например, не для какого-либо приложения,
Брайан Агнью,
11

Вы также можете использовать, java.sql.Timestampчтобы получить миллисекунды.

LocalDateTime now = LocalDateTime.now();
long milliSeconds = Timestamp.valueOf(now).getTime();
System.out.println("MilliSeconds: "+milliSeconds);
Nalam
источник
Вы игнорируете острую необходимость в часовом поясе. Я не рекомендую делать это таким образом. Также Timestampкласс давно устарел и полон проблем с дизайном, поэтому я бы предпочел этого избегать, особенно когда мы можем использовать классы из java.timeлайков LocalDateTime.
Оле В.В.
@ OleV.V. Просто любопытно о проблемах дизайна Timestamp, Можете поделиться какой-нибудь статьей об этом? Это также помогает мне избежать использования Timestampмоего кода. Спасибо!
Налам
1
Короче говоря, он реализован как подкласс, Dateно часто не может быть обработан как Date. Большинство методов, унаследованных от Dateодного конструктора, устарели. В его toStringметоде используется часовой пояс JVM, что смущает многих, поскольку одно и то же Timestampпечатается по-разному на разных компьютерах ( пример ).
Оле В.В.
Это идеально подходит для модульного тестирования. Просто замените сейчас наLocalDate.of(year, month, day)
G_V
Это должен быть принятый ответ для обхода значений «всегда по Гринвичу».
LeYAUable
9

Чтобы узнать текущее время в миллисекундах (начиная с эпохи), используйте System.currentTimeMillis().

Анубиан Нуб
источник
3

Если у вас есть часы Java 8, то вы можете их использовать clock.millis()(хотя и рекомендуется использовать clock.instant()Java 8 Instant, так как это более точно).

Почему вы используете часы Java 8? Таким образом, в вашей структуре DI вы можете создать bean-компонент Clock:

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

и тогда в ваших тестах вы можете легко смоделировать это:

@MockBean private Clock clock;

или у вас может быть другой боб:

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

который помогает с тестами, которые утверждают даты и время неизмеримо.

JeeBee
источник
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();
}
Mohamed.Abdo
источник
0

Почему никто не упомянул метод LocalDateTime.toEpochSecond():

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

Это кажется короче, чем многие предложенные ответы выше ...

maxxyme
источник
это то, что я искал. Этот принятый ответ дал мне воли.
Брилл Паппин
Принять его можно только в API 26: {
Брилл Паппин
1
Потому что это дает только секунды. Странно, что нет никакого toEpochMilliметода, учитывая тот факт, что вы можете указать даже наносекунды в LocalDateTime: есть метод LocalDateTime.of(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond).
Изогфиф