如何强制 LocalDateTime 月份为3个字母长

huangapple go评论138阅读模式
英文:

How to force LocalDateTime Month to be 3 letters long

问题

对于英语语言,这很容易:

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.
Juni → Jun.
Juli → Jul.

顺便说一下:这段代码是用Kotlin编写的,但Kotlin使用了Java的LocalDateTime。因此标记为Java。

编辑:我在Android 7.0上运行这段代码。

英文:

My goal is to use LocalDateTime and display a month with exactly 3 letters.

For the English language, this is easy:

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

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

The result is as expected:

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

For the German language (as above, only with Locale.GERMAN), the result is unexpected:

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

While the abbreviations are all common in german, "März", "Juni" and "Juli" haven't been shortened ("Mai" doesn't need to be shortened). Also, most month contain more than 3 letters (notice the dot!)

Is there a way to shorten those, two?
e.g.

>März ⇒ Mrz.
Juni ⇒ Jun.
Juli ⇒ Jul.

Btw: the code is in Kotlin, but Kotlin is using Java's LocalDateTime. Therefore tagged Java

Edit: i'm running this code on Android 7.0

答案1

得分: 1

Sure, here's the translated code portion:

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)
}

And the translated output:

八月
八月
英文:

You can have the desired / expected abbreviations like this:

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))
    }
}

the output comes as

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

LocalDateTime has a method getMonth() which returns a Month object, that means you can get the month of a LocalDateTime and build the desired String, maybe with a small fun like the following one

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

or even without a Locale as argument and a hard-coded Locale.GERMAN.

Don't really know why the German abbreviations are boiled down to 4 characters leaving month names with 4 or less characters as they are and abbreviate the remaining ones to three letters followed by a dot when you use a DateTimeFormatter with the pattern "MMM" on your system, in the Kotlin Playground, it doesn't! The following code produces two equal lines of output:

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)
}

which are (execution on 2020-08-12)

Aug
Aug

答案2

得分: 1

以下是翻译好的部分:

"Controlling exactly what month abbreviations Java gives you is hard, I don’t think you will want to bother. Java gets its locale data from up to four sources, and those sources generally come in versions. So even if you have managed to get your results exactly right, they may be different in the next Java version. I suggest that you choose between two options:

  1. Live with what you get. It’s well worked through and not unreasonable. Will any German have any trouble reading and understanding the abbreviations you mention?
  2. If you have very specific requirements for the abbreviations, such as Mrz rather than Mär, hardcode the abbreviations you require, and then you know they will stay that way no matter if the locale provider and/or the locale data version changes.

As a compromise between the two you may try to select the locale data provider through defining the system property java.locale.providers. As I said, the locale data you get from your provider may change in a future version.

If you want to hardcode your own preferred abbreviations, you can still build a DateTimeFormatter that uses your abbreviations. For a simple demonstration in 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.println(allAbbreviations);

Output is:

> Jan Feb Mrz Apr Mai Jun Jul Aug Sep Okt Nov Dez

The locale data providers are, from the documentation of LocaleServiceProvider:

> Java Runtime Environment provides the following four locale providers:
>
> - "CLDR": A provider based on Unicode Consortium's CLDR Project.
> - "COMPAT": represents the locale sensitive services that is compatible with the prior JDK releases up to JDK8 (same as JDK8's
> "JRE").
> - "SPI": represents the locale sensitive services implementing the subclasses of this LocaleServiceProvider class.
> - "HOST": A provider that reflects the user's custom settings in the underlying operating system. This provider may not be available,
> depending on the Java Runtime Environment implementation.
> - "JRE": represents a synonym to "COMPAT". This name is deprecated and will be removed in the future release of JDK."

英文:

Controlling exactly what month abbreviations Java gives you is hard, I don’t think you will want to bother. Java gets its locale data from up to four sources, and those sources generally come in versions. So even if you have managed to get your results exactly right, they may be different in the next Java version. I suggest that you choose between two options:

  1. Live with what you get. It’s well worked through and not unreasonable. Will any German have any trouble reading and understanding the abbreviations you mention?
  2. If you have very specific requirements for the abbreviations, such as Mrz rather than Mär, hardcode the abbreviations you require, and then you know they will stay that way no matter if the locale provider and/or the locale data version changes.

As a compromise between the two you may try to select the locale data provider through defining the system property java.locale.providers. As I said, the locale data you get from your provider may change in a future version.

If you want to hardcode your own preferred abbreviations, you can still build a DateTimeFormatter that uses your abbreviations. For a simple demonstration in 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);

Output is:

> Jan Feb Mrz Apr Mai Jun Jul Aug Sep Okt Nov Dez

The locale data providers are, from the documentation of LocaleServiceProvider:

> Java Runtime Environment provides the following four locale providers:
>
> - "CLDR": A provider based on Unicode Consortium's CLDR Project.
> - "COMPAT": represents the locale sensitive services that is compatible with the prior JDK releases up to JDK8 (same as JDK8's
> "JRE").
> - "SPI": represents the locale sensitive services implementing the subclasses of this LocaleServiceProvider class.
> - "HOST": A provider that reflects the user's custom settings in the underlying operating system. This provider may not be available,
> depending on the Java Runtime Environment implementation.
> - "JRE": represents a synonym to "COMPAT". This name is deprecated and will be removed in the future release of JDK.

huangapple
  • 本文由 发表于 2020年8月12日 18:58:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/63375108.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定