-
Notifications
You must be signed in to change notification settings - Fork 645
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[JSRangeErrorException - "Invalid timezone name!"] Fix Intl.DateTimeFormat bug with normalizing timeZone value #571
Conversation
Hi @anton-patrushev! Thank you for your pull request and welcome to our community. Action RequiredIn order to merge any pull request (code, docs, etc.), we require contributors to sign our Contributor License Agreement, and we don't seem to have one on file for you. ProcessIn order for us to review and merge your suggested changes, please sign at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need to sign the corporate CLA. Once the CLA is signed, our tooling will perform checks and validations. Afterwards, the pull request will be tagged with If you have received this in error or have any questions, please contact us at [email protected]. Thanks! |
2cb8965
to
c42e5b8
Compare
Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Facebook open source project. Thanks! |
0d37e60
to
7991f8c
Compare
@mhorowitz has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator. |
Thank you for the detailed bug report and the fix! CircleCI seems to be having issues on Android, but our internal CI system should run tests on this. If you want to run t hem yourself, take a look at https://github.com/facebook/hermes/blob/main/android/intltest/build.gradle which is where the tests are run from. There are instructions at the top. The actual test cases come from https://github.com/tc39/test262 |
@anton-patrushev has updated the pull request. You must reimport the pull request before landing. |
@mhorowitz So what are next steps you propose? |
@anton-patrushev has updated the pull request. You must reimport the pull request before landing. |
@mhorowitz Any updates? |
@mhorowitz has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator. |
Unfortunately, the regression tests didn't behave as I expected internally, either. I got them running, and the regression tests pass. The test you added in 23616f7 did not, though. I had to tweak it a bit, now I have this:
This passes. However, I realized this doesn't (I think) test the underlying fundamental problem of case folding the time zone. If I modify the test to mangle the case:
The output is GMT, not US/Eastern:
It's possible I'm misunderstanding the change you've made, but I expected the unusual casing would succeed based on the description in the PR. What am I missing? |
@mhorowitz Did you run these tests on my branch (with modified Java code) or on other branch, which has the same Java code as the main branch (before my fix)? I will be back with answer (I have an empty project with manually patched |
@anton-patrushev I did my testing on 692ef46 which appears to to be the top revision in your PR. Is there some other revision I should be testing? |
@mhorowitz Could I ask you to run this test case (which you mentioned and tweaked) on the main hermes branch to ensure it failed. It should failed since Android Intl API doesn't work for me from the main branch. |
@anton-patrushev has updated the pull request. You must reimport the pull request before landing. |
@anton-patrushev has updated the pull request. You must reimport the pull request before landing. |
@mhorowitz FYI So you can compare it with the stable But my fix still doesn't support case insensitivity :( |
@anton-patrushev Thanks for the screen shots! This is consistent with what I see. Your changes prevent Intl from throwing an exception, but do not fix the issues with timezone case sensitivity. I'll hold off merging this for now while you investigate the fix for that. |
We're also running into this problem which unfortunately makes Hermes Intl unusable for us. @anton-patrushev unless I'm reading it wrong, I believe the remaining problem is here:
|
Thanks for highlighting it @andreialecu! But just to be on the same page. I will be back with final fix to support case insensitivity too! |
I'd like to point out something regarding the implementation in this PR. There are a bunch of timezones which may not pass through the capitalization function properly. Take a look at: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones Examples: However, I think it's possible to normalize the timezone in a different way. The original casing of the match would then be the normalized time zone name. Hopefully this makes sense. :) |
@anton-patrushev has updated the pull request. You must reimport the pull request before landing. |
Finally, I'm back :) If you would have any questions regarding my approach do not hesitate to ask me. @mhorowitz Please take a look. |
@anton-patrushev has updated the pull request. You must reimport the pull request before landing. |
@anton-patrushev has updated the pull request. You must reimport the pull request before landing. |
@mhorowitz |
@mhorowitz any updates? |
I hope to look at it this week. For the future, I don't tend to check GitHub daily, and almost never on weekends, so pinging me on Saturday morning isn't likely to get a reply until at least Monday. |
Can someone provide any info on this? Can I do something on my end to make it merged? |
Hey @Huxpro, hope you don't mind the ping. This issue is preventing Intl from working in most (I think) real-life apps on Android. Mind taking a look at the PR, please? |
@mhorowitz has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://github.com/tc39/test262/blob/main/test/intl402/DateTimeFormat/timezone-invalid.js is failing, I suspect due to applying additional locale comparisons as noted in code comments below.
I found this by running the test suite on device. The instructions are a bit scattered in the source tree, so here's what you need.
- edit
hermes/android/build.gradle
to include
"${hermesHostBuild}/build_host_hermesc/ImportHermesc.cmake",
On line 31 or so. it should be pretty clear where it goes. - Run an android emulator, or connect a device
- Run these commands
export HERMES_WS_DIR=.../parent-of-hermes-checkout
cd "$HERMES_WS_DIR"
hermes/utils/build/configure.py ./build_host_hermesc
cmake --build ./build_host_hermesc --target hermesc
cd hermes/android
./gradlew intl:prepareTest262
./gradlew intl:connectedAndroidTest
The complete tests take a couple minutes to run on my emulator. On a real device they may take longer. logcat will print output fairly continuously while it runs.
You may trip over a bug which causes a crash result like
Test failed to run to completion. Reason: 'Instrumentation run failed due to 'Process crashed.''. Check device logcat for details
If so, you can apply https://gist.github.com/mhorowitz/f314397b97f0419c53011dded9c89b89 to comment out the problematic tests.
At that point, when you rerun the tests (the final command above) you should see output like
> There were failing tests. See the report at: file:///.../build_android/intltest/reports/androidTests/connected/flavors/debugAndroidTest/index.html
Open that file in your browser, and it will show you failures. Probably, you will see HermesIntlDateFormatTest has failed. Unfortunately, the specific failure does not appear here. You can grep for it in logcat:
$ adb logcat -d | grep 'Failed Tests:'
10-06 18:50:10.244 6896 6917 V HermesIntlNumberFormatTest: Failed Tests: test262/test/intl402/DateTimeFormat/timezone-invalid.js : Invalid time zone name Europe/İstanbul was not rejected. Expected a RangeError to be thrown but no exception was thrown at all
.filter(new Predicate<String>() { | ||
@Override | ||
public boolean test(String tz) { | ||
return tz.equalsIgnoreCase(timeZone); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this is incorrect. https://tc39.es/ecma402/#sec-case-sensitivity-and-case-mapping only allows mapping/folding ascii a-z <-> A-Z. equalsIgnoreCase is probably applying additional locale-specific comparisons.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be honest I don't find it critical. It's strange requirement. But ok, that's how it is.
Any way, I believe my changes will allow map A-Z
to a-z
and vice versa and it shouldn't be critical issue. I'm finding not working America/New_York
(e.g. timezones from IANA TZ db in its original look) more important & crucial.
So I will prefer to leave it as it's right now (since it works, but with such small issues). I guess it will good enough to add test suites which will cover this case sensitivity issue in the future. And fix it.
I will try to do my best and fix it according to ECMA standards and back with result.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You just need to bring this back:
Instead of using the built-in case insensitive comparison methods.
.filter(new Predicate<String>() { | ||
@Override | ||
public boolean test(String tz) { | ||
return tz.equalsIgnoreCase(timeZone); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here
} catch (JSRangeErrorException error) { | ||
throw error; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can just remove this try/catch, it doesn't do anything.
@mhorowitz Thanks for your review! |
Summary: <!-- Thanks for submitting a pull request! We appreciate you spending the time to work on these changes. Please provide enough information so that others can review your pull request. The two fields below are mandatory. Before submitting a pull request, please make sure the following is done: 1. Fork [the repository](https://github.com/facebook/hermes) and create your branch from `main`. 2. If you've fixed a bug or added code that should be tested, add tests! 3. Ensure it builds and the test suite passes. [tips](https://github.com/facebook/hermes/blob/HEAD/doc/BuildingAndRunning.md) 4. Format your code with `.../hermes/utils/format.sh` 5. If you haven't already, complete the CLA. --> Please feel free to edit anything as necessary. Picking up where #571 left off Error: ![intl_error](https://user-images.githubusercontent.com/30021449/139603461-2ae20e1d-7ead-4fe2-ab9a-da5f647b3d19.png) Cause: #627 (comment) _Coauthored with anton-patrushev_ 🎉 _A special thanks to hcwesson_ 🙏 <!-- Explain the **motivation** for making this change. What existing problem does the pull request solve? --> Pull Request resolved: #627 Test Plan: <!-- Demonstrate the code is solid. Example: The exact commands you ran and their output, screenshots / videos if the pull request changes the user interface. --> Followed testing instructions provided by mhorowitz #571 (review) ![image](https://user-images.githubusercontent.com/30021449/139600222-316bb2e1-f718-4d15-b02e-281374a26eac.png) Reviewed By: kodafb Differential Revision: D32240632 Pulled By: neildhar fbshipit-source-id: d9582d5908b22addb31516834a58649182da5c64
Closed that, since #627 had been merged into main. |
Info
I have tried to use
hermes-engine
v0.8.0 withreact-native
v0.65-rc4. The main reason was to testIntl
API implementation since my RN project uses Hermes engine (instead of JSC) for executing JS code on Android. I have also usingdate-fns
&date-fns-tz
libraries. The second one relies onIntl
API. That's the reason why I've tried to use newhermes-engine
withIntl
API support.But when I started to testing it I had realized what something was going wrong. I had noticed what
Intl.DateTimeFormat
is broken. Below is an example which was broken byIntl.DateTimeFormat
implementation.That is piece of code which is formats date and applies provided timeZone.
utcToZonedTime
converts provided date into appropriate timeZone and returns newDate.utcToZonedTime
under the hoods usestzParsetimeZone
function which accepts stringtimeZone
value and returnsoffsetInMilliseconds
number value.This function call
isValidTimezoneIANAString
. HereisValidTimezoneIANAString
function implementation.I have added
console.log(error)
to catch statement and have seen what Intl.DateTimeFormat throws the next error:That is why
utcToZonedTime
function always converts date into UTC timezone (tzParseTimeZone
always returns0
. value)I have found only one place in Hermes source code where it can throw
JSRangeErrorException("Invalid timezone name!")
.Here is
isValidTimeZoneName
method implementation under the hood. It is simple as possible. Everything should be ok.But
isValidTimeZone
method receive already messed up timeZone string value. In my case instead of receivingAmerica/New_York
value it acceptsAMERICA/NEW_YORK
. This happens because ofnormalizeTimeZoneName
method. This method transforms timeZone string into uppercase version.That's why
TimeZone.getTimeZone("AMERICA/NEW_YORK").getID().equals("AMERICA/NEW_YORK")
will always returns false. (TimeZone.getTimeZone("AMERICA/NEW_YORK").getID()
always returns"GMT:
string)Brief Changes
normalizeTimeZoneName
method to fit into JDK 1.8java.util.TimeZone
specs.As far as I understand there are some differences between 1.7 & 1.8
java.util.TimeZone
implementation. JDK 1.7 supply case insensitive TimeZone module, while JDK 1.8 provides case sensitive module for managing TimeZones. That's why calling the next piece of code will have different behaviors.I have fixed
normalizeTimeZoneName
function to follow ECMAScripts specs and make compatibility with JDK 1.8 and higher versions.That's how it behaves now. Tested on my End. Sorry for not providing unit tests for it. I wasn't able to find out how your test system is designed.