Как получить локализованную строку шаблона даты?
Очень легко форматировать и анализировать классы Java Date (или Calendar), используя экземпляр DateFormat, то есть я мог форматировать текущую дату в короткую локализованную дату:
DateFormat formatter = DateFormat.getDateInstance(DateFormat.SHORT, Locale.getDefault());
String today = formatter.format(new Date());
Моя проблема: мне нужно получить эту локализованную строку шаблона (например, что-то вроде "MM/dd/yy"
). Это должно быть тривиальной задачей, но я просто не мог найти поставщика...
Ответы
Ответ 1
Для SimpleDateFormat вы вызываете toLocalizedPattern()
EDIT:
Для пользователей Java 8:
API-интерфейс Java 8 Date Time похож на Joda-time. Чтобы получить локализованный шаблон, мы можем использовать класс
DateTimeFormatter
DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM);
Обратите внимание, что когда вы вызываете toString() в LocalDate, вы получите дату в формате ISO-8601
Обратите внимание, что API Time Time в Java 8 вдохновлен Joda Time, и большинство решений могут основываться на вопросах, связанных с временем.
Ответ 2
Для тех, кто по-прежнему использует Java 7 и старше:
Вы можете использовать что-то вроде этого:
DateFormat formatter = DateFormat.getDateInstance(DateFormat.SHORT, Locale.getDefault());
String pattern = ((SimpleDateFormat)formatter).toPattern();
String localPattern = ((SimpleDateFormat)formatter).toLocalizedPattern();
Так как DateFormat
, возвращаемый From getDateInstance()
, является экземпляром SimpleDateFormat
.
Эти два метода действительно должны быть в DateFormat, чтобы это было менее хаки, но в настоящее время они не являются.
Ответ 3
Возможно, странно, что я отвечаю на свой вопрос, но я верю, что могу добавить что-то к картине.
Внедрение ICU
Очевидно, что Java 8 дает вам много, но есть и еще что-то: ICU4J. На самом деле это источник оригинальной реализации Java таких вещей, как Calendar
, DateFormat
и SimpleDateFormat
, чтобы назвать несколько.
Поэтому не должно быть неожиданностью, что ICU SimpleDateFormat также содержит методы, такие как toPattern()
или toLocalizedPattern()
. Вы можете увидеть их в действии здесь:
DateFormat fmt = DateFormat.getPatternInstance(
DateFormat.YEAR_MONTH,
Locale.forLanguageTag("pl-PL"));
if (fmt instanceof SimpleDateFormat) {
SimpleDateFormat sfmt = (SimpleDateFormat) fmt;
String pattern = sfmt.toPattern();
String localizedPattern = sfmt.toLocalizedPattern();
System.out.println(pattern);
System.out.println(localizedPattern);
}
усовершенствования ICU
Это ничего нового, но я хотел бы отметить это:
DateFormat.getPatternInstance(String pattern, Locale locale);
Это метод, который может возвращать целую кучу специфичных для локали шаблонов, таких как:
- ABBR_QUARTER
- КВАРТАЛ
- год
- YEAR_ABBR_QUARTER
- YEAR_QUARTER
- YEAR_ABBR_MONTH
- YEAR_MONTH
- YEAR_NUM_MONTH
- YEAR_ABBR_MONTH_DAY
- YEAR_NUM_MONTH_DAY
- YEAR_MONTH_DAY
- YEAR_ABBR_MONTH_WEEKDAY_DAY
- YEAR_MONTH_WEEKDAY_DAY
- YEAR_NUM_MONTH_WEEKDAY_DAY
- ABBR_MONTH
- МЕСЯЦ
- NUM_MONTH
- ABBR_STANDALONE_MONTH
- STANDALONE_MONTH
- ABBR_MONTH_DAY
- MONTH_DAY
- NUM_MONTH_DAY
- ABBR_MONTH_WEEKDAY_DAY
- MONTH_WEEKDAY_DAY
- NUM_MONTH_WEEKDAY_DAY
- ДЕНЬ
- ABBR_WEEKDAY
- WEEKDAY
- ЧАС
- HOUR24
- HOUR_MINUTE
- HOUR_MINUTE_SECOND
- HOUR24_MINUTE
- HOUR24_MINUTE_SECOND
- HOUR_TZ
- HOUR_GENERIC_TZ
- HOUR_MINUTE_TZ
- HOUR_MINUTE_GENERIC_TZ
- МИНУТА
- MINUTE_SECOND
- ВТОРОЕ
- ABBR_UTC_TZ
- ABBR_SPECIFIC_TZ
- SPECIFIC_TZ
- ABBR_GENERIC_TZ
- GENERIC_TZ
- LOCATION_TZ
Конечно, их немало. Что хорошо в них, так это то, что эти шаблоны фактически являются строками (как в java.lang.String
), то есть, если вы используете английский шаблон "MM/d"
, вы получите обратную привязку к языку. Это может быть полезно в некоторых случаях. Обычно вы просто используете экземпляр DateFormat
и не будете заботиться о самом шаблоне.
Локально-специфичный шаблон против локализованного шаблона
Задача заключалась в том, чтобы получить локализацию, а не шаблон, специфичный для локали. Какая разница?
В теории, toPattern()
даст вам специфичный для локали шаблон (в зависимости от Locale
, который вы использовали для создания экземпляра (Simple)DateFormat
). То есть независимо от того, какой целевой язык/страна вы положили, вы получите шаблон, составленный из таких символов, как y
, M
, d
, h
, h
, M
и т.д.
С другой стороны, toLocalizedPattern()
должен возвращать локализованный шаблон, это то, что подходит для конечных пользователей для чтения и понимания. Например, немецкий шаблон даты (по умолчанию):
- toPattern(): dd.MM.yyyy
- toLocalizedPattern(): tt.MM.jjjj(day = Tag, month = Monat, year = Jahr)
Цель вопроса заключалась в следующем: "как найти локализованный шаблон, который может служить подсказкой о том, какой формат даты/времени". То есть, скажем, у нас есть поле даты, которое пользователь может заполнить, используя шаблон, специфичный для локали, но я хочу отобразить подсказку формата в локализованной форме.
К сожалению, до сих пор нет хорошего решения. Я уже упоминал ранее в этом сообщении ICU. Это потому, что данные, которые использует ICU, поступают из CLDR, что, к сожалению, частично переведено/частично исправлено. В случае моего родного языка, на момент написания, ни шаблоны, ни их локализованные формы не были правильно переведены. И каждый раз, когда я их исправляю, меня обманывали другие люди, которым не нужно жить в Польше, и не говорят на польском языке...
Мораль этой истории: не полностью полагаться на CLDR. Вам все еще нужно иметь локальных аудиторов/лингвистических обозревателей.
Ответ 4
Вы можете использовать DateTimeFormatterBuilder в Java 8. В следующем примере возвращается шаблон с локализованной датой, например. "d.M.yyyy"
.
String datePattern = DateTimeFormatterBuilder.getLocalizedDateTimePattern(
FormatStyle.SHORT, null, IsoChronology.INSTANCE,
Locale.GERMANY); // or whatever Locale
Ответ 5
Следующий код даст вам шаблон для локали:
final String pattern1 = ((SimpleDateFormat) DateFormat.getDateInstance(DateFormat.SHORT, locale)).toPattern();
System.out.println(pattern1);
Ответ 6
Java 8 предоставляет некоторые полезные функции для работы с датой и временем форматирования/синтаксического анализа, включая обработку локалей. Вот краткое введение.
Основные шаблоны
В простейшем случае для форматирования/анализа даты вы использовали бы следующий код с шаблоном String:
DateTimeFormatter.ofPattern("MM/dd/yyyy")
Стандарт затем должен использовать это с объектом даты непосредственно для форматирования:
return LocalDate.now().format(DateTimeFormatter.ofPattern("MM/dd/yyyy"));
И затем используя шаблон factory для синтаксического анализа даты:
return LocalDate.parse(dateString, DateTimeFormatter.ofPattern("MM/dd/yyyy"));
У самого шаблона есть большое количество опций, которые будут охватывать большинство случаев использования, полное расписание можно найти в местоположении javadoc здесь.
Locales
Включение локали довольно просто: для языкового стандарта по умолчанию у вас есть следующие параметры, которые затем могут быть применены к параметрам форматирования/анализа, показанным выше:
DateTimeFormatter.ofLocalizedDate(dateStyle);
Параметр 'dateStyle' выше FormatStyle параметр Enum для представления полной, длинной, средней и короткой версий локализованной даты, когда работая с DateTimeFormatter
. Используя FormatStyle, у вас также есть следующие опции:
DateTimeFormatter.ofLocalizedTime(timeStyle);
DateTimeFormatter.ofLocalizedDateTime(dateTimeStyle);
DateTimeFormatter.ofLocalizedDateTime(dateTimeStyle, timeStyle);
Последняя опция позволяет вам указать другую FormatStyle для даты и времени. Если вы не работаете с Locale по умолчанию, возврат каждого из методов Localized можно настроить с помощью опции .withLocale, например,
DateTimeFormatter.ofLocalizedTime(timeStyle).withLocale(Locale.ENGLISH);
Кроме того, у параметраPattern есть перегруженная версия, чтобы указать язык тоже
DateTimeFormatter.ofPattern("MM/dd/yyyy",Locale.ENGLISH);
Мне нужно больше!
DateTimeFormatter будет соответствовать большинству вариантов использования, однако он построен на DateTimeFormatterBuilder, который предоставляет пользователю огромный выбор опций строителя. Используйте DateTimeFormatter
для начала, и если вам нужны эти расширенные функции форматирования, возвращайтесь к строителю.
Ответ 7
Поскольку это только информация о локали, которую вы используете, я думаю, что вам нужно будет найти файл, который JVM (OpenJDK или Harmony) фактически использует в качестве входных данных для всего объекта Locale
и выясняет, как разобрать его. Или просто используйте другой источник в Интернете (наверняка там есть список). Это спасет этих бедных переводчиков.
Ответ 8
В нижеследующем коде, который принимает экземпляр локали и возвращает формат/шаблон данных конкретной локали, вы найдете.
public static String getLocaleDatePattern(Locale locale) {
// Validating if Locale instance is null
if (locale == null || locale.getLanguage() == null) {
return "MM/dd/yyyy";
}
// Fetching the locale specific date pattern
String localeDatePattern = ((SimpleDateFormat) DateFormat.getDateInstance(
DateFormat.SHORT, locale)).toPattern();
// Validating if locale type is having language code for Chinese and country
// code for (Hong Kong) with Date Format as - yy'?'M'?'d'?'
if (locale.toString().equalsIgnoreCase("zh_hk")) {
// Expected application Date Format for Chinese (Hong Kong) locale type
return "yyyy'MM'dd";
}
// Replacing all d|m|y OR Gy with dd|MM|yyyy as per the locale date pattern
localeDatePattern = localeDatePattern.replaceAll("d{1,2}", "dd").replaceAll(
"M{1,2}", "MM").replaceAll("y{1,4}|Gy", "yyyy");
// Replacing all blank spaces in the locale date pattern
localeDatePattern = localeDatePattern.replace(" ", "");
// Validating the date pattern length to remove any extract characters
if (localeDatePattern.length() > 10) {
// Keeping the standard length as expected by the application
localeDatePattern = localeDatePattern.substring(0, 10);
}
return localeDatePattern;
}
Ответ 9
Вы можете попробовать что-то вроде:
LocalDate fromCustomPattern = LocalDate.parse("20.01.2014", DateTimeFormatter.ofPattern("MM/dd/yy"))
Ответ 10
Я не уверен, что вы хотите, но...
Пример SimpleDateFormat:
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yy");
Date date = sdf.parse("12/31/10");
String str = sdf.format(new Date());