0

I'm supposed to show different time formats according to the language in my app. When the device is English the user should get the time format like this:

18 March 2018, 2.30 pm

But when the user's device is German he should get the time format like this:

18.03.2018, 14:30 Uhr

Is there any way to do this by formatting the time String with SimpleDateFormat or am I supposed to do this in another way and if so, how am I able to do this?

roisnd
  • 73
  • 3
Distra
  • 2,260
  • 2
  • 14
  • 23
  • Did you try it? where did it fail? – Henry Mar 20 '18 at 06:24
  • i don't know how to differ it. for now it's only showing the german format the whole time. that's the part where it fails. I just had the crazy idea to use the language string xml files to put the formats into it, but i don't really expect that to work – Distra Mar 20 '18 at 06:28
  • Possible duplicate of [SimpleDateFormat and locale based format string](https://stackoverflow.com/questions/1661325/simpledateformat-and-locale-based-format-string) – Ole V.V. Mar 20 '18 at 07:53
  • As an aside consider throwing away the long outmoded and notoriously troublesome `SimpleDateFormat` and friends, and adding [ThreeTenABP](https://github.com/JakeWharton/ThreeTenABP) to your Android project in order to use `java.time`, the modern Java date and time API. It is so much nicer to work with. – Ole V.V. Mar 20 '18 at 07:53

3 Answers3

1

I didn't think it would work, but it did. Just put the format you like into the string xml file for me it was:

<string name="date_time_format">dd MMMM yyyy, hh.mm a</string>
<string name="date_time_format">dd.MM.yyyy, HH:mm</string>

Then use it in the SDF like this:

SimpleDateFormat fmtOut = new SimpleDateFormat(context.getString(R.string.date_time_format), Locale.getDefault());

for the "Uhr" at the end of the german format i added a placeholder String that looks like this:

<string name="date_time_string">%s</string>
<string name="date_time_string">%s Uhr</string>

and i return the formated date with the String.format() method:

return String.format(context.getString(R.string.date_time_string), fmtOut.format(date));
Distra
  • 2,260
  • 2
  • 14
  • 23
  • Just to add, @Distra, you may also have to change the time value as per the locale . It will only update the format. – Manish Mar 20 '18 at 07:45
0

Try this code snippet. hope it will solve the issue.

        java.sql.Date date1 = new java.sql.Date((new Date()).getTime());

        SimpleDateFormat formatNowDay = new SimpleDateFormat("dd");
        SimpleDateFormat formatNowYear = new SimpleDateFormat("yyyy");
        SimpleDateFormat sdf12 = new SimpleDateFormat("hh:mm aa");
        SimpleDateFormat sdf24 = new SimpleDateFormat("HH:mm");
        SimpleDateFormat germanSdf = new SimpleDateFormat("dd.MM.yyyy");

        String currentDay = formatNowDay.format(date1);
        String currentYear = formatNowYear.format(date1);
        String time12 = sdf12.format(date1);
        String time24 = sdf24.format(date1);

        String germanTime = germanSdf.format(date1);

        Calendar mCalendar = Calendar.getInstance();
        String currentMonth = mCalendar.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.getDefault());

        String engTime = currentDay+" "+currentMonth+" "+currentYear+", "+time12;
        String germanFormat = germanTime+", "+time24+" Uhr";
0

One alternative is to use a java.text.DateFormat:

DateFormat df = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, Locale.ENGLISH);

The date and time styles (first and second parameters) can be either SHORT, MEDIUM, LONG or FULL. And you can use Locale.getDefault() to get the device's default language, if you want.

I'm not sure which combination of styles give what you want - all of them gave me different outputs and none gave me the one you described.

That's because locale specific formats are embeeded in the JVM, and I'm not sure how it varies among different API levels and devices.

If the solution above works, then it's fine. Otherwise, an alternative is to make specific patterns per locale:

// get device's locale
Locale locale = Locale.getDefault();

String pattern = "";
// check language
if ("en".equals(locale.getLanguage())) {
    // english
    pattern = "dd MMMM yyyy, h.mm a";
} else if ("de".equals(locale.getLanguage())) {
    // german
    pattern = "dd.MM.yyyy, HH:mm 'Uhr'";
} else {
    pattern = // use some default pattern for other languages?
}

SimpleDateFormat sdf = new SimpleDateFormat(pattern, locale);
String formattedDate = sdf.format(new Date());

One detail is that, in my JVM, the AM/PM symbols for English locale are in uppercase, so you may want to adjust it by doing:

// change AM/PM to am/pm (only for English)
if ("en".equals(locale.getLanguage())) {
    formattedDate  = formattedDate.toLowerCase();
}

java.time API

In API level 26, you can use the java.time API. For lower levels, there's a nice backport, with the same classes and functionalities.

This is much better to work with. The code might look similar, but the classes themselves solves lots of internal issues of the old API.

You can first try to get JVM's localized patterns and see if they match your output:

Locale locale = Locale.getDefault();
FormatStyle style = FormatStyle.MEDIUM;
String pattern = DateTimeFormatterBuilder.getLocalizedDateTimePattern(style, style, IsoChronology.INSTANCE, locale);
DateTimeFormatter fmt = DateTimeFormatter.ofPattern(pattern, locale);

Or do the same as above:

// get device's locale
Locale locale = Locale.getDefault();

String pattern = "";
// check language
if ("en".equals(locale.getLanguage())) {
    // english
    pattern = "dd MMMM yyyy, h.mm a";
} else if ("de".equals(locale.getLanguage())) {
    // german
    pattern = "dd.MM.yyyy, HH:mm 'Uhr'";
} else {
    pattern = ""; // use some default pattern?
}

DateTimeFormatter fmt = DateTimeFormatter.ofPattern(pattern, locale);

String formattedDate = LocalDateTime.now().format(fmt);

In my tests, I've got the same problem of having uppercase AM/PM for English. You can solve this by calling toLowerCase() as above, but this API also allows you to create a more flexible formatter.

And the formatters are thread-safe (while SimpleDateFormat isn't), so you could create a static map of formatters based on the language and reuse them as many times you want:

// map of formatters
Map<String, DateTimeFormatter> formatterMap = new HashMap<>();

// English formatter
Map<Long, String> customAmPmSymbols = new HashMap<>();
customAmPmSymbols.put(0L, "am");
customAmPmSymbols.put(1L, "pm");
DateTimeFormatter f = new DateTimeFormatterBuilder()
    // date/time
    .appendPattern("dd MMMM yyyy, h.mm ")
    // custom AM/PM symbols (lowercase)
    .appendText(ChronoField.AMPM_OF_DAY, customAmPmSymbols)
    // create formatter
    .toFormatter(Locale.ENGLISH);
// add to map
formatterMap.put("en", f);

// German formatter
formatterMap.put("de", DateTimeFormatter.ofPattern("dd.MM.yyyy, HH:mm 'Uhr'", Locale.GERMAN));

// get device's locale
Locale locale = Locale.getDefault();

DateTimeFormatter fmt = formatterMap.get(locale.getLanguage());

if (fmt != null) {
    String formattedDate = LocalDateTime.now().format(fmt);
}
roisnd
  • 73
  • 3