Как преобразовать (string в utc) дату в миллисекунды, не нарушая ее часовой пояс в java

Рассмотрим нижестроку - время в формате UTC, и мне нужно эквивалентное время в миллисекундах с использованием java.

String flcDate = "2018-09-07 05:45:00.0";
String geofenceDate = "2018-07-27 08:42:20";

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

public static long stringToMilliSeconds(String string) throws ParseException {

          SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
          Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
          TimeZone fromTimeZone = calendar.getTimeZone();
          TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
          calendar.setTimeZone(fromTimeZone);

          calendar.setTime(sdf.parse(string));
          System.out.println(calendar.getTime().toString());


          return calendar.getTime().getTime();
    }

Не используйте старый Clander API. Используйте новые классы java.time.*. взгляните на этот ответ: stackoverflow.com/a/33060590/3636601

Jens 10.09.2018 07:54

Можете ли вы вычесть его из эпохи в UTC, чтобы получить продолжительность времени, а затем получить количество миллисекунд в нем? У продолжительности не должно быть часового пояса.

TheBeardedQuack 10.09.2018 07:56

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

amit singh 10.09.2018 08:18

Я рекомендую вам избегать класса SimpleDateFormat. Они не только давно устарели вместе с Calendar и Date, но и доставляют много хлопот. Сегодня у нас намного лучше java.time, современный API даты и времени Java и его DateTimeFormatter.

Ole V.V. 10.09.2018 08:18

Несмотря на операции с часовыми поясами, ваш SimpleDateFormat использует ваш местный часовой пояс и, следовательно, выдает точку во времени 2018-09-07 05: 45: 00.0 в вашем местном часовом поясе, а не в формате UTC. После появления этой ошибки она распространяется через ваш объект Calendar и возвращается обратно в возвращаемое значение.

Ole V.V. 10.09.2018 08:30
1
6
406
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Это использует локальную дату, время и мгновение для преобразования строки.

return LocalDateTime.parse("2018-09-07 05:45:00.0", 
                           DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.S"))
     .toInstant(ZoneOffset.UTC)
     .toEpochMilli(); //1536299100000

Полученный long представляет собой миллисекунды эпохи для введенной даты / времени (время UTC):

Instant.ofEpochMilli(1536299100000L)  ==> 2018-09-07T05:45:00Z

А для второй строки в качестве форматтера можно использовать DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").

Вы уверены, что это правильно? Вы читаете дату в местном часовом поясе, не так ли?

keuleJ 10.09.2018 08:18

1536299100000 дает мне: - 07.09.2018, 11:15:00.

amit singh 10.09.2018 08:24

Это правильно. Цитируемый результат, 1536299100000, равен 09.07.2018 в 5:45 (UTC) (проверено на unixtimestamp.com/index.php). «Местное время» не означает ваше местное время, это означает отсутствие информации о часовом поясе, которая затем добавляется в следующей строке: toInstant(ZoneOffset.UTC).

Ole V.V. 10.09.2018 08:24

@amitsingh 9/7/2018, 11:15:00 AM в вашем часовом поясе равно какому времени UTC? Какой у вас часовой пояс? Мне все кажется правильным.

Ole V.V. 10.09.2018 08:32

Как получить длинное значение в миллисекундах, эквивалентное 2018-09-07T05: 45: 00Z

amit singh 10.09.2018 08:46

@amitsingh Обратное: Instant.parse("2018-09-07T05:45:00Z").toEpochMilli(). Кстати, в этом случае лучше использовать формат даты и времени 2018-09-07T05:45:00Z.

ernest_k 10.09.2018 08:48

Конечно, вам следует использовать новые классы java.time *. Но если это невозможно, попробуйте следующее:

public static long stringToMilliSeconds(String string) throws ParseException {

          SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
          sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
          Date date = sdf.parse(string);
          System.out.println(date.getTime());

          return date.getTime();
    }

Конечно, можно использовать классы java.time четырех с половиной лет назад. Однако при использовании Java 6 или 7 вам понадобится библиотека ThreeTen Backport. Начиная с Java 8 и на java.time встроен.

Ole V.V. 10.09.2018 08:20

Это правильный ответ, только не рекомендуется использовать устаревшие классы (кстати, вы не используете объект Calendar, поэтому я думаю, вы можете удалить эту строку).

Ole V.V. 10.09.2018 08:36
Ответ принят как подходящий

java.time

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

private static DateTimeFormatter FORMATTER = new DateTimeFormatterBuilder()
        .append(DateTimeFormatter.ISO_LOCAL_DATE)
        .appendLiteral(' ')
        .append(DateTimeFormatter.ISO_LOCAL_TIME)
        .toFormatter();

public static long stringToMilliseconds(String string) {
    return LocalDateTime.parse(string, FORMATTER)
            .toInstant(ZoneOffset.UTC)
            .toEpochMilli();
}

Демонстрация:

    String flcDate = "2018-09-07 05:45:00.0";
    System.out.println(stringToMilliseconds(flcDate)); // 1536299100000
    String geofenceDate = "2018-07-27 08:42:20";
    System.out.println(stringToMilliseconds(geofenceDate)); // 1532680940000

Вывод в комментариях.

Встроенный DateTimeFormatter.ISO_LOCAL_DATE принимает строку даты вроде 2018-09-10. DateTimeFormatter.ISO_LOCAL_TIME принимает временную строку, например 10:15 или 05: 45: 00.0. Секунды и доли секунды являются необязательными, и дробь может быть до 9 десятичных знаков. Я использую DateTimeFormatterBuilder для объединения двух форматеров в одно с пробелом между датой и временем.

«Local» в LocalDateTime (и других именах классов java.time) означает «без информации о часовом поясе», поэтому использование этого класса гарантирует, что никакой непреднамеренный часовой пояс, как ваш по умолчанию, не помешает. А использование ZoneOffset.UTC при преобразовании в Instant гарантирует, что мы получим время в формате UTC.

Что пошло не так в вашем коде?

Несмотря на операции с часовыми поясами, ваш SimpleDateFormat использует ваш местный часовой пояс и, следовательно, выдает точку во времени 2018-09-07 05: 45: 00.0 в вашем местном часовом поясе, а не в формате UTC. После появления этой ошибки она распространяется через ваш объект Calendar и возвращается обратно в возвращаемое значение.

Я рекомендую вам вообще не использовать SimpleDateFormat, Calendar и TimeZone. Эти классы давно устарели, и, как известно, проблема с SimpleDateFormat. Сегодня у нас намного лучше java.time, современный API даты и времени Java.

Ссылка:Учебник Oracle: Дата и время объясняет, как использовать java.time.

Другие вопросы по теме