如何获取本地化的日期模式字符串?

Paw*_*yda 45 java datetime localization internationalization

使用DateFormat的实例格式化和解析Java Date(或Calendar)类非常容易,即我可以将当​​前日期格式化为短的本地化日期,如下所示:

DateFormat formatter = DateFormat.getDateInstance(DateFormat.SHORT, Locale.getDefault());
String today = formatter.format(new Date());
Run Code Online (Sandbox Code Playgroud)

我的问题是:我需要获得这个本地化的模式字符串(即类似的东西"MM/dd/yy").这应该是一项微不足道的任务,但我找不到提供者......

Dam*_*ash 36

对于SimpleDateFormat,您调用toLocalizedPattern()

编辑:

对于Java 8用户:

Java 8 Date Time API类似于Joda-time.要获得本地化模式,我们可以使用类 DateTimeFormatter

DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM);

请注意,当您在LocalDate上调用toString()时,您将获得ISO-8601格式的日期

请注意,Java 8中的Date Time API受Joda Time的启发,大多数解决方案可以基于与时间相关的问题.

  • Java 8 DateTimeFormatter 的问题在于无法从中获取原始模式:/sf/ask/2026442561/ (3认同)

Zar*_*rok 31

对于那些仍在使用Java 7及更早版本的人:

你可以使用这样的东西:

DateFormat formatter = DateFormat.getDateInstance(DateFormat.SHORT, Locale.getDefault());
String pattern       = ((SimpleDateFormat)formatter).toPattern();
String localPattern  = ((SimpleDateFormat)formatter).toLocalizedPattern();
Run Code Online (Sandbox Code Playgroud)

由于DateFormat返回的From getDateInstance()是实例SimpleDateFormat.这两种方法实际上也应该在DateFormat中,因为这样做不那么hacky,但它们目前不是.


Paw*_*yda 21

可能很奇怪,我正在回答我自己的问题,但我相信,我可以在图片中添加一些内容.

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);
}
Run Code Online (Sandbox Code Playgroud)

ICU增强功能

这不是什么新鲜事,但我真正想指出的是:

DateFormat.getPatternInstance(String pattern, Locale locale);
Run Code Online (Sandbox Code Playgroud)

这是一种可以返回一大堆特定于语言环境的模式的方法,例如:

  • ABBR_QUARTER
  • 25美分硬币
  • YEAR_ABBR_QUARTER
  • YEAR_QUARTER
  • YEAR_ABBR_MONTH
  • YEAR_MONTH
  • YEAR_NUM_MONTH
  • YEAR_ABBR_MONTH_DAY
  • YEAR_NUM_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
  • 月日
  • 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.您仍需要当地审核员/语言审核员.


小智 11

您可以在Java 8中使用DateTimeFormatterBuilder.以下示例仅返回本地化日期模式,例如"d.M.yyyy".

String datePattern = DateTimeFormatterBuilder.getLocalizedDateTimePattern(
  FormatStyle.SHORT, null, IsoChronology.INSTANCE, 
  Locale.GERMANY); // or whatever Locale
Run Code Online (Sandbox Code Playgroud)

  • 这不能按预期工作.对于locale`德国`我得到`dd.MM.yy`,但是`((SimpleDateFormat)DateFormat.getDateInstance(DateFormat.SHORT,Locale.GERMANY)).toLocalizedPattern()`给出`tt.MM.uu`作为结果.此方法将使用格式字符作为`SimpleDateFormat`的specid返回模式,而不是指定语言环境的格式字符. (2认同)

小智 6

以下代码将为您提供语言环境的模式:

final String pattern1 = ((SimpleDateFormat) DateFormat.getDateInstance(DateFormat.SHORT, locale)).toPattern();
System.out.println(pattern1);
Run Code Online (Sandbox Code Playgroud)

  • 我不认为这是安全的.您正在转换为JRE的实现细节.JRE可以随时更改用于实现`DateFormat.getDateInstance`的类,从而导致类强制转换异常. (2认同)

Jim*_*Jim 6

Java 8 提供了一些开箱即用的有用功能,用于处理和格式化/解析日期和时间,包括处理区域设置。这里简单介绍一下。

基本模式

在最简单的情况下,要格式化/解析日期,您可以使用以下具有字符串模式的代码:

DateTimeFormatter.ofPattern("MM/dd/yyyy")
Run Code Online (Sandbox Code Playgroud)

标准是直接将其与日期对象一起使用进行格式化:

return LocalDate.now().format(DateTimeFormatter.ofPattern("MM/dd/yyyy"));
Run Code Online (Sandbox Code Playgroud)

然后使用工厂模式来解析日期:

return LocalDate.parse(dateString, DateTimeFormatter.ofPattern("MM/dd/yyyy"));
Run Code Online (Sandbox Code Playgroud)

该模式本身有大量选项,可以覆盖大多数用例,可以在此处的javadoc 位置找到完整的概要。

区域设置

包含区域设置相当简单,对于默认区域设置,您可以使用以下选项,然后将它们应用于上面演示的格式/解析选项:

DateTimeFormatter.ofLocalizedDate(dateStyle);
Run Code Online (Sandbox Code Playgroud)

上面的“dateStyle”是一个FormatStyle选项枚举,用于表示使用DateTimeFormatter. 使用FormatStyle您还可以选择以下选项:

DateTimeFormatter.ofLocalizedTime(timeStyle);
DateTimeFormatter.ofLocalizedDateTime(dateTimeStyle);
DateTimeFormatter.ofLocalizedDateTime(dateTimeStyle, timeStyle);
Run Code Online (Sandbox Code Playgroud)

最后一个选项允许您为日期和时间指定不同的FormatStyle 。如果您不使用默认的区域设置,则可以使用 .withLocale 选项调整每个本地化方法的返回,例如

DateTimeFormatter.ofLocalizedTime(timeStyle).withLocale(Locale.ENGLISH);
Run Code Online (Sandbox Code Playgroud)

或者 ofPattern 有一个重载版本来指定区域设置

DateTimeFormatter.ofPattern("MM/dd/yyyy",Locale.ENGLISH);
Run Code Online (Sandbox Code Playgroud)

我需要更多!

DateTimeFormatter 将满足大多数用例,但它是基于DateTimeFormatterBuilder构建的,后者为构建器的用户提供了大量选项。首先使用DateTimeFormatter,如果您需要这些广泛的格式化功能,请回退到构建器。

  • 这没有解决问题。 (3认同)

Din*_*mte 5

请在下面的代码中找到它接受区域设置实例并返回区域设置特定的数据格式/模式。

 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;
}
Run Code Online (Sandbox Code Playgroud)