moment / luxon

⏱ A library for working with dates and times in JS
https://moment.github.io/luxon
MIT License
15.12k stars 728 forks source link

Luxon weekdayShort giving null value for all dates | React native IOS real device only #1500

Closed ashishmangukiya closed 6 months ago

ashishmangukiya commented 10 months ago

Describe the bug I am using luxon library to manage dates in my iOS application which is developed using react-native. In android it is working fine but in iOS real device it is giving null value from any date.

To Reproduce Install latest luxon library in React native application. Start iOS application in real device. Use DateTime.now().weekdayShort and console it, It will give null value

Actual vs Expected behavior Expected output should be like 'Mon', 'Tue' etc

Additional context It is working fine in iOS simulator but in real device it is giving null value for all dates

diesieben07 commented 10 months ago

React Native uses Hermes as its JavaScript engine, which unfortunately has many shortcomings in terms of its Intl.DateTimeFormat API implementation. However, I am unable to reproduce this in Expo: https://snack.expo.dev/dVh0QsfdD (I do not have access to a physical iOS device). Included in the code is a test to do the same thing Luxon does using the Intl.DateTimeFormat API. Please test, if this code reports the correct value on your device. If not, this is a problem with your runtime, not with Luxon.

ashishmangukiya commented 10 months ago

@diesieben07 The issue is only in iOS real device, Hermes is been used for Android only and not for iOS. For iOS, JavascriptCore engine is been used. I opened your expo link and run it on real iOS device. again same issue Link.

diesieben07 commented 10 months ago

I will test on a real device later today and try to debug the problem.

ashishmangukiya commented 10 months ago

Ok, If you need any help on debugging then let me know.

diesieben07 commented 10 months ago

I have now confirmed that this indeed an issue with Hermes. Your statement that Hermes is only used on Android is incorrect. If I open the Expo link on a real iOS device, then global.HermesInternal is defined, meaning Hermes is in use. Please verify again if you are really not using Hermes.

The following code demonstrates the problem:

const intl = new Intl.DateTimeFormat(undefined, { weekday: "short" });
console.log(intl.formatToParts());

In a correct implementation of DateTimeFormat (including in Safari on iOS) this produces the following:

[{ type: "weekday", "value": "Thu" }]

Hermes instead produces:

[{ type: "literal", "value": "Thu" }]

We might be able to add a work-around for this case, but I am reluctant to do so, because of potential negative effects on properly functioning engines.

AndrewKirkovski commented 8 months ago

Is there a known work around for this issue except disabling hermes for IOS?

diesieben07 commented 8 months ago

Is there a known work around for this issue except disabling hermes for IOS?

You could install a Polyfill for the Intl API.

krystiansliwa commented 6 months ago

Is there a known work around for this issue except disabling hermes for IOS?

You could install a Polyfill for the Intl API.

I have the same issue. What polyfill you are referring to?

diesieben07 commented 6 months ago

I have the same issue. What polyfill you are referring to?

https://formatjs.io/docs/polyfills/intl-datetimeformat/

SerSerch commented 4 months ago

@diesieben07 I don't know why exactly this works on IOS

export function dateFormat(fmt, date) {
  try {
    const regex = /(\w)\1+|\w/g;
    const localDate = date || DateTime.local();

    return typeof fmt === 'string'
      ? fmt.replace(regex, function (match) {
          switch (match) {
            case 'EEE':
            case 'ccc':
              return localDate.toLocaleString({weekday: 'short'});
            case 'EEEE':
            case 'cccc':
              return localDate.toLocaleString({weekday: 'long'});
            case 'MMM':
            case 'LLL':
              return localDate.toLocaleString({month: 'short'});
            case 'MMMM':
            case 'LLLL':
              return localDate.toLocaleString({month: 'long'});

            // case 'DD':
            // case 'DDD':
            // case 'DDDD':
            // case 'ff':
            // case 'FF':
            //   return 'problem';

            default:
              return localDate.toFormat(match);
          }
        })
      : '';
  } catch (err) {
    console.log('ERROR[datetime] dateFormat', err);
  }
}