Fix conversion of dates from C# to V8 #76
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
It's me again, with another correction of the date conversion π
Problems with the current approach
In #75 we introduced a date conversion from C# to V8 using the constructor V8 exposes in their C++ API that only takes one parameter (milliseconds since
1970-01-01 00:00:00
), and then using theset*
methods on the constructed date object. This is bad however, since there is no single permutation of those methods that always yields the correct value. Sorry for that! πExample:
1967-04-01 00:00:00
Depending on the timezone the milliseconds from C# could represent
1967-03-31 23:00:00
. If we now set the month to April we get the 31st of April which JavaScript interprets as the 1st of May, leading to an incorrect date of1967-05-01 00:00:00
.This is partly because we used the milliseconds from the C#
DateTime
object to construct a date value near the desired one and then manipulating it setting the year first, then month, etc. You could remedy that case by reversing the order of theset*
methods, setting the date first, and starting at1970-01-01 00:00:00
for example instead of the current date. But this would lead to other errors as shown in the next example.Example:
1972-02-29 00:00:00
If we start from
1970-01-01 00:00:00
which was not a leap year, we need to set the year first.Otherwise, if we set the month to February and the date to 29 we get the 1st of March.
This approach is therefore not feasible at all, leading to this PR.
The new approach
We instead need to use the date constructor available to JS that takes all parts of a date value to correct this. We get to it by querying the global object. This is then equivalent to something like
We also added a brute force test that iterates through all dates from
1900-01-01
to2100-01-01
to have some quality control. This has two caveats though:Tested timezones
The results are from the new test
SetAndReadDateTimeLocal_DateRange
. All other tests pass!Oberservations from the failed tests
The reason for these failures is that it is not possible with V8 to contruct these dates at
00:00:00
local time as if that time doesn't exist at all. You can test that by setting the timezone in your operating system and then running the following code in the Chrome Dev ToolsWe did not manage to get V8 to set the time back to
00:00:00
. We also tested the same dates with NodaTime, but as soon as we try to convert back to a local timezone, NodaTime agrees with V8 by setting the time to01:00:00
(or similar). Both use the IANA timezone database, so we think they are correct. It's as if00:00:00
did not exist. We currently have no solution to this problem.Detailed list of failures:
Conclusion
We sincerely think the approach of this PR is the best/most correct we can get, since both worlds unfortunately inherently disagree. Looking forward to your opinions!
Thanks!
/cc @Ablu