Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to obtain the locale date format on month and day

Im using Joda Time to format the dateTime as following:

DateTimeFormatter dateFormatter = DateTimeFormat.longDate();
String startTimeStr = dateFormatter.print(localStartTime);

The variables's values are:

localStartTime={org.joda.time.LocalDateTime@830018681648}"2013-04-06T23:54:35.000"
startTimeStr={java.lang.String@830018688880}"2013年4月6日"

Problem is how could I obtain the locale date format on month and day? I have tried the following codes:

DateTimeFormatter monDayFormatter = DateTimeFormat.forPattern("MMMd");
String startTimeStr = monDayFormatter.print(localStartTime);

and the variables's values are:

localStartTime={org.joda.time.LocalDateTime@830018681648}"2013-04-06T23:54:35.000"
startTimeStr={java.lang.String@830018683220}"4月6"

What I expected startTimeStr is 4月6日. Here the Chinese character = Day. I do not want to hard code the pattern to "MMMd日", because it should adjust itself according to the current locale information. Any help will be appreciated.

like image 727
lu yuan Avatar asked Mar 21 '23 15:03

lu yuan


1 Answers

On the website of unicode consortium, you will find in Chinese CLDR repository for example entries like follows (calendar type = gregorian):

<dateFormats>
  <dateFormatLength type="full">
     <dateFormat>
    <pattern>y年M月d日EEEE</pattern>
     </dateFormat>
  </dateFormatLength>
  <dateFormatLength type="long">
     <dateFormat>
        <pattern>y年M月d日</pattern>
     </dateFormat>
  </dateFormatLength>
  <dateFormatLength type="medium">
     <dateFormat>
       <pattern>y年M月d日</pattern>
     </dateFormat>
  </dateFormatLength>
  <dateFormatLength type="short">
     <dateFormat>
       <pattern>yy/M/d</pattern>
     </dateFormat>
  </dateFormatLength>
</dateFormats>

Internally every localized date format either in JodaTime or in JDK dateformat classes will be translated to such a pattern - including literals like "日". CLDR does not define a month-day-only-format, but this is just a part of a general year-month-day-format, so if you use as replacement for

DateTimeFormatter dateFormatter = DateTimeFormat.longDate().withLocale(Locale.CHINESE);
LocalDateTime localStartTime = new LocalDateTime(2013,4,6,23,54,35);
String startTimeStr = dateFormatter.print(localStartTime);
System.out.println(startTimeStr); // output: 2013年4月6日

this code:

DateTimeFormatter dateFormatter = DateTimeFormat.forPattern("M月d日");
LocalDateTime localStartTime = new LocalDateTime(2013,4,6,23,54,35);
String startTimeStr = dateFormatter.print(localStartTime);
System.out.println(startTimeStr); // output: 4月6日

then you get what you want. Although you write:

I do not want to hard code the pattern to "MMMd日"

that is pretty much the same procedure as done internally by libraries. So the pattern itself is localized by choosing the appropriate literals. There is no way to extract from CLDR a localized date pattern without year. If you want this, then you have to manage your own set of localized month-day-patterns for different locales, maybe in a Map<Locale, String>.

Update from 2016-12-06:

The situation not having a generic month-day-pattern for any locale has not changed for Joda-Time. Unfortunately the official successor of Joda-Time, the JSR-310 (java.time-package) does not manage it well, too, see the JDK-issue 8168532. This was reason enough for me to find a solution for my own time library Time4J in the mean-time. A close analysis of CLDR data has shown that there are other date formats available for many languages, but in a different section and accessible via a group of fields. The keys "Md", "MMMd" and "MMMMd" are relevant for your use-case. Example in Time4J (which should hopefully be supported by JSR-310, too, in a future release):

    PlainTimestamp tsp = Iso8601Format.EXTENDED_DATE_TIME.parse("2013-04-06T23:54:35.000");
    AnnualDate ad = AnnualDate.of(tsp.getMonth(), tsp.getDayOfMonth());
    ChronoFormatter<AnnualDate> chinese =
        ChronoFormatter.ofStyle(DisplayMode.LONG, Locale.CHINESE, AnnualDate.chronology());
    ChronoFormatter<AnnualDate> english =
        ChronoFormatter.ofStyle(DisplayMode.LONG, Locale.ENGLISH, AnnualDate.chronology());
    System.out.println(chinese.format(ad)); // 4月6日
    System.out.println(english.format(ad)); // Apr 6

It is also worth to note that the locale cannot be changed after construction of formatter in a sensible way because the localized pattern structure will be freezed during construction and is no longer sensible for later changes of locale. This will be improved in future release, however.

like image 55
Meno Hochschild Avatar answered Apr 02 '23 19:04

Meno Hochschild