Reputation: 34550
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
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
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
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
Reputation: 3022
Using com.ibm.icu library:
import com.ibm.icu.text.DateFormat;
DateFormat.getPatternInstance(DateFormat.MONTH_DAY, locale).format(date);
Upvotes: 1
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
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
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
Reputation: 994
or
SimpleDateFormat dateFormat = new SimpleDateFormat("EEE MMM d');
dateFormat.format(date);
Upvotes: -4
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
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