Fix: Date.parse() now works the same as the browser - #2497
KaustAbhinand wants to merge 4 commits into
Conversation
|
@rbri Please review the changes, I think its fixed. I manually tested it as well. NaN is returned for invalid inputs |
|
2 CI jobs have failed, but I'm unable to isolate the cause though. Particularly the Java 21 build and test. Can't really tell whats happening. I've tried to re-trigger the CI to see if they fail again. I got these errors: Java 21 build & test: [Incubating] Problems report is available at: file:///home/runner/work/rhino/rhino/build/reports/problems/problems-report.html
BUILD FAILED in 25m 56s For more on this, please refer to https://docs.gradle.org/9.4.0/userguide/command_line_interface.html#sec:command_line_warnings in the Gradle documentation. Rhino Test: FAILURE: Build failed with an exception. [Incubating] Problems report is available at: file:///home/runner/work/rhino/rhino/build/reports/problems/problems-report.html
Execution failed for task ':rhino-kotlin:decycleMain'.
BUILD FAILED in 2m 41s |
|
Will have a look |
|
Well the CI is green now, suppose the re-run did it |
| } | ||
| } | ||
| if (year < 0 || mon < 0 || mday < 0) return ScriptRuntime.NaN; | ||
| // Reject out of range fields (output NaN instead of rolling over). |
There was a problem hiding this comment.
maybe we can improve this comment a bit, the first part is only true for the line before
the second part is only of some meaning for people knowing that we did the rollover before, all others are confused
There was a problem hiding this comment.
Should I delete the comment entirely?
| if (hour > 24 || min > 59 || sec > 59) return ScriptRuntime.NaN; | ||
| if (hour == 24 && (min > 0 || sec > 0)) return ScriptRuntime.NaN; | ||
|
|
||
| if (sec < 0) sec = 0; |
There was a problem hiding this comment.
is this still correct? we have the < 0 check for year/mon/mday above, what do the browsers do?
There was a problem hiding this comment.
Well Date.parse('20/15/26') did give an NaN, I checked it in the browser as well.
| if (year < 0 || mon < 0 || mday < 0) return ScriptRuntime.NaN; | ||
| // Reject out of range fields (output NaN instead of rolling over). | ||
| if (mon > 11) return ScriptRuntime.NaN; | ||
| if (mday < 1 || mday > DaysInMonth(year, mon + 1)) return ScriptRuntime.NaN; |
There was a problem hiding this comment.
at least mday is now checked twice, maybe we can make the code a bit more logical by checking all conditions field by field
There was a problem hiding this comment.
I didn't quite understand the field-by-field part?
There was a problem hiding this comment.
Maybe at first one if with all the checks for year, then one with all chechs for month and so on...
|
@rbri Hi! So sorry for the delays I have changed the if-conditions to make them field-by-field - (month, hour, year, minutes, seconds) Hopefully its fine now! Please review it 😄 (By mistake I put the PR number as the issue number in the commit message) |
|
Another note though, I discovered another issue (was not sure if it was in the scope for this PR, so I didn't implement it). For inputs like Date.parse('02/12/26') - Rhino gives -1384925400000 and the browser gives 1770834600000 For 01/01/50 and 12/31/99 though, the browser and Rhino give the same output. But here, the NaN checks work fine though, so I committed it. Thought I would report this behaviour before I do anything. Should I create a new issue for this? |
|
@KaustAbhinand please make a new issue will review this on sunday, sorry |
| // Parsing a time that is out of range - Needs to give an NaN. | ||
| ctorDateTimeString("NaN", "String(Date.parse('01/01/2026 25:00'))"); | ||
| ctorDateTimeString("NaN", "String(Date.parse('01/01/2026 10:75'))"); | ||
| ctorDateTimeString("NaN", "String(Date.parse('01/01/2026 10:30:75'))"); |
There was a problem hiding this comment.
mybe you can add tests for the border cases here
- min 59/60
- sec 59/60 and
- also for the several hour checks ((hour > 24 || (hour == 24 && (min > 0 || sec > 0))
|
And I hate to ask but can you please do research on whether we need to
handle leap seconds. How does Java handle it?
|
|
@rbri i have updated the test file as well. |
Sure @gbrail, I'll do a quick read up on it. |
|
Well I've done some done some poking around with Claude, and read Oracles's docs on how a leap second is handled. Here is what I've gathered. Java's date class only reflects UTC, it is intended to reflect the coordinated universal times, but it depends on the host environment of the JVM. But the OS is the real limitation - nearly all of the modern OS' assume a day as 86,400 seconds, whereas the UTC inserts a second as the last second of Dec 31 or June 30. But the doc also says that the computer clocks aren't accurate enough to reflect this distinction. I guess it ultimately means that Java ignores this altogether. Whether Rhino needs to implement it? Well ECMAScript's Date object is designed to ignore leap seconds. Time is measured in milliseconds since the epoch using a simplified model where every day has exactly 86,400,000 ms — leap seconds don't exist in this model at all. (This I have quoted from Claude) And also, the parseISOString method already has a check - if sec > 59 - defined as NaN. So anyway, the default handling is to ignore it. https://docs.oracle.com/javase/8/docs/api/java/util/Date.html - this was the Docs I had looked up. @gbrail, I hope it answers your question! :) |
Hello @rbri! This is the PR for the issue #2411
Closes #2411
What I changed
Nothing much really. Only the file NativeDate.java had to be changed.
The method changed was: date_parseString - I added more if-cases when the month, day and time are out of range and made them return NaN, instead of them rolling over to the next month or day like they used to.
Tests
I have added new methods in NativeDateTest.java. All the test cases pass.
Conclusion
I think its fixed. Please review the changes. Thanks!