53

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.

Matthias Braun
  • 32,039
  • 22
  • 142
  • 171
Paweł Dyda
  • 18,366
  • 7
  • 57
  • 79
  • I am pretty sure there is no way you can access these patterns. What do you need them for? – Sean Patrick Floyd Jan 04 '11 at 14:17
  • 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). – Paweł Dyda Jan 04 '11 at 14:38
  • `java.text.SimpleDateFormat` lets you specify your own date format. – David Bullock Jan 04 '11 at 14:13
  • 2
    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. – Paweł Dyda Jan 04 '11 at 14:17
  • 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? – David Bullock Jan 04 '11 at 14:27
  • Right. I've tried to debug DateFormat, but failed miserably... – Paweł Dyda Jan 04 '11 at 14:44
  • 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. – David Bullock Jan 04 '11 at 14:45
  • http://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: http://www.java2s.com/Code/Java/Data-Type/DateFormatwithLocale.htm – Hannes Jun 09 '14 at 17:19

10 Answers10

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.

  • 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); :) – herman Jun 19 '13 at 16:21
  • 3
    The problem with Java 8 DateTimeFormatter is that there is no way how to get the original pattern from it: https://stackoverflow.com/questions/28949179/get-original-pattern-string-given-a-jdk-8-datetimeformatter – Natix Jan 25 '18 at 17:10
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.

Zarremgregarrok
  • 484
  • 5
  • 8
24

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.

Paweł Dyda
  • 18,366
  • 7
  • 57
  • 79
  • 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. – SpaceTrucker Jun 11 '14 at 15:14
  • 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. – trooper Jul 15 '16 at 20:44
  • Great writing! Very informative. Btw may I ask you one thing? Does DateFormat.get*Instance() method always return a SimpleDateFormat object? – Jenix Jul 29 '18 at 23:15
  • Very good answer, thank you. Saved me some time trying to battle a weird API. ;) – Baptiste Candellier Sep 26 '19 at 09:21
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
Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
mikaves
  • 169
  • 1
  • 2
  • 2
    This does not work as expected. For locale `GERMANY`I 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. – SpaceTrucker Jun 05 '14 at 20:17
  • @SpaceTrucker This is the correct way to do it in Java 8. What you are seeing is a [bug/limitation/whatever of previous Java versions](http://bugs.java.com/view_bug.do?bug_id=4265184). `SimpleDateFormat#toLocalizedPattern()` is wrong. The above is correct. – Sotirios Delimanolis Jun 09 '14 at 02:31
  • Please see the [answer of @PawełDyda](http://stackoverflow.com/a/24128930/1466267) 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. – SpaceTrucker Jun 11 '14 at 06:23
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);
  • 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. – iain Apr 20 '11 at 07:08
  • Casting is the only way to do it. Also using `toPattern` instead of `toLocalizedPattern` is probably what you want. – DDD Jun 12 '13 at 09:36
5

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.

atamanroman
  • 11,607
  • 7
  • 57
  • 81
Jim
  • 3,254
  • 1
  • 19
  • 26
5

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;
}
Dinesh Lomte
  • 569
  • 7
  • 5
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.

David Bullock
  • 6,112
  • 3
  • 33
  • 43
-2

You can try something like :

LocalDate fromCustomPattern = LocalDate.parse("20.01.2014", DateTimeFormatter.ofPattern("MM/dd/yy"))
Maxime Lorant
  • 34,607
  • 19
  • 87
  • 97
-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());
Renan
  • 741
  • 4
  • 7