SimpleDateFormat.parse (date_string) генерирует предыдущую дату - PullRequest
0 голосов
/ 17 июня 2020

У меня странная проблема.

SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy", Locale.ENGLISH);

Я вызываю его с помощью:

Date date = sdf.parse("06/05/2020");

, и он показывает, что «дата» - четверг июнь 04 18:00:00 MDT 2020, то есть , на один день меньше.

Где не подходит SimpleDateFormat?

Я использую Android Studio 3.5.1 и Androidx.

Заранее спасибо. Шон

Ответы [ 2 ]

1 голос
/ 17 июня 2020

java .time и ThreeTenABP

Пуленепробиваемый способ - переход на java .time, современный Java API даты и времени.

    DateTimeFormatter dateFormatter
            = DateTimeFormatter.ofPattern("MM/dd/yyyy", Locale.ENGLISH);

    LocalDate date = LocalDate.parse("06/05/2020", dateFormatter);

    System.out.println(date);

Вывод это:

2020-06-05

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

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

Первая возможность, часовой пояс по умолчанию вашей JVM мог измениться в процессе. Чтобы продемонстрировать:

    TimeZone.setDefault(TimeZone.getTimeZone("Etc/UTC"));
    SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy", Locale.ENGLISH);
    Date date = sdf.parse("06/05/2020");

    TimeZone.setDefault(TimeZone.getTimeZone("America/Edmonton"));
    System.out.println(date);

Четверг, 04 июня 18:00:00 MDT 2020

Честно говоря, это не полный день неправильно, это 6 часов. Это достаточно плохо, и определенно день недели и день месяца неправильные. Обратите внимание, что настройка часового пояса JVM могла быть изменена из совершенно другой части вашей программы или из другой программы, работающей в той же JVM. Произошло следующее: SimpleDateFormat получил часовой пояс JVM по умолчанию, то есть UT C. Итак разобрал дату в первый момент 5 июня в UT C. На данный момент в Северной Америке все еще 4 июня. Затем, когда мы печатаем Date, Date.toString() захватывает (измененный) часовой пояс JVM и использует его для рендеринга строки. Таким образом, мы получили время MDT (летнее время в горах Северной Америки), а не время UT C, которое использовалось для синтаксического анализа.

Нам не нужно что-то столь же drasti c, как установка часового пояса для демонстрации всей JVM. Достаточно установить часовой пояс форматтера.

    SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy", Locale.ENGLISH);
    sdf.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
    Date date = sdf.parse("06/05/2020");
    System.out.println(date);

При работе в Америке / часовом поясе Эдмонтона:

Четверг, 04 июня 18:00:00 MDT 2020

Что происходит, в основном то же, что и выше.

Вопрос: Разве java .time не требует Android уровня API 26?

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

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

Ссылки

0 голосов
/ 17 июня 2020

Это обычная проблема с TimeZone, вам нужно установить правильный часовой пояс для sdf, например:

sdf.setTimeZone(TimeZone.getTimeZone("GMT"))

Если вы установите правильный часовой пояс, вы увидите правильный день :)

Надеюсь, это поможет

...