SimpleDateFormat mm: формат ss - минуты дополняются 3 - PullRequest
0 голосов
/ 09 ноября 2018

У меня самая странная проблема - в нашем приложении в одном месте мы показываем время, отформатированное с помощью mm: ss, с использованием SimpleDateFormat. Проблема в том, что у нас есть клиент в США, который жалуется на то, что 5 минут отформатированы как 35:00. Я сузил, что SimpleDateFormat.format вызывается с тем же значением, с которым я тестирую, но они получают минуты, дополненные 3 вместо 0.

Дело в том, что я не могу воспроизвести проблему, и они говорят мне, что они тестировали и получают ее на 4 разных устройствах:

  • Oppo X9076 (Android 5.0)
  • Xiaomi Mi A1 (Android 8.1.0)
  • Samsung SM-T715Y (Android 7.0)
  • HUAWEI BLA-L29 (Android 8.0)

Я тоже тестирую на Xiaomi Mi A1 (и некоторых других), но время подходит, когда я пытаюсь.

Вот как форматируется время:

SimpleDateFormat timeFormatter = new SimpleDateFormat("mm:ss", Locale.getDefault());
timeFormatter.format(new Date(5*60*1000));

Кто-нибудь видел что-то подобное?

1 Ответ

0 голосов
/ 09 ноября 2018

Это проблема часового пояса. Точнее говоря, проблема неправильного использования SimpleDateFormat для чего-то, для чего оно не предназначалось. Вот способ, которым вы можете воспроизвести:

    TimeZone.setDefault(TimeZone.getTimeZone("America/St_Johns"));
    SimpleDateFormat timeFormatter = new SimpleDateFormat("mm:ss", Locale.getDefault());
    System.out.println(timeFormatter.format(new Date(5*60*1000)));

Вывод этого фрагмента:

35: 00

Пояснение: new Date(5*60*1000) дает дату-время через 5 минут после эпохи, то есть 00:05:00 UTC 1 января 1970 года. В это время, как и в любое другое время, разные зоны мира имеют разное время. Однако большинство часовых поясов имеют смещение от UTC на целое количество часов. Таким образом, время будет через 5 минут после часа, и ваш форматер напечатает его как 05:00. Вот почему вы не заметили проблему раньше. Например, в Берлине будет 01:05:00, а в Нью-Йорке будет 19:05:00 накануне вечером. Однако есть также часовые пояса, которые имеют смещения от UTC, которые не являются целым числом часов. Например, Азия / Калькутта в +05: 30 и Азия / Катманду в +05: 45. В таком часовом поясе время не будет на 5 минут позже часа, и вы получите неожиданный результат, подобный тому, который вы видели.

Предлагаемые решения включают в себя:

  • Используйте TimeUnit для преобразования секунд в минуты и секунды и String.format для их форматирования в две цифры.
  • Если вам нужно хорошее решение, и вы в порядке с внешней зависимостью от старой библиотеки в режиме обслуживания, посмотрите на PeriodFormatter Joda-Time.

Вот пример использования TimeUnit для расчета частей для форматирования, как это предлагается в первом пункте:

    long totalSeconds = TimeUnit.MINUTES.toSeconds(5); // 300

    long minutes = TimeUnit.SECONDS.toMinutes(totalSeconds);
    long secondsPart = totalSeconds - TimeUnit.MINUTES.toSeconds(minutes);
    String formattedDuration = String.format("%02d:%02d", minutes, secondsPart);
    System.out.println("Formatted duration: " + formattedDuration);

Выход:

Форматированная продолжительность: 05: 00

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

В этом вопросе гораздо больше вдохновения, с которым я уже связался в комментарии. На момент написания у него было 20 ответов. Я повторяю ссылку внизу.

И, кстати, даже для форматирования и анализа дат и времени вы можете рассмотреть , не используя SimpleDateFormat. Это общеизвестно хлопотно и давно устарело. Вместо этого добавьте ThreeTenABP в свой проект Android, чтобы использовать java.time, современный Java-интерфейс даты и времени. Намного приятнее работать.

Ссылки

...