Преобразование даты UTC в миллисекунды

Меня не интересует текущее время в формате UTC в миллисекундах, и мне не нужно возиться с часовыми поясами. Моя исходная дата уже сохранена как отметка времени в формате UTC.

У меня есть дата, хранящаяся в базе данных по времени UTC, «2012-06-14 05:01:25». Меня не интересует datetime, а только часть даты it. Итак, после получения даты на Java и без учета часов, минут и секунд - у меня осталось «2012-06-14».

Как я могу преобразовать это в миллисекунды UTC?


person Tyrick    schedule 22.08.2012    source источник


Ответы (6)


РЕДАКТИРОВАТЬ: я пропустил «игнорирование времени суток». Сейчас он присутствует, но ближе к концу ...

Самый простой подход - это, вероятно, использовать SimpleDateFormat, установив часовой пояс. соответственно:

SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US);
format.setTimeZone(TimeZone.getTimeZone("UTC"));

Date date = format.parse(text);
long millis = date.getTime();

(Здесь важна установка часового пояса, иначе значение будет интерпретироваться как местный часовой пояс.)

В качестве альтернативы, если вы делаете что-то менее тривиальное, чем это, используйте Joda Time, который является гораздо лучшим API даты / времени. В частности, SimpleDateFormat не потокобезопасен, тогда как DateTimeFormatter:

// This can be reused freely across threads after construction.
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")
    .withLocale(Locale.US)
    .withZoneUTC();

// Option 1
DateTime datetime = formatter.parseDateTime(text);
long millis = dateTime.getMillis();

// Option 2, more direct, but harder to diagnose errors
long millis = formatter.parseMillis(text);

Итак, мы разобрали всю кабуду целиком. Самый простой способ игнорировать часть даты - просто округлить ее - в конце концов, Java не учитывает дополнительных секунд, поэтому мы можем просто обрезать ее:

long millisPerDay = 24L * 60L * 60L * 1000L; // Or use TimeUnit
long dayMillis = (millis / millisPerDay) * millisPerDay;

Это будет «округляться к 1970 году», поэтому, если у вас есть дата до 1970 года, она будет округлена до конца дня - но я подозреваю, что это вряд ли будет проблемой.

В версии Joda Time вы можете просто использовать это вместо:

DateTime dateTime = formatter.parseDateTime(text);
long millis = dateTime.toLocalDate().getLocalMillis();

Я лично не согласился бы с идеей просто взять подстроку. Даже если вы на самом деле не заинтересованы в сохранении часа / минуты / секунды, я думаю, что уместно проанализировать то, что вам дали, и затем выбросить информацию. Помимо всего прочего, это приводит к тому, что ваш код не работает должным образом с неверными данными, например.

"2012-06-100"

or

"2012-06-14 25:01:25"

указывают на проблемы в том, что предоставляет вам данные, и это хорошо заметить, а не продолжать вслепую только потому, что первые 10 символов в порядке.

person Jon Skeet    schedule 22.08.2012
comment
Поскольку OP хочет только дату, я бы сначала подстроку (0,10) ее проанализировал бы только дату. - person Peter Lawrey; 23.08.2012
comment
@PeterLawrey: Я возражал против вызова подстроки в конце сообщения. - person Jon Skeet; 23.08.2012

ОБНОВЛЕНИЕ. См. современное решение с использованием классов java.time в правильных ответах Оле В.В..

Проще

Ответ Джона Скита правильный. И он делает хорошее замечание о включении, а не усечении информации о времени суток при синтаксическом анализе.

Однако его код можно было упростить. Тем более что в последних версиях Joda-Time появился важный новый метод: _ 1_. Этот метод заменяет все классы и методы, связанные с "полуночью", которые теперь устарели.

Указание языкового стандарта - хорошая привычка, как показано в его коде. Но в этом конкретном случае Locale не нужен.

Его ответ правильно предполагает, что библиотека Joda-Time намного превосходит использование java.util.Date, .Calendar и java.text.SimpleTextFormat. Эти занятия, как известно, доставляют много хлопот, и их следует избегать. Вместо этого используйте Joda-Time или новый java .time пакет, встроенный в Java 8 (вдохновленный Joda-Time, определенный JSR 310).

Первый момент дня

Вы не можете игнорировать время дня, если вам нужно количество миллисекунд с момента эпоха. Я подозреваю, что вы хотите изменить время до первого момента дня. В UTC это всегда означает время 00:00:00.000. Но обратите внимание, что в местных часовых поясах первый момент может быть другим временем из-за перехода на летнее время А возможно и другие аномалии.

ISO 8601

Ваша строка почти в стандартном формате ISO 8601, но нам нужно заменить T на ПРОБЕЛ в центре. Затем мы можем передать полученную строку непосредственно в Joda-Time, поскольку Joda-Time имеет встроенный средства форматирования, используемые по умолчанию для стандартных строк.

Пример кода

В следующем примере кода предполагается, что целью вашего вопроса является анализ строки как значения даты и времени в UTC часовой пояс, отрегулируйте время до первого момента дня, а затем преобразуйте его в количество миллисекунд, поскольку эпоха Unix (начало 1970 г. по всемирному координированному времени).

String inputRaw = "2012-06-14 05:01:25";
String input = inputRaw.replace( " ", "T" );  // Replace SPACE with a 'T'.
DateTime dateTime = new DateTime( input, DateTimeZone.UTC );  // Parse, assuming UTC.
DateTime dateTimeTopOfTheDay = dateTime.withTimeAtStartOfDay();  // Adjust to first moment of the day.
long millisecondsSinceUnixEpoch = dateTimeTopOfTheDay.getMillis();  // Convert to millis. Use a 'long', not an 'int'.
person Basil Bourque    schedule 08.10.2014

java.time и JDBC 4.2

Даю современный ответ. В наши дни (и в последние несколько лет) вы должны использовать java.time, современный API даты и времени Java, для работы с датой и временем. А начиная с JDBC 4.2 вы можете напрямую извлекать объекты java.time из своей базы данных (а также сохранять их в ней). Современная реализация JPA (Hibernate, по крайней мере, начиная с Hibernate 5) будет счастлива сделать то же самое. Так что забудьте о SimpleDateFormat, Date и других старых классах, используемых в большинстве старых ответов. Упомянутые из них плохо спроектированы, и работать с java.time намного приятнее.

Получите правильные объекты даты и времени из вашей базы данных

Я также рекомендую не извлекать время UTC в виде строки из базы данных. Если тип данных в SQL - timestamp with time zone (рекомендуется для времени UTC), получите OffsetDateTime. Например:

    PreparedStatement pStmt = yourDatabaseConnection
            .prepareStatement("select utc_time from your_table where id = 7;");
    ResultSet rs = pStmt.executeQuery();
    if (rs.next()) {
        OffsetDateTime utcDateTime = rs.getObject("utc_time", OffsetDateTime.class);
        long millisecondsSinceEpoch = utcDateTime.truncatedTo(ChronoUnit.DAYS)
                .toInstant()
                .toEpochMilli();
        System.out.println("Milliseconds since the epoch: " + millisecondsSinceEpoch);
    }

Если тип в SQL - dateTime или timestamp без часового пояса, нам, вероятно, потребуется вместо этого получить LocalDateTime (подробности зависят от вашего драйвера JDBC и часового пояса вашего сеанса базы данных). Проходит так же. Чтобы преобразовать ваш LocalDateTime в OffsetDateTime, см. Преобразование ниже.

Если вам нужно преобразовать из строки

Если вы не можете избежать получения времени UTC в виде строки, как в вопросе, проанализируйте его в LocalDateTime и преобразуйте оттуда. Например:

    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss");
    String utcTimeString = "2012-06-14 05:01:25";
    long millisecondsSinceEpoch = LocalDateTime.parse(utcTimeString, formatter)
            .atOffset(ZoneOffset.UTC)
            .toInstant()
            .toEpochMilli();
    System.out.println("Milliseconds since the epoch: " + millisecondsSinceEpoch);

Выход:

Миллисекунды с эпохи: 1339650085000

Ссылка

person Ole V.V.    schedule 30.03.2020

Используйте объект Date в сочетании с SimpleDateFormat.

В Date есть метод getTime (), который вернет вам миллисекунды.

Пример, решающий вашу проблему:

Date truc = new SimpleDateFormat( "y-m-d").parse( "2010-06-14");
System.out.println(truc.getTime());
person Benj    schedule 22.08.2012

SimpleDateFormat ft = new SimpleDateFormat ("yyyy-MM-dd"); //or whatever format you have
Date t = ft.parse('2014-03-20');

String result = String.format("%tQ", t);

System.out.printf("%tQ", t);

Здесь есть два метода:

  1. вы помещаете результат в миллисекунды в переменный результат
  2. распечатайте его прямо сейчас.
person Nazilla    schedule 07.10.2014

Я использую простой и понятный подход:

Date date = new Date(utcDateInString);
long utcDateInMilliSeconds = date.getTime();
person zeeshan    schedule 10.02.2015
comment
Кто-то проголосовал против моего ответа без объяснения причин. В последнее время в StackOverflow наблюдается растущая тенденция, и ее не следует поощрять. - person zeeshan; 12.10.2016
comment
Я не голосовал против. Возможные причины для этого: (1) Ваш код выдает IllegalArgumentException (когда utcDateInString - это строка из вопроса). (2) Вы пытаетесь использовать конструктор Date(String), который устарел уже более 10 лет, когда вы опубликовали свой ответ. - person Ole V.V.; 30.03.2020