Reputation: 2460
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?
Upvotes: 0
Views: 3359
Reputation: 73
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();
}
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);
}
Upvotes: 0
Reputation: 103
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";
Upvotes: 0
Reputation: 2460
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));
Upvotes: 1