Разбор строки в дату и время не возвращает правильное время

В Android... Я ожидаю 15:12 как время ожидания следующего кода, но получаю 16:12. Каков правильный способ анализа этого формата даты и времени.

String dt = "2018-09-02T19:12:00-0400";
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");

try {
    Date date = dateFormat.parse(dt);
    System.out.println(date);
} catch (ParseException e) {
    e.printStackTrace();
}

person YKDev    schedule 03.09.2018    source источник
comment
Может быть, он не использует тот же часовой пояс, что и вы? Попробуйте отформатировать дату явно в строку, включая часовой пояс, и посмотрите, что там написано...   -  person moilejter    schedule 03.09.2018
comment
Каков желаемый шаблон вывода?   -  person xingbin    schedule 03.09.2018
comment
А почему вы ожидаете 4:12 pm, ваш часовой пояс -07:00?   -  person xingbin    schedule 03.09.2018
comment
Я добавил dateFormat.setTimeZone(TimeZone.getTimeZone(timeZone)); но все же выход на один час позже.   -  person YKDev    schedule 03.09.2018
comment
В качестве отступления подумайте о том, чтобы выбросить давно устаревший и заведомо неприятный SimpleDateFormat и друзей и добавить ThreeTenABP на свой Android. проект, чтобы использовать java.time, современный API даты и времени Java. С ним намного приятнее работать.   -  person Ole V.V.    schedule 04.09.2018
comment
Просто проверяю, ты неправильно понял смещение? -0400 не означает, что вы должны вычесть 4 часа, а скорее наоборот: время находится со смещением на -4 часа от UTC, таким образом, 4 часа уже вычтены. Таким образом, 19:12:00-04:00 — это тот же момент времени, что и 23:12 UTC.   -  person Ole V.V.    schedule 04.09.2018


Ответы (1)


Часовой пояс

Лучше всего явно указать, в каком часовом поясе вы хотите получить результат:

    DateTimeFormatter inputFormatter 
            = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssXX");
    DateTimeFormatter displayFormatter = DateTimeFormatter
            .ofLocalizedDateTime(FormatStyle.LONG)
            .withLocale(Locale.ENGLISH);
    ZoneId displayZone = ZoneId.of("Pacific/Pitcairn");

    String dt = "2018-09-02T19:12:00-0400";
    OffsetDateTime dateTime = OffsetDateTime.parse(dt, inputFormatter);
    String displayDateTime = dateTime.atZoneSameInstant(displayZone)
            .format(displayFormatter);
    System.out.println(displayDateTime);

Это печатает:

2 сентября 2018 г., 15:12:00 по тихоокеанскому стандартному времени

Я использовал часовой пояс Pacific/Pitcairn в своем коде, но вы лучше знаете, какой часовой пояс вам нужен.

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

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

Ваш способ анализа строки даты правильный и дает правильный Date.

При печати Date вы неявно вызываете toString. Устаревший класс Date имеет своеобразный и запутанный метод toString: он получает настройку часового пояса JVM и использует ее для создания строки. Таким образом, в зависимости от вашего часового пояса по умолчанию вы можете получить любой час дня на выходе. Таким образом, кажется, что настройка часового пояса вашей JVM не соответствует тому, что вы ожидали.

Поскольку вы ожидали 15:12 из вашего ввода 19:12:00-0400, я полагаю, что вам нужен часовой пояс со смещением -08:00 от UTC в сентябре. Если, например, вашим часовым поясом по умолчанию была Америка/Лос-Анджелес, стандартное время которого -08:00, вы получите Sun Sep 02 16:12:00 PDT 2018, потому что летнее время (летнее время) действует в Калифорнии в сентябре, поэтому смещение равно -07. :00.

Использование часового пояса по умолчанию вашей JVM всегда ненадежно, поскольку этот параметр может быть изменен в любое время другими частями вашей программы или другими программами, работающими в той же JVM.

Вопрос: Могу ли я использовать java.time на Android?

Да, java.time прекрасно работает на старых и новых устройствах Android. Просто требуется как минимум Java 6.

  • В Java 8 и более поздних версиях, а также на более новых устройствах Android (начиная с уровня API 26, как мне сказали) современный API встроен.
  • В Java 6 и 7 используйте ThreeTen Backport, бэкпорт новых классов (ThreeTen для JSR 310; см. ссылки внизу).
  • На (старом) Android используйте версию ThreeTen Backport для Android. Он называется ThreeTenABP. И убедитесь, что вы импортируете классы даты и времени из org.threeten.bp с подпакетами.

Ссылки

person Ole V.V.    schedule 04.09.2018