9

I like to format the local timeformat into a string without the year. At the moment I am able to show the local format containing the year:

java.text.DateFormat df = java.text.DateFormat.getDateInstance(java.text.DateFormat.SHORT);
String dateString = df.format(date);

therefore i receive an time string output like

12.03.2012
03/12/2012

for the different countries. Now i like to get a short form like

12.03.
03/12

how would i do this?

thanks for your help!

Anthea
  • 3,741
  • 5
  • 40
  • 64

8 Answers8

17

You can use SimpleDateFormat:

Date date = new Date();
java.text.SimpleDateFormat df = new java.text.SimpleDateFormat("MM/dd");
String dateString = df.format(date);

Output:

03/15

EDIT:

After researching locale formats further, and expanding on Peters answer, here's some code to demonstrator differences between toPattern() and toLocalizedPattern():

import java.text.*
import java.util.*

ArrayList<Locale> locales = new ArrayList<Locale>();
locales.add(Locale.US);
locales.add(Locale.UK);
locales.add(Locale.GERMANY);
locales.add(Locale.CHINA);

Date date = new Date();

for(Locale l : locales)
{
    SimpleDateFormat sdf = (SimpleDateFormat) SimpleDateFormat.getDateInstance(DateFormat.SHORT, l);
    String pattern = sdf.toPattern();
    String localizedPattern = sdf.toLocalizedPattern()
    println "country: " + l.getDisplayName();
    println "pattern: " + pattern;
    println "localizedPattern: " + localizedPattern;

    try {
        SimpleDateFormat temp = new SimpleDateFormat(localizedPattern, l);
        println "localized pattern re-parsed successfully"
    } catch (IllegalArgumentException e) {
        println "localized pattern re-parsed unsuccessfully: " + e.getMessage();
    }
    SimpleDateFormat df = new SimpleDateFormat(pattern, l);
    String dateString = df.format(date);
    println "resulting date: " + dateString
    String yearlessPattern = pattern.replaceAll("\\W?[Yy]+\\W?", "");
    println "yearlessPattern = " + yearlessPattern;
    SimpleDateFormat yearlessSDF = new SimpleDateFormat(yearlessPattern, l);
    println "resulting date without year: " + yearlessSDF.format(date) + "\n";
}

Produces following output:

country: English (United States)
pattern: M/d/yy
localizedPattern: M/d/yy
localized pattern re-parsed successfully
resulting date: 3/15/12
yearlessPattern = M/d
resulting date without year: 3/15

country: English (United Kingdom)
pattern: dd/MM/yy
localizedPattern: dd/MM/yy
localized pattern re-parsed successfully
resulting date: 15/03/12
yearlessPattern = dd/MM
resulting date without year: 15/03

country: German (Germany)
pattern: dd.MM.yy
localizedPattern: tt.MM.uu
localized pattern re-parsed unsuccessfully: Illegal pattern character 't'
resulting date: 15.03.12
yearlessPattern = dd.MM
resulting date without year: 15.03

country: Chinese (China)
pattern: yy-M-d
localizedPattern: aa-n-j
localized pattern re-parsed unsuccessfully: Illegal pattern character 'n'
resulting date: 12-3-15
yearlessPattern = M-d
resulting date without year: 3-15

So in conclusion, to display a localized date without a year:

String yearlessPattern = DateFormat.getDateInstance(DateFormat.SHORT).toPattern().replaceAll("\\W?[Yy]+\\W?", "");

Alex
  • 10,470
  • 8
  • 40
  • 62
10

I needed to convert date to String removing year. String should keep locale settings. Date format is of type DateFormat.LONG, not DateFormat.SHORT. E.g., full string is September 18, 2012, not 09/18/12.

My solution (based on Alex post):

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.regex.Pattern;

public class Test {


private static void testLocaleDates() {
    String fmtString = "%-20s %-25s %-25s %-20s %-20s";
    System.out.println(String.format(fmtString, "Locale", "Complete date", "Pattern", "Yearless date", "Yearless pattern"));
    Pattern regExpPattern = Pattern.compile("Sweden|Spain|Russia|Ukraine|States|France|German|Japan|China", Pattern.CASE_INSENSITIVE);

    for (Locale locale : Locale.getAvailableLocales()) {
        boolean isPrint = regExpPattern.matcher(locale.getDisplayCountry()).find(); 
        if (!isPrint)
            continue;
        Date date = new Date();
        String dateTxt = DateFormat.getDateInstance(DateFormat.LONG, locale).format(date);
        SimpleDateFormat sdf = (SimpleDateFormat) SimpleDateFormat.getDateInstance(DateFormat.LONG, locale);
        String pattern = sdf.toPattern();
        // Checking 'de' we omit problems with Spain locale
        String regExpPatternTxt = pattern.contains("de") ? "[^Mm]*[Yy]+[^Mm]*" : "[^DdMm]*[Yy]+[^DdMm]*";
        String yearlessPattern = pattern.replaceAll(regExpPatternTxt, "");
        SimpleDateFormat yearlessSDF = new SimpleDateFormat(yearlessPattern, locale);

        System.out.println(String.format(fmtString, locale.getDisplayCountry(), dateTxt, pattern, yearlessSDF.format(date), yearlessPattern));
    }
}

public static void main(String[] args) {
    testLocaleDates();
}
}

Program output:

Locale            Complete date          Pattern                Yearless date     Yearless pattern  
Japan             2012/09/18             yyyy/MM/dd             09/18             MM/dd             
Japan             H24.09.18              Gy.MM.dd               09.18             MM.dd             
United States     September 18, 2012     MMMM d, yyyy           September 18      MMMM d            
Spain             18 de septiembre de 2012d' de 'MMMM' de 'yyyy  18 de septiembre  d' de 'MMMM       
United States     18 de septiembre de 2012d' de 'MMMM' de 'yyyy  18 de septiembre  d' de 'MMMM       
Ukraine           18 вересня 2012        d MMMM yyyy            18 вересня        d MMMM            
Spain             18 / setembre / 2012   d' / 'MMMM' / 'yyyy    18 / setembre     d' / 'MMMM        
Russia            18 Сентябрь 2012 г.    d MMMM yyyy 'г.'       18 Сентябрь       d MMMM            
China             2012年9月18日             yyyy'年'M'月'd'日'        9月18日             M'月'd'日'          
France            18 septembre 2012      d MMMM yyyy            18 septembre      d MMMM            
Germany           18. September 2012     d. MMMM yyyy           18. September     d. MMMM           
Sweden            den 18 september 2012  'den 'd MMMM yyyy      den 18 september  'den 'd MMMM      

Community
  • 1
  • 1
Exterminator13
  • 2,152
  • 1
  • 23
  • 28
  • +1. Could you pls let me know why `pattern.contains("de") ? "[^Mm]*[Yy]+[^Mm]*" : "[^DdMm]*[Yy]+[^DdMm]` ? – Trying Oct 13 '15 at 19:43
  • @Trying Let's take 10/14/2015. US locale patttern is "MMMM d, yyyy". Without this checking we'll get "October" for US locale but we need "October 14". Because "Dd" is not listed in "excluded" of RegExp "[^DdMm]" it'll be removed. But if we will use it for Spanish locale "d' de 'MMMM' de 'yyyy", we'll get an exception! – Exterminator13 Oct 13 '15 at 23:37
  • Great but it does a bad replacement for Vietnamese resulting in yearlessPattern having an unterminated quote: dd 'tháng' M 'năm – Mark Jul 11 '18 at 00:10
  • Thanks for `DateFormat.getDateInstance(DateFormat.LONG, Locale.getDefault()).format(Date())`. – CoolMind May 21 '19 at 09:34
2

Other authors have correctly recognized that the Java platform does not manage predefined localized format patterns for a month-day-combination without year so complex workarounds like using data analysis and regexp-patterns were suggested.

I have embedded such format patterns into my library Time4J based on the newest CLDR-data. Example:

AnnualDate now = SystemClock.inLocalView().now(AnnualDate.chronology());
System.out.println("xml-schema: " + now); // --09-23

ChronoFormatter<AnnualDate> fEnglishUS =
    ChronoFormatter.ofStyle(DisplayMode.SHORT, Locale.US, AnnualDate.chronology());
ChronoFormatter<AnnualDate> fFrench =
    ChronoFormatter.ofStyle(DisplayMode.SHORT, Locale.FRENCH, AnnualDate.chronology());
ChronoFormatter<AnnualDate> fGerman =
    ChronoFormatter.ofStyle(DisplayMode.SHORT, Locale.GERMAN, AnnualDate.chronology());
System.out.println("us: " + fEnglishUS.format(now)); // 9/23
System.out.println("french:  " + fFrench.format(now)); // 23/09
System.out.println("german:  " + fGerman.format(now)); // 23.9.

Good to know: ICU4J does have this capability, too, but with a far more complex API.

Meno Hochschild
  • 42,708
  • 7
  • 104
  • 126
2

There is no predefined format to achieve this. Here is a workaround: Format the date with java.text.DateFormat.SHORT and with a custom formatter with the format yyyy. Now search the result of the former for the latter.

If the year is near the beginning, remove the next non-digit after the year, otherwise strip non-digits before the year.

But that's not perfect either, because it gives you "12.3" instead of "12.3." for German.

If you really need to get it right, look into the Java source code, specifically the package sun.text.resources in rt.jar and print all the locale dates (you can simply create a DateFormat with type SHORT for all locales).

That should give you all the data you need to create your own resource bundle with day/month format strings for all languages.

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
1

java.time.MonthDay

Java offers a class to represent such a value, a month and a day-of-month without any year: java.time.MonthDay

LocalDate ld = LocalDate.parse( "2012-12-03" );  // December 3rd.
MonthDay md = MonthDay.from( ld );

ISO 8601

If you call toString, you get a string generated in the format following the ISO 8601 standard, --MM-DD. That is the Extended format, and the standard also allows for the Basic format minimizing the use of separators, --MMDD. Reference: Section 5.2.1.3 Truncated representations d) A specific day of a month in the implied year of the ISO 8601:2000 standard.

String output = md.toString();

--12-03

Custom formats

I suggest using the standard formats whenever possible. But if you must use other formats, you can specify with the DateTimeFormatter class.

DateTimeFormatter f = DateTimeFormatter.ofPattern( "MM/dd" );
String output = md.format( f ); 

12/03

The java.time classes provide for automatic localization of date-only values and date-time values. Unfortunately, no such support for month-day values. So you will have to define your own custom format explicitly for your desired localization. For alternatives, see the Answer by Meno Hochschild.

Community
  • 1
  • 1
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • The format "--MM-DD" is **NOT** ISO-8601 but an invention done by XML-Schema. See also the relevant sections "4.1.2.2 Complete representations" and "4.1.2.3 Representations with reduced accuracy" in the original ISO-8601-paper. And else I must say that this post does not answer the question how to find a localized pattern without explicitly setting it. – Meno Hochschild Sep 23 '16 at 17:29
  • [This final draft of ISO 8601, dated 2000-10-15, Reference number ISO/FDIS 8601:2000(E)](http://xml.coverpages.org/ISO-FDIS-8601.pdf) does indeed define a format `--MM-DD` (Extended format) and `--MMDD` (Basic format) in section *5.2.1.3 Truncated representations* under part *d) A specific day of a month in the implied year*. – Basil Bourque Sep 23 '16 at 20:03
  • Thank you very much for showing this link. However, it is an outdated ISO-paper. Probably XML-schema has taken this as base for its month-day-format, and later, the last ISO-version has now cancelled this format resp. does not mention it any longer. – Meno Hochschild Sep 24 '16 at 07:34
1

You can extract the pattern and remove the year.

SimpleDateFormat df = (SimpleDateFormat)
                      DateFormat.getDateInstance(DateFormat.SHORT);
String pattern = df.toLocalizedPattern().replaceAll(".?[Yy].?", "");
System.out.println(pattern);
SimpleDateFormat mdf = new SimpleDateFormat(pattern);

prints

M/d

on my system.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • @android_dev what is used for the year in Bulgarian? – Peter Lawrey Jul 01 '20 at 06:57
  • Bulgarin pattern is " d.MM.yy 'г' ". The last part of the pattern is also related to year and should be removed. What we are currently planning to use is " ([^dM]*)y[^dM]* " https://stackoverflow.com/a/46428741/1635488 – android_dev Jul 01 '20 at 07:45
  • As you're well experienced in Java, maybe you know a clean way to do this in Java 8? Without this kind of hacks. – android_dev Jul 01 '20 at 07:47
0

A note on using DateFormat.getDateInstance(DateFormat.LONG) or DateFormat.getDateInstance(DateFormat.FULL) on devices set to Spanish locale.

The format that comes out with text literals from simpleDateFormat.toLocalizedPattern().

d 'de' MMMM 'de' y

In the case I'm looking at.

(e.g. 15th January 2021 is 15 de enero de 2021 in Spanish)

Removing the y and any non word char would lead to java.lang.IllegalArgumentException: Unterminated quote exceptions (as the last ' on the last 'de' would be removed as a non word character).

So as a least worst solution, in our non-year formater, we stripped out any literals if the patern contains single quote char '. (Using reg ex pattern.replaceAll("'\\w+'", "")).

I have tested this with a few other locals and it seems to work. (de, ja, pt, en)

Diederik
  • 5,536
  • 3
  • 44
  • 60
0

As you probably realize, short formats depends not only on language but also on country. Unfortunately, there are no such patterns built-in in Java. Instead, you might need to use the ones defined by CLDR - search for "pattern" or "Md" (month / day pattern).

However, I must warn you that these patterns might be buggy. Instead you might want to move them to resource file and let the translators deal with them (appropriate comment on what it is and how to deal with it would be required.)

Paweł Dyda
  • 18,366
  • 7
  • 57
  • 79