How do I get localized date pattern string?
Asked Answered
D

10

55

It is quite easy to format and parse Java Date (or Calendar) classes using instances of DateFormat.

I could format the current date into a short localized date like this:

DateFormat formatter = DateFormat.getDateInstance(DateFormat.SHORT, Locale.getDefault());
String today = formatter.format(new Date());

My problem is that I need to obtain this localized pattern string (something like "MM/dd/yy").

This should be a trivial task, but I just couldn't find the provider.

Disfeature answered 4/1, 2011 at 14:11 Comment(8)
java.text.SimpleDateFormat lets you specify your own date format.Sappington
Yes, also FastDateFormat. I am asking on how to read localized date formats used by Java classes internally. I know how to format dates, I need pattern for other purposes.Massacre
I am pretty sure there is no way you can access these patterns. What do you need them for?Obaza
OK, so you don't want a DateFormat, you want the SimpleDateFormat-compatible 'pattern' that the DateFormat instance returned by DateFormat.getDateInstance(DateFormat.SHORT, Locale.getDefault()) actually uses internally?Sappington
That's what I was afraid of. Let's say I would like to use them as 1) Hint for user 2) Input for JQuery Datepicker. But it seems I have no choice but force translators to provide such patterns (poor Localization guys, they will have few bugs to fix).Massacre
Right. I've tried to debug DateFormat, but failed miserably...Massacre
I suspect it's a lost cause. I could only possibly, tentatively suggest that there is a ResourceBundle keyed by Locale that the JVM will have access to. But it's unlikely to be a supported API, and you're best off not doing it.Sappington
docs.oracle.com/javase/tutorial/i18n/format/dateFormat.html might help. You requirement looks like the SHORT one. Some old code from sun to check the patterns: java2s.com/Code/Java/Data-Type/DateFormatwithLocale.htmLindseylindsley
C
40

For SimpleDateFormat, You call toLocalizedPattern()

EDIT:

For Java 8 users:

The Java 8 Date Time API is similar to Joda-time. To gain a localized pattern we can use class DateTimeFormatter

DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM);

Note that when you call toString() on LocalDate, you will get date in format ISO-8601

Note that Date Time API in Java 8 is inspired by Joda Time and most solution can be based on questions related to time.

Crossexamine answered 4/1, 2011 at 14:56 Comment(2)
It seems like I accidentally downvoted this answer and can't undo until it's edited. Maybe you can add that for JodaTime you can use DateTimeFormat.patternForStyle(style, locale); :)Peskoff
The problem with Java 8 DateTimeFormatter is that there is no way how to get the original pattern from it: #28949679Expertise
B
35

For those still using Java 7 and older:

You can use something like this:

DateFormat formatter = DateFormat.getDateInstance(DateFormat.SHORT, Locale.getDefault());
String pattern       = ((SimpleDateFormat)formatter).toPattern();
String localPattern  = ((SimpleDateFormat)formatter).toLocalizedPattern();

Since the DateFormat returned From getDateInstance() is instance of SimpleDateFormat. Those two methods should really be in the DateFormat too for this to be less hacky, but they currently are not.

Blackmarketeer answered 1/12, 2011 at 15:41 Comment(5)
This returns MMM d, yyyy for me although what I want is MM/dd/yyyy. What do I do.Anile
@prernaKeshari It returns what your default Java Locale is set to. If you want string for some specific/different Locale replace Locale.getDefault() with the Locale that you are using.Blackmarketeer
is casting between these actually safe? it does seem to work but it definitely feels hacky. still looking for a way to get the pattern string without a cast.Afroamerican
Which of DateFormat did you use?Cutcherry
What do you mean by: Which of DateFormat did you use? The class DateFormat and its static method.Blackmarketeer
D
25

It may be strange, that I am answering my own question, but I believe, I can add something to the picture.

ICU implementation

Obviously, Java 8 gives you a lot, but there is also something else: ICU4J. This is actually the source of Java original implementation of things like Calendar, DateFormat and SimpleDateFormat, to name a few.
Therefore, it should not be a surprise that ICU's SimpleDateFormat also contains methods like toPattern() or toLocalizedPattern(). You can see them in action here:

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 enhancements

This is nothing new, but what I really wanted to point out is this:

DateFormat.getPatternInstance(String pattern, Locale locale);

This is a method that can return a whole bunch of locale specific patterns, such as:

  • ABBR_QUARTER
  • QUARTER
  • YEAR
  • 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
  • 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
  • DAY
  • ABBR_WEEKDAY
  • WEEKDAY
  • HOUR
  • HOUR24
  • HOUR_MINUTE
  • HOUR_MINUTE_SECOND
  • HOUR24_MINUTE
  • HOUR24_MINUTE_SECOND
  • HOUR_TZ
  • HOUR_GENERIC_TZ
  • HOUR_MINUTE_TZ
  • HOUR_MINUTE_GENERIC_TZ
  • MINUTE
  • MINUTE_SECOND
  • SECOND
  • ABBR_UTC_TZ
  • ABBR_SPECIFIC_TZ
  • SPECIFIC_TZ
  • ABBR_GENERIC_TZ
  • GENERIC_TZ
  • LOCATION_TZ

Sure, there are quite a few. What is good about them, is that these patterns are actually strings (as in java.lang.String), that is if you use English pattern "MM/d", you'll get locale-specific pattern in return. It might be useful in some corner cases. Usually you would just use DateFormat instance, and won't care about the pattern itself.

Locale-specific pattern vs. localized pattern

The question intention was to get localized, and not the locale-specific pattern. What's the difference?

In theory, toPattern() will give you locale-specific pattern (depending on Locale you used to instantiate (Simple)DateFormat). That is, no matter what target language/country you put, you'll get the pattern composed of symbols like y, M, d, h, H, M, etc.

On the other hand, toLocalizedPattern() should return localized pattern, that is something that is suitable for end users to read and understand. For instance, German middle (default) date pattern would be:

  • toPattern(): dd.MM.yyyy
  • toLocalizedPattern(): tt.MM.jjjj (day = Tag, month = Monat, year = Jahr)

The intention of the question was: "how to find the localized pattern that could serve as hint as to what the date/time format is". That is, say we have a date field that user can fill-out using the locale-specific pattern, but I want to display a format hint in the localized form.

Sadly, so far there is no good solution. The ICU I mentioned earlier in this post, partially works. That's because, the data that ICU uses come from CLDR, which is unfortunately partially translated/partially correct. In case of my mother's tongue, at the time of writing, neither patterns, nor their localized forms are correctly translated. And every time I correct them, I got outvoted by other people, who do not necessary live in Poland, nor speak Polish language...

The moral of this story: do not fully rely on CLDR. You still need to have local auditors/linguistic reviewers.

Disfeature answered 9/6, 2014 at 20:56 Comment(4)
Although this doesn't address Java 8, I awarded the bounty to you, because no other answer so far provides any additional insights for Java 8 and your answer adds valuable content to your question.Klutz
a lot of great insight in this answer. It looks like getPatternInstance has been added to android api 24. I'm not sure what the right solution for earlier versions is, but those locale specific patterns (HOUR_MINUTE) seem very nice.Afroamerican
Great writing! Very informative. Btw may I ask you one thing? Does DateFormat.get*Instance() method always return a SimpleDateFormat object?Shadshadberry
Very good answer, thank you. Saved me some time trying to battle a weird API. ;)Assignee
B
16

You can use DateTimeFormatterBuilder in Java 8. Following example returns localized date only pattern e.g. "d.M.yyyy".

String datePattern = DateTimeFormatterBuilder.getLocalizedDateTimePattern(
  FormatStyle.SHORT, null, IsoChronology.INSTANCE, 
  Locale.GERMANY); // or whatever Locale
Biforate answered 4/6, 2014 at 19:27 Comment(3)
This does not work as expected. For locale GERMANYI get dd.MM.yy, but ((SimpleDateFormat) DateFormat.getDateInstance(DateFormat.SHORT, Locale.GERMANY)).toLocalizedPattern() gives tt.MM.uu as a result. This method will return the pattern using the format characters as specifid for SimpleDateFormat and not the format characters for the specified locale.Klutz
@Klutz This is the correct way to do it in Java 8. What you are seeing is a bug/limitation/whatever of previous Java versions. SimpleDateFormat#toLocalizedPattern() is wrong. The above is correct.Tachygraphy
Please see the answer of @PawełDyda for the difference between locale-specific date patterns and localized date patterns. Even though the localized date pattern for German is incorrect, I asked for a way to access the localized date pattern in the Java 8 Date Time API in my bounty, which would at least get the incorrect pattern.Klutz
S
9

The following code will give you the pattern for the locale:

final String pattern1 = ((SimpleDateFormat) DateFormat.getDateInstance(DateFormat.SHORT, locale)).toPattern();
System.out.println(pattern1);
Sweep answered 22/2, 2011 at 18:0 Comment(2)
I don't think that this is safe. You are casting to an implementation detail of the JRE. The JRE can change the class used to implement DateFormat.getDateInstance at any time causing a class cast exception.Annikaanniken
Casting is the only way to do it. Also using toPattern instead of toLocalizedPattern is probably what you want.Carreno
F
6

Java 8 provides some useful features out of the box for working with and formatting/parsing date and time, including handling locales. Here is a brief introduction.

Basic Patterns

In the simplest case to format/parse a date you would use the following code with a String pattern:

DateTimeFormatter.ofPattern("MM/dd/yyyy")

The standard is then to use this with the date object directly for formatting:

return LocalDate.now().format(DateTimeFormatter.ofPattern("MM/dd/yyyy"));

And then using the factory pattern to parse a date:

return LocalDate.parse(dateString, DateTimeFormatter.ofPattern("MM/dd/yyyy"));

The pattern itself has a large number of options that will cover the majority of usecases, a full rundown can be found at the javadoc location here.

Locales

Inclusion of a Locale is fairly simple, for the default locale you have the following options that can then be applied to the format/parse options demonstrated above:

DateTimeFormatter.ofLocalizedDate(dateStyle);

The 'dateStyle' above is a FormatStyle option Enum to represent the full, long, medium and short versions of the localized Date when working with the DateTimeFormatter. Using FormatStyle you also have the following options:

DateTimeFormatter.ofLocalizedTime(timeStyle);
DateTimeFormatter.ofLocalizedDateTime(dateTimeStyle);
DateTimeFormatter.ofLocalizedDateTime(dateTimeStyle, timeStyle);

The last option allows you to specify a different FormatStyle for the date and the time. If you are not working with the default Locale the return of each of the Localized methods can be adjusted using the .withLocale option e.g

DateTimeFormatter.ofLocalizedTime(timeStyle).withLocale(Locale.ENGLISH);

Alternatively the ofPattern has an overloaded version to specify the locale too

DateTimeFormatter.ofPattern("MM/dd/yyyy",Locale.ENGLISH);

I Need More!

DateTimeFormatter will meet the majority of use cases, however it is built on the DateTimeFormatterBuilder which provides a massive range of options to the user of the builder. Use DateTimeFormatter to start with and if you need these extensive formatting features fall back to the builder.

Farinaceous answered 9/6, 2014 at 2:10 Comment(2)
While this is a nice intro, the question was about getting the format string out of an existing formatter.Faviolafavonian
This doesn't address the question.Sialagogue
M
6

Please find in the below code which accepts the locale instance and returns the locale specific data format/pattern.

 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;
}
Millepore answered 30/3, 2017 at 8:27 Comment(0)
S
0

Since it's just the locale information you're after, I think what you'll have to do is locate the file which the JVM (OpenJDK or Harmony) actually uses as input to the whole Locale thing and figure out how to parse it. Or just use another source on the web (surely there's a list somewhere). That'll save those poor translators.

Sappington answered 4/1, 2011 at 14:55 Comment(0)
M
-2

You can try something like :

LocalDate fromCustomPattern = LocalDate.parse("20.01.2014", DateTimeFormatter.ofPattern("MM/dd/yy"))
Marven answered 9/6, 2014 at 7:54 Comment(0)
M
-4

Im not sure about what you want, but...

SimpleDateFormat example:

SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yy");
Date date = sdf.parse("12/31/10");
String str = sdf.format(new Date());
Manheim answered 4/1, 2011 at 14:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.