Skip to content

Fix: Date.parse() now works the same as the browser - #2497

Open
KaustAbhinand wants to merge 4 commits into
mozilla:masterfrom
KaustAbhinand:Fix-for-#2411
Open

KaustAbhinand wants to merge 4 commits into
mozilla:masterfrom
KaustAbhinand:Fix-for-#2411

Conversation

@KaustAbhinand

Copy link
Copy Markdown

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!

@KaustAbhinand

Copy link
Copy Markdown
Author

@rbri Please review the changes, I think its fixed. I manually tested it as well. NaN is returned for invalid inputs

@KaustAbhinand

Copy link
Copy Markdown
Author

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:
FAILURE: Build failed with an exception.

[Incubating] Problems report is available at: file:///home/runner/work/rhino/rhino/build/reports/problems/problems-report.html

  • What went wrong:
    Execution failed for task ':rhino:test'.

There were failing tests. See the report at: file:///home/runner/work/rhino/rhino/rhino/build/reports/tests/test/index.html

  • Try:
    Deprecated Gradle features were used in this build, making it incompatible with Gradle 10.

Run with --scan to get full insights from a Build Scan (powered by Develocity).

BUILD FAILED in 25m 56s
You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins.

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.
124 actionable tasks: 118 executed, 6 from cache
Configuration cache entry stored.
Error: Process completed with exit code 1.

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

  • What went wrong:

Execution failed for task ':rhino-kotlin:decycleMain'.
Deprecated Gradle features were used in this build, making it incompatible with Gradle 10.

A failure occurred while executing de.obqo.decycle.gradle.DecycleWorker

Stream closed
You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins.

Run with --stacktrace option to get the stack trace.
109 actionable tasks: 102 executed, 7 from cache
Run with --info or --debug option to get more log output.
Run with --scan to get full insights from a Build Scan (powered by Develocity).
Get more help at https://help.gradle.org./

BUILD FAILED in 2m 41s
Configuration cache entry stored.
Error: Process completed with exit code 1.

@rbri

rbri commented Sep 19, 2026

Copy link
Copy Markdown
Collaborator

Will have a look

@KaustAbhinand

Copy link
Copy Markdown
Author

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).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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;

@rbri rbri Sep 20, 2026 •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this still correct? we have the < 0 check for year/mon/mday above, what do the browsers do?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

at least mday is now checked twice, maybe we can make the code a bit more logical by checking all conditions field by field

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't quite understand the field-by-field part?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe at first one if with all the checks for year, then one with all chechs for month and so on...

@KaustAbhinand

KaustAbhinand commented Sep 23, 2026 •

Copy link
Copy Markdown
Author

@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)

@KaustAbhinand

Copy link
Copy Markdown
Author

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
Similarly for Date.parse('01/01/49') - Rhino gives -662707800000 and the browser gives 2493052200000

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?

@rbri

rbri commented Sep 23, 2026

Copy link
Copy Markdown
Collaborator

@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'))");

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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))

@gbrail

gbrail commented Sep 23, 2026 via email •

Copy link
Copy Markdown
Collaborator

@KaustAbhinand

KaustAbhinand commented Sep 24, 2026 •

Copy link
Copy Markdown
Author

@rbri i have updated the test file as well.
Please review

@KaustAbhinand

Copy link
Copy Markdown
Author

And I hate to ask but can you please do research on whether we need to handle leap seconds. How does Java handle it?

Sure @gbrail, I'll do a quick read up on it.

@KaustAbhinand

Copy link
Copy Markdown
Author

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! :)

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Date.parse is more lenient than browser implementation

3 participants