0

I want the "correct" localized time for users with US or German system locale. Meaning "1:00 PM" and "13:00"

Java API says: https://docs.oracle.com/javase/tutorial/i18n/format/dateFormat.html

Formats     U.S. Locale     German Locale
DEFAULT     7:03:47 AM      7:03:47
SHORT       7:03 AM         07:03

Correct so far.

Android API: https://developer.android.com/reference/java/text/DateFormat.html

SHORT is completely numeric, such as 12.13.52 or 3:30pm 

Correct for US, if you set a German Locale, Android will "translate" AM/PM and not remove it, how the correct way is and how Java did it.

My question, why does Google do that? Am I stupid and lacking sleep, not to understand "the Google logic"? This is a trivial request, yet I tried for 2 hours to get a correct German short time presentation, that would also work for US localization. "13:57 nachm." is NOT a German time representation. No one uses that, that's why we have a 24 hour formating system. It's so awkward that it breaks every reading attempt.

Test code:

private void testGoogleLocaleLogic() {
    TimeZone tz_de = TimeZone.getTimeZone("Europe/Berlin");

    Calendar c_us = Calendar.getInstance(tz_de,Locale.US);
    Calendar c_de = Calendar.getInstance(tz_de,Locale.GERMAN);

    java.text.DateFormat df_date_us_short_ = java.text.DateFormat.getTimeInstance(java.text.DateFormat.SHORT,Locale.US);
    java.text.DateFormat df_date_de_short = java.text.DateFormat.getTimeInstance(java.text.DateFormat.SHORT,Locale.GERMAN);

    c_us.set(Calendar.YEAR,2018);
    c_us.set(Calendar.MONTH,2);
    c_us.set(Calendar.DAY_OF_YEAR,6);
    c_us.set(Calendar.HOUR_OF_DAY,13);

    c_de.set(Calendar.YEAR,2018);
    c_de.set(Calendar.MONTH,2);
    c_de.set(Calendar.DAY_OF_YEAR,6);
    c_de.set(Calendar.HOUR_OF_DAY,13);

    Log.d("localeTest","Android Dateformat getTimeInstance SHORT US: " + df_date_us_short_.format(c_us.getTime()));
    Log.d("localeTest","Android Dateformat getTimeInstance SHORT DE: " + df_date_de_short.format(c_de.getTime()));
    Log.d("localeTest","df_date_de_short is type of: " + df_date_de_short.getClass().getName());
}

Results in

Android Dateformat SHORT US: 1:57 PM
Android Dateformat SHORT DE: 1:57 nachm.

Why it's not 13:57 for German locale, although I set it two times in Calendar and DateFormat is also beyond my knowledge.

A solution to print out minutes and hours manually and then switch case between system locales to add or hide "PM/AM" is exactly why people invented Locales in the first place. To avoid that. Please tell me this is not the case.

UPDATES/MORE TESTING/MORE RESEARCH (forced use of java.text....):

My Moto X Style, Android 7, German locale prints:

Android Dateformat getTimeInstance SHORT US: 1:29 PM
Android Dateformat getTimeInstance SHORT DE: 1:29 nachm.
df_date_de_short is type of: java.text.SimpleDateFormat

Android Emulator NEXUS_5_API_26, US locale

Android Dateformat getTimeInstance SHORT US: 1:18 PM
Android Dateformat getTimeInstance SHORT DE: 13:18
df_date_de_short is type of: java.text.SimpleDateFormat

So the forced use of "java.text.SimpleDateFormat" works, but only on an emulator, not in real world? I'm close, maybe someone has the last 5 cents!

Banana
  • 2,435
  • 7
  • 34
  • 60
CaptainCrunch
  • 1,230
  • 14
  • 15
  • Possible duplicate of [Date Format with Locale](https://stackoverflow.com/questions/48398572/date-format-with-locale) – Ole V.V. Feb 06 '18 at 16:00
  • `TimeZone`, `Calendar` and `DateFormat` are long outdated classes, and the last in particular notoriously troublesome. See if you can get rid of them and use [`java.time`, the moden Java date and time API,](https://docs.oracle.com/javase/tutorial/datetime/) instead. I suspect that it may also solve your problem. – Ole V.V. Feb 06 '18 at 16:03
  • I've actually seen that tutorial while researching and now I went through it. I see only little aspect to localization, almost none. Very sadly it's only available from API 26 which holds me back a little. I'm starting to think this is just an Android Bug, I might give it a shot, this should be trivial, but then again what is ... – CaptainCrunch Feb 07 '18 at 10:41

2 Answers2

4

My guess earlier was right, sadly. If you don't search for it with this "guess", you'll never find it as date formatting is such a common topic. Long story short, it's an Android bug:

https://issuetracker.google.com/issues/37054851

It was fixed over a year ago. That's why the emulator works, but devices before API27 won't have the fixes as OEM don't care.

Google employee added this workaround in above bug report:

boolean use24Hour = android.text.format.DateFormat.is24HourFormat(context);
final String skeleton = use24Hour ? "Hm" : "hm";
final String pattern = android.text.format.DateFormat.getBestDateTimePattern(locale, skeleton);
DateFormat formatter = new SimpleDateFormat(pattern, locale);

... for SHORT date. MEDIUM would use skeletons of "Hms" / "hms" instead. The code above bypasses the internal code that keep the (incorrect) in-memory state that tracks whether the user prefers 12 or 24 hour time formatting. AFAIK, android.text.format.DateFormat.is24HourFormat has always used the underlying user setting. is24HourFormat() was added in API 3. getBestDateTimePattern() was only added in API 18.

That's exactly the switch case crap I feared humanity has to use in the year of 2018. We want to live on Mars, yet we can't figure out how to print time on planet Earth!

CaptainCrunch
  • 1,230
  • 14
  • 15
0

why don't u try using SimpleDateFormat instead of using default DateFormat? maybe you can do something like this:

SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy");
dateFormat.setTimeZone(tz_de);
Log.d("localeTest",dateFormat.format(c_us.getTime())));
  • Yes I would do that, however SimpleDateFormat extends DateFormat and is just a simplified version of it. But more important it can't do what DateTime does: "get localized time". It's great in simple static formating on fixed patterns, like in your example. I need a truly localized time String, by using a pattern, I destroy localization. I'd be happy to be proven wrong. – CaptainCrunch Feb 07 '18 at 10:26