React-native: toLocaleString has erroneous format on Android

Created on 14 Dec 2018  路  11Comments  路  Source: facebook/react-native

Is this a bug report?

Yes

Have you read the Contributing Guidelines?

Yes

Environment

Environment:
OS: macOS Mojave 10.14.1
Node: v11.1.0
Yarn: 1.12.3
npm: 6.4.1
Watchman: 4.9.0
Xcode: Xcode 10.0 Build version 10A255
Android Studio: 3.1.3 Build #AI-173.4819257

Packages: (wanted => installed)
react: 16.4.1 => 16.4.1
react-native: 0.57.0 => 0.57.0

Target Platform: Android (8.0)

Steps to Reproduce

  1. Open a fresh React Native project
  2. Make sure you're not debugging JS remotely
  3. Try to use toLocaleString on a Date() object
  let formatted = new Date('2017-11-17T10:59:30.527Z').toLocaleString('de-DE', {
    timeZone: 'Europe/Zurich',
    year: 'numeric',
    month: 'numeric',
    day: 'numeric',
    hour: 'numeric',
    minute: 'numeric',
  })
  1. Either write up a simple component to display text or do an alert/console.log with the aforementioned variable.

Expected Behavior

The expected string should be as follows:

Input: 2017-11-17T10:59:30.527Z -> Output: 17.11.2017, 11:59

Actual Behavior

The resulting string is as follows:

Input: 2017-11-17T10:59:30.527Z -> Output: Fri Nov 17 11:59:30 2017

My contention is that this is an issue with the underlying JS engine that Android uses, and handles it differently as opposed to the integrated JS engine on iOS, hence the variance in the date format. For this reason if you open a remote debugged, say on Chrome, you will actually get the correct format, due to the different JS engine handling it, but if you switch off the debugger and resume using the application whilst not debugging remotely, the incorrect format will be shown.

Reproducible Demo

Here's an example Expo project that shows the behaviour, toggle between iOS and Android to see the difference in the output.

https://snack.expo.io/Bk3unwhyM

Related:

12597 #16867

Bug JavaScript Android Locked

Most helpful comment

@hramos the updated JSC doesn't include the Intl modules. toLocaleString still won't work on 0.59. Please reopen this issue.

All 11 comments

Thanks for the report. We're working on upgrading the JS VM that is bundled in Android, lets check back up on this issue once that task is done.

Excellent news, thanks for the update.

I get inconsistencies when using toLocalString to format numbers across different android devices which seems the oddest.

The JSC was updated on Android. This will be reflected in release 0.59, and is already available on master.

@hramos the updated JSC doesn't include the Intl modules. toLocaleString still won't work on 0.59. Please reopen this issue.

@hramos @leethree Just checked this. toLocaleString still doesn't work in Android on 0.59.2.

In that case, you'll need to follow the instructions at https://github.com/react-native-community/jsc-android-buildscripts for building your own JavaScriptCore flavor, with Intl included. As of 0.59, the JSC is pulled from npm, so pointing your project to use an arbitrary JSC build should be straightforward. I believe there's ongoing work to reduce the friction here in a future release, but for now I'll leave this closed as we don't intend to switch the default JSC at this time.

For Android use
https://www.npmjs.com/package/currency-formatter
var currencyFormatter = require('currency-formatter');
currencyFormatter.format(1000000, { code: 'USD' });
i have used this in react native android app and its working fine.

For both ios and android
import currencyFormatter from 'currency-formatter';
export const currencyFormat = (value) => {
if(Platform.OS === 'ios'){
return Number(value.toFixed(2)).toLocaleString('en-US', { style: 'currency', currency: 'USD' });
}else {
return currencyFormatter.format(value, { code: 'USD' });
}
}

You don't have to implement entire JSCore for this. Check my answer here.
You can also check other answers for currency and number formats.

Hope this helps others too.

In my opinion toLocaleString is very commonly used API and it's frustrating to find out it doesn't work in runtime and it's not documented in any way. Asking every developer to come up with their own workaround does not make sense to me. Hopefully #24276 will be released with 0.60 so we can select intl variant of JSC.

This is still broken.

Running new Date('2019-05-13T00:00:00+10:00').toLocaleString() with the device set to Australia/Brisbane (which is also +10) results in an output of '5/12/2019, 2:00:00 PM'. With options passed in, it looks as tho it just renders the dates in GMT. ('May 12, 2:00:00 PM GMT')

I'm running React Native 0.59.8, with the latest JSC from jsc-android-buildscripts, and followed the Intl steps as outlined here.

Unsure what else I need to do here to get it to work. I would have thought using the JSC with Intl compiled into it would result in the essentially the same JSC as ships with the iPhone.

Was this page helpful?
0 / 5 - 0 ratings