Java dateformat незаконный шаблонный символ 'y'

В последнее время у нас возникла странная ошибка в рабочей среде (тестовые среды отлично работают).

java.lang.IllegalArgumentException: символ нелегального шаблона 'y'

Это вызвано следующим кодом

SimpleDateFormat dateFormat = (SimpleDateFormat)DateFormat.getDateInstance();
dateFormat.applyLocalizedPattern("yyyy-MM-dd");

Эта ошибка обычно возникает, если, например, использовать "Y" вместо "y" в течение года. Это не так, как вы можете видеть выше. Я не уверен на 100% от локали, установленной на сервере. Linux env LANG установлен на "de_DE.UTF_8", поэтому это, вероятно, используется.

Ввод исходного кода SimpleDateFormat.java Я нашел метод translatePattern(String pattern, String from, String to). Это исключает упомянутое исключение, если какой-либо символ из pattern не существует. Значения выглядят как это при отладке локально на другом компьютере

pattern = "yyyy-MM-dd"
from = "GyMdkHmsSEDFwWahKzZ"

Из исключения на сервере видно, что первый "y" не существует в from. from извлекается из formatData.getLocalPatternChars(), который является DateFormatSymbols, инициализированным из локали на сервере.

Доступны ли даже локали, которые могут иметь форматы без 'y'? Эта ошибка началась без какого-либо изменения кода, и, насколько мне известно, изменение конфигурации сервера не было.

Ответ 1

Из SimpleDateFormat javadoc:

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

В вашем случае местным является DE, поэтому локализованный шаблон будет jjjj-MM-tt. J обозначает Jahr и T для Tage.

Если вы не хотите иметь дело с локализованным шаблоном, просто используйте SimpleDateFormat.applyPattern( "yyyy-MM-dd" ).

Ответ 2

В идеале вы должны применять локали шаблона, иначе ваш шаблон должен измениться для разных локалей, поскольку yyyy работает для en_US, jjjj для de_DE и т.д. Вместо этого укажите только yyyy и locale как en_US независимо от языка вашей машины.

SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH);
System.out.println(format.format(new java.util.Date()));

Как говорит javadoc:

Создает SimpleDateFormat с использованием заданного шаблона и значения по умолчанию символы формата даты для данного языка. Примечание. Этот конструктор может не поддерживает все локали. Для полного охвата используйте методы factory в класс DateFormat.

Параметры:

pattern: шаблон, описывающий формат даты и времени

locale: язык, в котором должны использоваться символы формата даты

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