fhucho
fhucho

Reputation: 34550

Format date without year

How can create text representation of some date, that takes locale into account and contains only day and month (no year)?

Following code gives me something like 23/09/2010

DateFormat.getDateInstance(DateFormat.SHORT, Locale.getDefault()).format(date);

I want to get 23/09

Upvotes: 41

Views: 25665

Answers (10)

Ayaz Alifov
Ayaz Alifov

Reputation: 8608

The main difficulty here is that in some locales the order of month and day is different. I solved it in a way which is different from those which presented here.

    Date dateObject = ...;

    String dayMonthDateString = getDayMonthDateString(dateObject, Locale.GERMANY);
    Log.i("customDate", "dayMonthDateString = " + dayMonthDateString);

private String getDayMonthDateString(Date date, Locale locale)
{
    try
    {
        boolean dayBeforeMonth = defineDayMonthOrder(locale);

        SimpleDateFormat newDateFormat;

        if (dayBeforeMonth)
        {
            newDateFormat = new SimpleDateFormat("dd/MM", locale);
        }
        else
        {
            newDateFormat = new SimpleDateFormat("MM/dd", locale);
        }

        return newDateFormat.format(date);
    }
    catch (ParseException e)
    {
        e.printStackTrace();
    }

    return null;
}


private boolean defineDayMonthOrder(Locale locale) throws ParseException
{
    String day = "10";
    String month = "11";
    String year = "12";

    String calendarDate = day + "." + month + "." + year;

    SimpleDateFormat format = new SimpleDateFormat("dd.MM.yy");
    Date date = format.parse(calendarDate);

    String localizedDate = SimpleDateFormat.getDateInstance(SimpleDateFormat.SHORT, locale).format(date);

    int indexOfDay = localizedDate.indexOf(day);
    int indexOfMonth = localizedDate.indexOf(month);

    return indexOfDay < indexOfMonth;
}

Upvotes: 3

zelig74
zelig74

Reputation: 532

Although Andrzej Pronobis's answer is very good, it doesn't work for instance with ZH local. I ended up with manual removing year from localized pattern. This function was tested for all locals for SHORT, MEDIUM, LONG and FULL formats.

public String removeYearFromPattern(String pattern) throws IllegalArgumentException {
    int yPos = 0;
    while (yPos < pattern.length() && pattern.charAt(yPos) != 'y' && pattern.charAt(yPos) != 'Y') {
        if (pattern.charAt(yPos) == '\'') {
            yPos++;
            while (yPos < pattern.length() && pattern.charAt(yPos) != '\'') yPos++;
        }
        yPos++;
    }
    if (yPos >= pattern.length()) throw new IllegalArgumentException("Did not find year in pattern");
    String validPatternLetters = "EMd";
    // go forward
    int endPos = yPos;
    while (endPos < pattern.length() && validPatternLetters.indexOf(pattern.charAt(endPos)) == -1) {
        endPos++;
        if (endPos < pattern.length() && pattern.charAt(endPos) == '\'') {
            endPos++;
            while (endPos < pattern.length() && pattern.charAt(endPos) != '\'')
                endPos++;
        }
    }
    if (endPos != pattern.length()) validPatternLetters += ',';
    // go backward
    int startPos = yPos;
    while (startPos >= 0 && validPatternLetters.indexOf(pattern.charAt(startPos)) == -1) {
        startPos--;
        if (startPos >= 0 && pattern.charAt(startPos) == '\'') {
            startPos--;
            while (startPos >= 0 && pattern.charAt(startPos) != '\'') startPos--;
        }
    }
    startPos++;
    String yLetters = pattern.substring(startPos, endPos);
    return pattern.replace(yLetters, " ").trim();
}

Function above can be tested by running:

for (Locale locale : Locale.getAvailableLocales()) {
    SimpleDateFormat df = (SimpleDateFormat) DateFormat.getDateInstance(DateFormat.FULL, locale);
    String dfPattern = "?";
    String newPattern = "?";
    try {
        dfPattern = df.toPattern();
        newPattern = removeYearFromPattern(dfPattern);
        df.applyPattern(newPattern);
    } catch (IllegalArgumentException e) {
        Log.e(TAG, "Error removing year for " + locale + ": " + e.getMessage());
    }
    Log.d(TAG, locale + ": old  " + dfPattern + "; new " + newPattern + "; result " + df.format(new Date()));
}

I know it is not as elegant as regex, but it is a little bit faster and works for all locals (if I am able to recognize).

Upvotes: 2

android developer
android developer

Reputation: 116040

If you use Android, you might be able to use getBestDateTimePattern , and just put there all the fields you want to allow. It should automatically put the correct order and special characters according to the current locale.

Sadly, it requires API 18+ .

EDIT: This seems like a not-so-good choice, sadly. I've written about it here: http://code.google.com/p/android/issues/detail?id=171591


So, this is what I've done:

public static String convertDateToString(Context context, Locale locale, final Date date, boolean alsoShowYearIfPossible) {
    if (date == null)
        return "";
    String defaultDateFormat;
    if (locale != null) {
        defaultDateFormat = ((SimpleDateFormat) DateFormat.getDateInstance(DateFormat.SHORT, locale)).toLocalizedPattern();
    } else defaultDateFormat = getDefaultDateFormat(context);
    if (alsoShowYearIfPossible)
        return new SimpleDateFormat(defaultDateFormat, Locale.getDefault()).format(date);
    //need removal of year
    String removedYearFormat = defaultDateFormat.replaceAll("[^{mdMD}]*y+[^{mdMD}]*", "");
    String result = new SimpleDateFormat(removedYearFormat, Locale.getDefault()).format(date);
    //Log.d("AppLog", locale + ": \"" + defaultDateFormat + "\" => \"" + removedYearFormat + "\" =>" + result);
    return result;
}

private static String getDefaultDateFormat(final Context context) {
    String dateFormatString = Settings.System.getString(context.getContentResolver(), Settings.System.DATE_FORMAT);
    if (TextUtils.isEmpty(dateFormatString)) {
        // if device date format is available , use device date order,and if not available ,use default
        final char[] dateFormatOrder = android.text.format.DateFormat.getDateFormatOrder(context);
        if (dateFormatOrder.length == 0)
            dateFormatString = DEFAULT_DATE_FORMAT;
        else {
            // construct the date format based on the device date order
            final StringBuilder sb = new StringBuilder();
            for (int i = 0; i < dateFormatOrder.length; ++i) {
                final char c = dateFormatOrder[i];
                switch (Character.toLowerCase(c)) {
                    case 'y':
                        sb.append("yyyy");
                        break;
                    case 'm':
                        sb.append("MM");
                        break;
                    case 'd':
                        sb.append("dd");
                        break;
                }
                if (i != dateFormatOrder.length - 1)
                    sb.append('-');
            }
            dateFormatString = sb.toString();
        }
    }
    return dateFormatString;
}

This code works on any locale available, on Android 5.0.2 .

Here's a sample of how to check it on on locales:

    Date date = new Date();
    for (Locale locale : Locale.getAvailableLocales()) {
        SimpleDateFormat sdf = (SimpleDateFormat) DateFormat.getDateInstance(DateFormat.SHORT, locale);
        String localizedDatePattern = sdf.toLocalizedPattern();
        convertDateToString(this,locale,date,false);
    }

Upvotes: 1

Maxim Kachurovskiy
Maxim Kachurovskiy

Reputation: 3022

Using com.ibm.icu library:

import com.ibm.icu.text.DateFormat;

DateFormat.getPatternInstance(DateFormat.MONTH_DAY, locale).format(date);

Upvotes: 1

unify
unify

Reputation: 6351

This will work for Android, in case someone needs it:

int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NO_YEAR;
String monthAndDayText = DateUtils.formatDateTime(context, date, flags);

Upvotes: 58

Don
Don

Reputation: 221

The following is a utility class which gives you the date format without year. I list all the date formats known to Java using the following code.

Locale[] locales = SimpleDateFormat.getAvailableLocales();
for (int i = 0; i < locales.length; i++) {
    Locale locale = locales[i];
    DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.FULL, locale);
}

And then manually remove the year part. It returns two flavors of date format, normal and abbreviated, ie Monday, March 18 vs Mon, Mar 18.

public class DateFormatWithoutYear {

    private static Map<String, String> formats = new HashMap<String, String>();
    private static String DEFAULT_FORMAT = "EEEE, d MMMM";
    static {
        formats.put("_af", "EEEE dd MMMM");
        formats.put("_am", "EEEE, d MMMM");
        formats.put("_az", "EEEE, d, MMMM");
        formats.put("_be", "EEEE, d MMMM");
        formats.put("_bg", "dd MMMM, EEEE");
        formats.put("BG_bg", "dd MMMM, EEEE");
        formats.put("_ca", "EEEE d MMMM");
        formats.put("ES_ca", "EEEE d MMMM");
        formats.put("_cs", "EEEE, d. MMMM");
        formats.put("CZ_cs", "EEEE, d. MMMM");
        formats.put("_da", "EEEE 'den' d. MMMM");
        formats.put("DK_da", "EEEE 'den' d. MMMM");
        formats.put("_de", "EEEE, d. MMMM");
        formats.put("AT_de", "EEEE, dd. MMMM");
        formats.put("BE_de", "EEEE, d. MMMM");
        formats.put("CH_de", "EEEE, d. MMMM");
        formats.put("DE_de", "EEEE, d. MMMM");
        formats.put("LI_de", "EEEE, d. MMMM");
        formats.put("LU_de", "EEEE, d. MMMM");
        formats.put("_el", "EEEE, d MMMM");
        formats.put("GR_el", "EEEE, d MMMM");
        formats.put("_en", "EEEE, MMMM d");
        formats.put("AU_en", "EEEE, d MMMM");
        formats.put("BE_en", "EEEE d MMMM");
        formats.put("BW_en", "EEEE dd MMMM");
        formats.put("BZ_en", "EEEE, MMMM d");
        formats.put("CA_en", "EEEE, d MMMM");
        formats.put("GB_en", "EEEE, d MMMM");
        formats.put("HK_en", "EEEE, d MMMM");
        formats.put("IE_en", "EEEE d MMMM");
        formats.put("IN_en", "EEEE d MMMM");
        formats.put("JM_en", "EEEE, MMMM d");
        formats.put("MH_en", "EEEE, MMMM d");
        formats.put("MT_en", "EEEE, d MMMM");
        formats.put("NA_en", "EEEE, MMMM d");
        formats.put("NZ_en", "EEEE, d MMMM");
        formats.put("PH_en", "EEEE, MMMM d");
        formats.put("PK_en", "EEEE, MMMM d");
        formats.put("RH_en", "EEEE dd MMMM");
        formats.put("SG_en", "EEEE, d MMMM");
        formats.put("TT_en", "EEEE, MMMM d");
        formats.put("US_en", "EEEE, MMMM d");
        formats.put("VI_en", "EEEE, MMMM d");
        formats.put("ZA_en", "EEEE dd MMMM");
        formats.put("ZW_en", "EEEE dd MMMM");
        formats.put("_es", "EEEE d 'de' MMMM");
        formats.put("AR_es", "EEEE d 'de' MMMM");
        formats.put("BO_es", "EEEE d 'de' MMMM");
        formats.put("CL_es", "EEEE d 'de' MMMM");
        formats.put("CO_es", "EEEE d 'de' MMMM");
        formats.put("CR_es", "EEEE d 'de' MMMM");
        formats.put("DO_es", "EEEE d 'de' MMMM");
        formats.put("EC_es", "EEEE d 'de' MMMM");
        formats.put("ES_es", "EEEE d 'de' MMMM");
        formats.put("GT_es", "EEEE d 'de' MMMM");
        formats.put("HN_es", "EEEE dd 'de' MMMM");
        formats.put("MX_es", "EEEE d 'de' MMMM");
        formats.put("NI_es", "EEEE d 'de' MMMM");
        formats.put("PA_es", "EEEE d 'de' MMMM");
        formats.put("PE_es", "EEEE d 'de' MMMM");
        formats.put("PR_es", "EEEE d 'de' MMMM");
        formats.put("PY_es", "EEEE d 'de' MMMM");
        formats.put("SV_es", "EEEE d 'de' MMMM");
        formats.put("US_es", "EEEE d 'de' MMMM");
        formats.put("UY_es", "EEEE d 'de' MMMM");
        formats.put("VE_es", "EEEE d 'de' MMMM");
        formats.put("_et", "EEEE, d. MMMM");
        formats.put("_eu", "EEEE, MMMM'ren' dd'a'");
        formats.put("_fi", "cccc, d. MMMM");
        formats.put("FI_fi", "cccc, d. MMMM");
        formats.put("_fil", "EEEE, MMMM dd");
        formats.put("PH_fil", "EEEE, MMMM dd");
        formats.put("_fr", "EEEE d MMMM");
        formats.put("BE_fr", "EEEE d MMMM");
        formats.put("CA_fr", "EEEE d MMMM");
        formats.put("CH_fr", "EEEE, d MMMM");
        formats.put("FR_fr", "EEEE d MMMM");
        formats.put("LU_fr", "EEEE d MMMM");
        formats.put("MC_fr", "EEEE d MMMM");
        formats.put("_gl", "EEEE dd MMMM");
        formats.put("_iw", "EEEE, d בMMMM");
        formats.put("IL_iw", "EEEE, d בMMMM");
        formats.put("_hi", "EEEE, d MMMM");
        formats.put("IN_hi", "EEEE, d MMMM");
        formats.put("_hr", "EEEE, d. MMMM");
        formats.put("HR_hr", "EEEE, d. MMMM");
        formats.put("_hu", "MMMM d., EEEE");
        formats.put("HU_hu", "MMMM d., EEEE");
        formats.put("_hy", "EEEE, MMMM d");
        formats.put("_in", "EEEE, dd MMMM");
        formats.put("ID_in", "EEEE, dd MMMM");
        formats.put("_it", "EEEE d MMMM");
        formats.put("CH_it", "EEEE, d MMMM");
        formats.put("IT_it", "EEEE d MMMM");
        formats.put("_ja", "M月d日EEEE");
        formats.put("JP_ja", "M月d日EEEE");
        formats.put("_ka", "EEEE, MMMM dd");
        formats.put("_kk", "EEEE, d MMMM");
        formats.put("_ko", "M월 d일 EEEE");
        formats.put("KR_ko", "M월 d일 EEEE");
        formats.put("_lt", "'m'. MMMM d 'd'., EEEE");
        formats.put("LT_lt", "'m'. MMMM d 'd'., EEEE");
        formats.put("_lv", "EEEE, d. MMMM");
        formats.put("LV_lv", "EEEE, d. MMMM");
        formats.put("_mk", "EEEE, dd MMMM");
        formats.put("_ms", "EEEE, d MMMM");
        formats.put("_nb", "EEEE d. MMMM");
        formats.put("NO_nb", "EEEE d. MMMM");
        formats.put("_nl", "EEEE d MMMM");
        formats.put("BE_nl", "EEEE d MMMM");
        formats.put("NL_nl", "EEEE d MMMM");
        formats.put("_pl", "EEEE, d MMMM");
        formats.put("PL_pl", "EEEE, d MMMM");
        formats.put("_ps", "EEEE د MMMM d");
        formats.put("_pt", "EEEE, d 'de' MMMM");
        formats.put("BR_pt", "EEEE, d 'de' MMMM");
        formats.put("PT_pt", "EEEE, d 'de' MMMM");
        formats.put("_rm", "EEEE, d. MMMM");
        formats.put("_ro", "EEEE, d MMMM");
        formats.put("RO_ro", "EEEE, d MMMM");
        formats.put("_ru", "EEEE, d MMMM");
        formats.put("RU_ru", "EEEE, d MMMM");
        formats.put("UA_ru", "EEEE, d MMMM");
        formats.put("_sk", "EEEE, d. MMMM");
        formats.put("SK_sk", "EEEE, d. MMMM");
        formats.put("_sl", "EEEE, dd. MMMM");
        formats.put("SI_sl", "EEEE, dd. MMMM");
        formats.put("_sr", "EEEE, dd. MMMM");
        formats.put("BA_sr", "EEEE, dd. MMMM");
        formats.put("CS_sr", "EEEE, dd. MMMM");
        formats.put("CYRL_sr", "EEEE, dd. MMMM");
        formats.put("CYRL_sr", "EEEE, dd. MMMM");
        formats.put("CYRL_sr", "EEEE, dd. MMMM");
        formats.put("CYRL_sr", "EEEE, dd. MMMM");
        formats.put("CYRL_sr", "EEEE, dd. MMMM");
        formats.put("CYRL_sr", "EEEE, dd. MMMM");
        formats.put("LATN_sr", "EEEE, dd. MMMM");
        formats.put("LATN_sr", "EEEE, dd. MMMM");
        formats.put("LATN_sr", "EEEE, dd. MMMM");
        formats.put("LATN_sr", "EEEE, dd. MMMM");
        formats.put("LATN_sr", "EEEE, dd. MMMM");
        formats.put("LATN_sr", "EEEE, dd. MMMM");
        formats.put("ME_sr", "EEEE, dd. MMMM");
        formats.put("RS_sr", "EEEE, dd. MMMM");
        formats.put("YU_sr", "EEEE, dd. MMMM");
        formats.put("_sv", "EEEE'en' 'den' d:'e' MMMM");
        formats.put("FI_sv", "EEEE'en' 'den' d:'e' MMMM");
        formats.put("SE_sv", "EEEE'en' 'den' d:'e' MMMM");
        formats.put("_sw", "EEEE, d MMMM");
        formats.put("_th", "EEEEที่ d MMMM G");
        formats.put("TH_th", "EEEEที่ d MMMM G");
        formats.put("_tr", "d MMMM EEEE");
        formats.put("TR_tr", "d MMMM EEEE");
        formats.put("_uk", "EEEE, d MMMM");
        formats.put("UA_uk", "EEEE, d MMMM");
        formats.put("_uz", "EEEE, MMMM dd");
        formats.put("_vi", "EEEE, 'ngày' dd MMMM");
        formats.put("VN_vi", "EEEE, 'ngày' dd MMMM");
        formats.put("_zh", "M月d日EEEE");
        formats.put("CN_zh", "M月d日EEEE");
        formats.put("HK_zh", "M月d日EEEE");
        formats.put("HANS_zh", "M月d日EEEE");
        formats.put("HANS_zh", "M月d日EEEE");
        formats.put("HANS_zh", "M月d日EEEE");
        formats.put("HANS_zh", "M月d日EEEE");
        formats.put("HANT_zh", "M月d日EEEE");
        formats.put("HANT_zh", "M月d日EEEE");
        formats.put("HANT_zh", "MM月dd日EEEE");
        formats.put("HANT_zh", "M月d日EEEE");
        formats.put("MO_zh", "MM月dd日EEEE");
        formats.put("SG_zh", "M月d日EEEE");
        formats.put("TW_zh", "M月d日EEEE");
        formats.put("_zu", "EEEE dd MMMM");
    }

    public static String getLongFormatWithoutYear(Locale locale) {
        if (locale != null) {
            String key = locale.getCountry() + "_" + locale.getLanguage();
            String format = formats.get(key);
            if (format != null) {
                return format;
            }
        }
        return DEFAULT_FORMAT;
    }

    public static String getShortFormatWithoutYear(Locale locale) {
        String longFormat = getLongFormatWithoutYear(locale);
        return longFormat.replaceAll("E+", "E").replaceAll("MMMM", "MMM");
    }
}

Upvotes: 4

Andrzej Pronobis
Andrzej Pronobis

Reputation: 36136

Just wanted to contribute another modification removing year from the pattern, which works well for DateFormat.MEDIUM, even in locales such as pt_PT (d 'de' MMM 'de' yyyy) or lv_LV (y. 'gada' d. MMM).

public static DateFormat getMediumDateInstanceWithoutYears()
 {
   SimpleDateFormat sdf = (SimpleDateFormat) DateFormat.getDateInstance(DateFormat.MEDIUM);
   sdf.applyPattern(sdf.toPattern().replaceAll(
       "([^\\p{Alpha}']|('[\\p{Alpha}]+'))*y+([^\\p{Alpha}']|('[\\p{Alpha}]+'))*",
       ""));
   return sdf;
 }

Upvotes: 10

Puran
Puran

Reputation: 994

or

   SimpleDateFormat dateFormat = new SimpleDateFormat("EEE MMM d');
    dateFormat.format(date);

Upvotes: -4

BalusC
BalusC

Reputation: 1109635

You could use regex to trim off all y's and any non-alphabetic characters before and after, if any. Here's a kickoff example:

public static void main(String[] args) throws Exception {
    for (Locale locale : Locale.getAvailableLocales()) {
        DateFormat df = getShortDateInstanceWithoutYears(locale);
        System.out.println(locale + ": " + df.format(new Date()));      
    }
}

public static DateFormat getShortDateInstanceWithoutYears(Locale locale) {
    SimpleDateFormat sdf = (SimpleDateFormat) DateFormat.getDateInstance(DateFormat.SHORT, locale);
    sdf.applyPattern(sdf.toPattern().replaceAll("[^\\p{Alpha}]*y+[^\\p{Alpha}]*", ""));
    return sdf;
}

You see that this snippet tests it for all locales as well. It looks to work fine for all locales here.

Upvotes: 25

fhucho
fhucho

Reputation: 34550

I did it this way:

DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.SHORT, Locale.getDefault());
if (dateFormat instanceof SimpleDateFormat) {
    SimpleDateFormat simpleDateFormat = (SimpleDateFormat) dateFormat;
    String pattern = simpleDateFormat.toPattern();

    // I modified the pattern here so that dd.MM.yyyy would result to dd.MM

    simpleDateFormat.applyPattern(modifiedPattern);

    ... etc
}

Upvotes: 4

Related Questions