Рубрики
Без рубрики

Руководство по SimpleDateFormat

Краткое руководство по использованию SimpleDateFormat в Java.

Автор оригинала: Sam Millington.

1. введение

В этом уроке мы проведем углубленную экскурсию по классу SimpleDateFormat .

Мы рассмотрим простые экземпляры | и стили форматирования , а также полезные методы, которые класс предоставляет для обработки локалей и часовых поясов .

2. Простое Создание Экземпляра

Во-первых, давайте рассмотрим, как создать экземпляр нового объекта SimpleDateFormat .

Есть 4 возможных конструктора – но в соответствии с названием давайте все упростим. Все, что нам нужно для начала, – это Строка представление шаблона даты , который мы хотим .

Давайте начнем с шаблона даты, разделенного черточками, вот так:

"dd-MM-yyyy"

Это позволит правильно отформатировать дату, начиная с текущего дня месяца, текущего месяца года и, наконец, текущего года. Мы можем протестировать наш новый форматер с помощью простого модульного теста. Мы создадим новый объект SimpleDateFormat и передадим известную дату:

SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy");
assertEquals("24-05-1977", formatter.format(new Date(233345223232L)));

В приведенном выше коде форматер преобразует миллисекунды как длинные ong в читаемую человеком дату-24 мая 1977 года.

2.1. Заводские методы

Хотя SimpleDateFormat является удобным классом для быстрого создания средства форматирования данных, нам рекомендуется использовать заводские методы в DateFormat классе | getDateFormat () , getDateTimeFormat () , getTimeFormat() .

Приведенный выше пример выглядит немного иначе при использовании этих заводских методов:

DateFormat formatter = DateFormat.getDateInstance(DateFormat.SHORT);
assertEquals("5/24/77", formatter.format(new Date(233345223232L)));

Как видно из приведенного выше, количество параметров форматирования предопределено полями в классе DateFormat . Это в значительной степени ограничивает наши доступные варианты форматирования , поэтому в этой статье мы будем придерживаться SimpleDateFormat .

2.2. Безопасность резьбы

В JavaDoc для SimpleDateFormat явно указано:

Форматы дат не синхронизируются. Рекомендуется создавать отдельные экземпляры формата для каждого потока. Если несколько потоков одновременно обращаются к формату, он должен быть синхронизирован извне.

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

Лучший подход к решению этой проблемы состоит в том, чтобы использовать их в сочетании с ThreadLocal . Таким образом, каждый поток получает свой собственный экземпляр SimpleDateFormat , а отсутствие общего доступа делает программу потокобезопасной:

private final ThreadLocal formatter = ThreadLocal
  .withInitial(() -> new SimpleDateFormat("dd-MM-yyyy"));

Аргумент для метода with Initial является поставщиком экземпляров SimpleDateFormat . Каждый раз, когда ThreadLocal необходимо создать экземпляр, он будет использовать этого поставщика.

Затем мы можем использовать форматер через экземпляр ThreadLocal :

formatter.get().format(date)

Метод ThreadLocal.get() сначала инициализирует SimpleDateFormat для текущего потока, а затем повторно использует этот экземпляр.

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

Есть два других подхода к решению той же проблемы:

  • Использование синхронизированных блоков или ReentrantLock s
  • Создание ненужных экземпляров SimpleDateFormat по требованию

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

Стоит отметить, что начиная с Java 8, был введен новый DateTimeFormatter класс . Новый класс DateTimeFormatter является неизменяемым и потокобезопасным. Если мы работаем с Java 8 или более поздней версией, рекомендуется использовать новый класс DateTimeFormatter .

3. Анализ Дат

SimpleDateFormat и DateFormat не только позволяют нам форматировать даты, но мы также можем отменить операцию. Используя метод parse , мы можем ввести строковое представление даты и вернуть эквивалент даты объекта:

SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy");
Date myDate = new Date(233276400000L);
Date parsedDate = formatter.parse("24-05-1977");
assertEquals(myDate.getTime(), parsedDate.getTime());

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

4. Шаблоны Даты и времени

SimpleDateFormat предоставляет широкий спектр различных опций при форматировании дат. Хотя полный список доступен в JavaDocs , давайте рассмотрим некоторые из наиболее часто используемых опций:

M 12; Дек Месяц
y 94 год
d 23; Пн день
H 03 час
m 57 минута

Вывод , возвращаемый компонентом date, также сильно зависит от количества символов, используемых в строке . Например, возьмем июнь месяц. Если мы определим строку даты как:

"MM"

Тогда наш результат будет выглядеть как код номера – 06. Однако, если мы добавим еще один M в нашу строку даты:

"MMM"

Затем наши результирующие отформатированные данные отображаются в виде слова Jun .

5. Применение локализаций

Класс SimpleDateFormat также поддерживает широкий диапазон локализаций , который устанавливается при вызове конструктора.

Давайте применим это на практике, отформатировав дату на французском языке. Мы создадим экземпляр объекта SimpleDateFormat , предоставив Locale.ФРАНЦИЯ к конструктору.

SimpleDateFormat franceDateFormatter = new SimpleDateFormat("EEEEE dd-MMMMMMM-yyyy", Locale.FRANCE);
Date myWednesday = new Date(1539341312904L);
assertTrue(franceDateFormatter.format(myWednesday).startsWith("vendredi"));

Указав заданную дату, в среду днем, мы можем утверждать, что наш france DateFormatter правильно отформатировал дату. Новая дата правильно начинается с Vendredi -Французский для среды!

Стоит отметить небольшую ошибку в версии Locale конструкторахотя поддерживаются многие локали, полное покрытие не гарантируется . Oracle рекомендует использовать заводские методы в классе DateFormat для обеспечения локального покрытия.

6. Смена часовых Поясов

Поскольку SimpleDateFormat расширяет класс DateFormat , мы также можем манипулировать часовым поясом с помощью метода setTimeZone . Давайте посмотрим на это в действии:

Date now = new Date();

SimpleDateFormat simpleDateFormat = new SimpleDateFormat("EEEE dd-MMM-yy HH:mm:ssZ");

simpleDateFormat.setTimeZone(TimeZone.getTimeZone("Europe/London"));
logger.info(simpleDateFormat.format(now));

simpleDateFormat.setTimeZone(TimeZone.getTimeZone("America/New_York"));
logger.info(simpleDateFormat.format(now));

В приведенном выше примере мы поставляем одну и ту же Дату в два разных часовых пояса одного и того же объекта SimpleDateFormat . Мы также добавили символ ‘Z’ в конец шаблона String , чтобы указать различия в часовых поясах . Вывод из метода format затем регистрируется для пользователя.

Нажав run, мы можем увидеть текущее время относительно двух часовых поясов:

INFO: Friday 12-Oct-18 12:46:14+0100
INFO: Friday 12-Oct-18 07:46:14-0400

7. Резюме

В этом уроке мы глубоко погрузились в тонкости SimpleDateFormat .

Мы рассмотрели, как создать экземпляр SimpleDateFormat , а также как шаблон Строка влияет на форматирование даты .

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

Как всегда, полный исходный код можно найти на GitHub .