【问题标题】:How to force LocalDateTime Month to be 3 letters long如何强制 LocalDateTime Month 为 3 个字母长
【发布时间】:2020-08-12 10:58:10
【问题描述】:

我的目标是使用 LocalDateTime 并显示恰好包含 3 个字母的月份。

对于英语来说,这很容易:

val englishFormatter = DateTimeFormatter.ofPattern("MMM", Locale.ENGLISH)

for (month in 1..12) {
    println(LocalDateTime.of(0, month, 1, 0, 0)
                         .format(englishFormatter))
}

结果如预期:

Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec

对于德语(如上,仅使用Locale.GERMAN),结果出乎意料:

Jan. Feb. März Apr. Mai Juni Juli Aug. Sep. Okt. Nov. Dez.

虽然缩写在德语中都很常见,但“März”、“Juni”和“Juli”并未缩短(“Mai”不需要缩短)。此外,大多数月份包含超过 3 个字母(注意点!)

有没有办法缩短这两个?
例如

März ⇒ Mrz.
六月 ⇒ 六月。
七月⇒七月。

顺便说一句:代码在 Kotlin 中,但 Kotlin 使用的是 Java 的 LocalDateTime。因此标记为 Java

编辑:我在 Android 7.0 上运行此代码

【问题讨论】:

  • 你必须做类似this的事情。
  • 作为替代方案,您可以提取LocalDateTimeMonth 并通过month.getDisplayName(TextStyle.SHORT, Locale.GERMAN) 找到所需的缩写...
  • 我用 java 测试了你的代码,它是正确的。我认为这不是 java 的问题。
  • 这是 3 字符 abb 的已知问题。使用 MMM 和 Java 中的任何日期时间格式化 API(旧版或新版)的月份名称。可能你错过了检查stackoverflow.com/questions/1635681/…

标签: java datetime


【解决方案1】:

准确控制 Java 给你的月份缩写很难,我认为你不会想打扰。 Java 从最多四个来源获取其语言环境数据,这些来源通常有不同的版本。因此,即使您已经设法得到完全正确的结果,它们在下一个 Java 版本中可能会有所不同。我建议您在两个选项之间进行选择:

  1. 接受你所得到的。它工作得很好,而且不是不合理的。任何德国人在阅读和理解您提到的缩写时会遇到困难吗?
  2. 如果您对缩写有非常具体的要求,例如 Mrz 而不是 Mär,请将所需的缩写硬编码,然后您就知道无论语言环境提供者和/或语言环境如何,它们都会保持这种状态数据版本更改。

作为两者之间的折衷方案,您可以尝试通过定义系统属性java.locale.providers 来选择语言环境数据提供者。正如我所说,您从提供商处获得的语言环境数据可能会在未来的版本中发生变化。

如果您想硬编码自己喜欢的缩写,您仍然可以构建一个使用您的缩写的DateTimeFormatter。用 Java 做一个简单的演示:

    Map<Long, String> monthAbbreviations = Map.ofEntries(
            Map.entry(1L, "Jan"), Map.entry(2L, "Feb"), Map.entry(3L, "Mrz"),
            Map.entry(4L, "Apr"), Map.entry(5L, "Mai"), Map.entry(6L, "Jun"),
            Map.entry(7L, "Jul"), Map.entry(8L, "Aug"), Map.entry(9L, "Sep"),
            Map.entry(10L, "Okt"), Map.entry(11L, "Nov"), Map.entry(12L, "Dez"));
    DateTimeFormatter formatter = new DateTimeFormatterBuilder()
            .appendText(ChronoField.MONTH_OF_YEAR, monthAbbreviations)
            .toFormatter(Locale.GERMAN);
    
    String allAbbreviations = Arrays.stream(Month.values())
            .map(formatter::format)
            .collect(Collectors.joining(" "));
    System.out.println(allAbbreviations);

输出是:

一月 二月 Mrz Apr Mai Jun Jul Aug Sep Okt Nov Dez

语言环境数据提供者来自LocaleServiceProvider的文档:

Java 运行时环境提供以下四个语言环境提供程序:

  • “CLDR”:基于 Unicode 联盟的 CLDR 项目的提供程序。
  • “COMPAT”:表示与以前的 JDK 版本兼容的区域设置敏感服务,直到 JDK8(与 JDK8 相同) “JRE”)。
  • “SPI”:表示实现此 LocaleServiceProvider 类的子类的区域设置敏感服务。
  • “HOST”:在底层操作系统中反映用户自定义设置的提供程序。此提供程序可能不可用, 取决于 Java 运行时环境的实现。
  • “JRE”:表示“COMPAT”的同义词。此名称已弃用,将在 JDK 的未来版本中删除。

链接

【讨论】:

    【解决方案2】:

    您可以使用这样的所需/预期的缩写:

    import java.time.LocalDateTime
    import java.time.Month
    import java.time.format.TextStyle
    import java.util.Locale
    
    fun main() {
        for (m in 1..12) {
            val month = Month.of(m)
            println(month.getDisplayName(TextStyle.SHORT, Locale.GERMAN))
        }
    }
    

    输出为

    Jan
    Feb
    Mär
    Apr
    Mai
    Jun
    Jul
    Aug
    Sep
    Okt
    Nov
    Dez
    

    LocalDateTime 有一个 getMonth() 方法,它返回一个 Month 对象,这意味着您可以获得 LocalDateTime 的月份并构建所需的 String,可能使用一个小的 fun,如下所示一个

    fun getAbbreviatedMonth(localDateTime: LocalDateTime, locale: Locale): String {
        return localDateTime.getMonth()
                            .getDisplayName(TextStyle.SHORT, locale)
    }
    

    甚至没有Locale 作为参数和一个硬编码 Locale.GERMAN

    真的不知道为什么德语缩写被归结为 4 个字符,而月份名称则保留 4 个或更少的字符,而当您使用 DateTimeFormatter 和模式"MMM" 在您的系统上,在 Kotlin Playground 中,它没有!以下代码产生两行相等的输出:

    import java.time.LocalDateTime
    import java.time.Month
    import java.time.format.TextStyle
    import java.util.Locale
    import java.time.format.DateTimeFormatter
    
    fun main() {
        var localDateTime = LocalDateTime.now()
        println(getAbbreviatedMonth(localDateTime, Locale.GERMAN))
        println(localDateTime.format(DateTimeFormatter.ofPattern("MMM", Locale.GERMAN)))
    }
    
    fun getAbbreviatedMonth(localDateTime: LocalDateTime, locale: Locale): String {
        return localDateTime.getMonth()
                            .getDisplayName(TextStyle.SHORT, locale)
    }
    

    是(2020-08-12 执行)

    Aug
    Aug
    

    【讨论】:

    • 天哪,我没想到这可能是特定于平台的,甚至是特定于设备的。我在 Android 应用程序中使用这个 Kotlin 代码。在这个 Android 应用程序中,getAbbreviatedMonth() 也产生与我的版本相同(意外)的结果。惭愧:(
    • @m.reiter 然后尝试通过使用意外输出并获取它的substring(0, 3) 来绕过它...目前对此没有更多想法...跨度>
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-27
    • 2019-08-25
    相关资源
    最近更新 更多