5

We have an android app which more or less constists of only a webview, displaying a webapp. At some point, we want to display some timestamp to the user and use the following code

let dateString = new Date().toLocaleTimeString();

The problem is, this always produces a 12h time representation (ie with AM/PM, for instance 3:15 PM instead of 15:15), even if we set the device to use 24h clock (and the device does respect this setting, because we see the correct time in the statusbar). We also set the device to use German language and removed the english language settings. No luck either. The device locale is used, as our app is shown in the correct language, but the timestrings are still wrong.

window.navigator.language  -> "de-AT"
new Date().toLocaleTimeString(); -> "6:10:13 PM"
new Date().toLocaleTimeString(window.navigator.language); -> "18:10:32"

At a first glance, the last line seemed as a possible workaround, but if language is for instance "en-US" this will always return 12h format, regardless whether the os is configured for using 24h clock or not.

I'm aware of this question, which seems somehow related to this issue, but the answers don't work for us.

Using various virtual devices I found out, it still works correctly on chrome 58 (on API 26) but does not work any more on chrome 61 (on API 27). Currently testing at chrome 70 beta, the problem still persists.

It's also important to note, that it works correctly in chrome itself (ie if I display a time stamp in a test website, it uses the system settings), but only fails in the webview.

Our current workaround is to generate timestamps via native app, but that seems rather clumsy.

UPDATE

I know I can do some things on the webapp side like overriding toLocaleTimeString (which in fact, I already did to get the correct format from the native app).

My question is more about: Is there any known changed behaviour (and maybe a setting to reverse this) in the native WebView which causes this issue to happen, because this works/worked like a charm on devices with Chrome <= 58.

In the meantime I filed an issue with chromium, they were able to reproduce it. Maybe this will get fixed in one of the next versions ...

UPDATE 2

The issue is already fixed on google's side and may be rolled out with some future update. In the meantime I will continue to use my current override of toLocaleTimeString() which calls back to the native app ...

derpirscher
  • 14,418
  • 3
  • 18
  • 35
  • Well, I know the exact output format is implementation dependent. But it should at least somehow reflect the correct locale and not always use en-US. It's working in chrome browser, which uses the same code. It's working (kind of) if I define the locale as parameter. So it's quite save to assume, that this is an issue with the initialization of the webview. – derpirscher Oct 16 '18 at 20:24
  • From the specifications: "This function returns a string value. The contents of the string are implementation-dependent, but are intended to represent the “time” portion of the Date in the current time zone in a convenient, human- readable form that corresponds to the conventions of the host environment’s current locale". I know that's not an exact specification of the output, but outputting en-US conventions on a de-DE system is, in my opinion, against specifications. Especially if the same product in another environment acts differently – derpirscher Oct 16 '18 at 20:34
  • fair enough, just don't use localeString()s if you don't like the output... – dandavis Oct 16 '18 at 20:36
  • I would like the output, if it behaved like specified. I also have a workaround, which I find rather clumsy. Furthermore this worked as expected up to at least version 58 of chrome. Therefore I really see it as an issue (unless someone points out an official document where this behavior change is explained) and the intention of my question is to find out whether someone else has stumbled upon this and solved it without replacing every occurrence of `toLocaleTimeString` – derpirscher Oct 16 '18 at 20:46
  • you can re-define the method. ex: `Date.prototype.toLocaleTimeString = function(){return String(this).bold();}; new Date().toLocaleTimeString(); // has bold tags` using something like moment.js. you can also use the toISOString() to get a 24-hour version, but you'll need to first offset the date by the local timezone offset, which takes a little math but isn't difficult. – dandavis Oct 16 '18 at 20:49
  • The problem is, in JS there is no reliable way of knowing whether the device is set to use a 24h clock or not. `toLocaleTimeString` used to go along with os settings up to version 58 of chrome. So even on an english system, which was set to 24h clock, it delivered something like `22:58:43` instead of `10:58:43 PM` which was consistent with the device clock. Now `toLocaleTimeString()` and `toToLocaleTimeString('en-US')` always return `10:58:43 PM`regardless of the os-settings – derpirscher Oct 16 '18 at 21:12
  • try using options https://stackoverflow.com/questions/22347521/change-time-format-to-24-hours-in-javascript – isma3l Oct 18 '18 at 22:53
  • @isma3l i know this possibility, but there's no no way to find the system's locale settings in JavaScript. – derpirscher Oct 19 '18 at 07:05

1 Answers1

2

Please try overriding the function Date.prototype.toLocaleTimeString

let f = Date.prototype.toLocalString;

Date.prototype.toLocalString = function(){
  let s = f();
  //since the method fails for US-locale manupulate s as required when locale is US and system is set to show 24 hr 
  
  // if ends with AM - just delete "AM"
  // if ends with PM - add 12 to hr and delete "PM"
  return s;
}
---please avoid directly modifying prototype of inbuilt JS objects--- let me also point out that it is not advisable to play with inbuilt object of JS as it may break or interrupt execution of some external libraries. So better create a new object and modify prototype of that object - use prototypical inheritance.
Mayank Kumar Chaudhari
  • 16,027
  • 10
  • 55
  • 122
  • Sorry, but nope. I want to have a localeString which reflects the systems settings, ie get a 24h time when the android device is set to 24h clock and get a 12h time when the android device is set to 12h time. Your suggestion always delivers a 24h time, which moreover is wrong for 12:00 AM (which is 00:00 in a 24h clock and not 12:00) and 12:00 PM (which is 12:00 in a 24h clock and not 24:00). – derpirscher Oct 19 '18 at 14:27
  • Thanks for pointing out. And sorry for not making answer very clear. 1. FOCUS - try to override the method. 2. I have clearly written that only modify the date when a. The locale is the one for which date does not reflect system format (in this case US Locale) and b. When system is set to 24 hr. – Mayank Kumar Chaudhari Oct 19 '18 at 18:07
  • Since you seem to be very advanced programmer, let me also point out that it is not advisable to play with inbuilt object of JS as it may break or interrupt execution of some external libraries. So better create a new object and modify prototype of that object - use prototypical inheritance. – Mayank Kumar Chaudhari Oct 19 '18 at 18:13
  • Try setting webchrome client along with webview client.Not sure if it helps in your case. myWebView.setWebChromeClient(new WebChromeClient()); – Mayank Kumar Chaudhari Oct 22 '18 at 07:47