I am getting value like 202001.
I want to covert it like January_2020.
Is there a way to convert it like this?:
202001->January_2020
i tried to do this by using Intl and it is working fine for ios but not working in android.
i tried below one.
const dateToStr = (input) => {
if (input.length !== 6) {
return "wrong date syntax, use YYYYMM";
}
const parts = input.match(/([0-9]{4})([0-9]{2})/);
if (!parts) {
return "wrong date syntax, use YYYYMM";
}
// NOTE: check syntax of parts
const formatter = new Intl.DateTimeFormat("en-EN", { month: "long" })
.format;
const formatted = formatter(
new Date(Date.UTC(parseInt(parts[1]), parseInt(parts[2]) - 1))
);
return `${formatted}_${parts[1]}`;
};
How can i get this updated value in Javascript without using any library in android and ios both?
CodePudding user response:
While you could just create a parsing function, ignoring the use of built in date formatting capabilities, or other date manipulation libraries (which as you'll learn also may not work on Android!), let's address why your use of Intl
works in iOS and not in Android as that's the much more interesting part of this question.
Why can't I use Intl
on Android?
Your React Native JS code is executing within a javascript engine, which differs between iOS and Android.
iOS - uses the JavaScriptCore (JSC) engine, crucially this is the engine used by WebKit and is sourced from the existing implementation in Safari on the device.
Android - also uses JSC, however this is not sourced from an operating system provided web browser, instead its binaries for a headless version of the JSC engine are included as an NPM dependency of React Native.
Hermes - of course both iOS and Android can be set to ignore the default and use the Hermes JS engine, which will act same as Android in this respect
Intl
is a spec predominantly useful for UIs, and is implemented in most modern browsers, including iOS Safari, which is why your code executing as part of React Native runtime is able to use it.
However as a headless JS engine, the JSC included by Android is stripped down and missing a lot of UI focused APIs, as headless JS engines tend to be used for non UI purposes so no need to add UI bloat. As such it does not have the Intl
API available.
This can be exceptionally confusing when using the React Native debugger attached to an Android simulator or Android device, as this will appear to work for Android! This is because when using the debugger, React Native will delegate its JS runtime to that of the debugger, so is actually running your JS in V8 engine provided by the Chrome browser instance on your computer (which will have the
Intl
API available).
So how to use missing internationalisation on Android?
There are a couple of ways to do this...
Use a different JSC build
You can configure Android to use a different build of JSC that has internationalisation functionality
Open your android/app/build.gradle
and you will find this chunk of config
/**
* The preferred build flavor of JavaScriptCore.
*
* For example, to use the international variant, you can use:
* `def jscFlavor = 'org.webkit:android-jsc-intl: '`
*
* The international variant includes ICU i18n library and necessary data
* allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
* give correct results when using with locales other than en-US. Note that
* this variant is about 6MiB larger per architecture than default.
*/
def jscFlavor = 'org.webkit:android-jsc: '
Use the example and substitute in the org.webkit:android-jsc-intl:
variant, or find other variant that suits your needs.
Add a polyfill
Using the intl
polyfill available on NPM, you can patch support for Intl
APIs in your code. This will always test for the presence of Intl
API before patching, so is safe to include for your iOS code too.
You can also configure only the locale packs that you require, which can help reduce the size of your app.
Importing the polyfill and locale data in your App entry file will make it available to use as Intl
anywhere in your app
npm install --save intl
// configure Intl polyfill
import 'intl';
import 'intl/locale-data/jsonp/en'; // other local data is available, import each locale that you need
You may find you also need to disable regexp caching due to further limitations within the React Native JS runtime
// https://www.npmjs.com/package/intl#regexp-cache--restore
import IntlPolyfill from 'intl';
IntlPolyfill.__disableRegExpRestore();
What about Hermes???
If using Hermes, changing JSC flavour will not work, as Hermes replaces JSC as the JavaScript runtime. However using the polyfill will also work for in Hermes builds.
Why else might I fix this?
Along with being useful for date manipulation as is your use case, patching the Intl
API in whatever form is a worthwhile endeavour in your React Native app, as it will also allow you to use the full power of internationalisation libraries such as react-intl, which can help you to implement i18n for dates, times, numbers, currencies, languages etc in a declarative manner