-
Notifications
You must be signed in to change notification settings - Fork 47
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
Date object has significant UTC errors #114
Comments
I will try to understand and fix this bug. |
I rewrote the whole thing, and while it hasn't been extensively tested it seems to work nicely: https://github.com/questmetrics/NiL.JS |
I made some fixes for Date. Please, check it for you system. |
No, it still has lots of errors related to UTC and DST. When you ask for things like the hour, day, month, or even year of a UTC based date you can't just call the local one.
There are lots of issues like this through the code, which is why I rewrote it based on the framework DateTime, which correctly calculates every daylight saving correctly, leap-years etc. Here's an example of the issues:
The values should be:
because daylight saving changes during the year, and every UTC hour calculation has to take the target date into account.
(these only apply in Australia, as we're +10/+11) Check out my replacement here: https://github.com/questmetrics/NiL.JS/blob/develop/NiL.JS/BaseLibrary/Date.cs |
@jsobell, I tested this with your example. Work good. |
Nope:
Should say
Seriously, instead of messing around with this, why not use the DateTime object built into .NET like I did? The whole point of that object is that it tracks all of this stuff automatically, and it makes marshalling back and for to .NET so much simpler. |
I maked hotfix for it. And add test for this case. The storage of time was slightly reworked and this bug is a consequence of it. |
I checked your implementation with unit tests and found that it's incorrect. I got a lot test for fail. See sections s9_4 and s15_9 |
Well, it's getting very complicated now.
Chrome gives
which is wrong!!!!
which is correct!
This made testing a little tricky, as I was testing against the Clearscript (Chromium) engine. Re the s9_4 and s15_9 tests, I'd consider modifying the DateTime based solution for the bizarre edge-cases in those tests, but the project on GitHub doesn't currently compile due to missing Having said that, your code is getting closer... but it gives the wrong day at the moment:
Today is Sunday. This is because The other main functions seem to give the correct value now, with the only discrepancy being that in 2000 the Sydney Olympics meant they moved daylight saving to be a month earlier, and Microsoft honour this, whereas javascript doesn't. I think we can safely ignore this and return the correct value the same as .NET does :) |
You need this:
and this change in toString():
Also, |
Fix is:
|
Also, toISOString is wrong, needs:
|
With these changes the only failing tests appear to be the weird edge-cases like
which I think we can live without. internal class Program
{
public static void Main(string[] args)
{
ScriptEngine nilQM = new V8ScriptEngine();
Context nilNiL = new Context();
DateTime d = DateTime.Parse("2 Oct 2017 01:00");
DateTime end = DateTime.Parse("30 Mar 2018 01:00");
while (d < end)
{
var init = $"var d=new Date({d.Year},{d.Month - 1},{d.Day},{d.Hour},{d.Minute},{d.Second})";
nilQM.Evaluate(init);
nilNiL.Eval(init);
Compare(d, "d.valueOf()", nilQM, nilNiL, "new Date({x}).toString()");
Compare(d, "d.toString()", nilQM, nilNiL);
Compare(d, "d.toUTCString()", nilQM, nilNiL);
Compare(d, "d.getDay()", nilQM, nilNiL);
Compare(d, "d.getHours()", nilQM, nilNiL);
Compare(d, "d.getUTCHours()", nilQM, nilNiL);
Compare(d, "d.getTimezoneOffset()", nilQM, nilNiL);
Compare(d, "d.getUTCDate()", nilQM, nilNiL);
Compare(d, "d.toISOString()", nilQM, nilNiL);
Compare(d, "d.getUTCHours()", nilQM, nilNiL);
Compare(d, "d.getUTCFullYear()", nilQM, nilNiL);
d = d.AddHours(1);
}
Console.WriteLine("Done!");
}
private static void Compare(DateTime d, string script, ScriptEngine nilQM, Context nilNiL, string reverse=null)
{
var qmresult = nilQM.Evaluate(script).ToString();
var nilresult = nilNiL.Eval(script).As<string>();
if (nilresult != qmresult)
{
string feedback = "";
if (!String.IsNullOrWhiteSpace(reverse))
{
feedback =
$" (QM={nilQM.Evaluate(reverse.Replace("{x}", qmresult))} , NiL={nilQM.Evaluate(reverse.Replace("{x}", nilresult))})";
}
Console.WriteLine($"{d} : {script} : Chrome {qmresult} != NiL {nilresult} {feedback}");
}
}
} |
Output format of |
Also I fixed timezone parsing, remove timezone offset from results of |
Duplicate of #133 |
The code at the moment within Date has some serious fundamental issues.
The use of UTC requires correctly handling DST times, and at the moment they don't work correctly.
The most noticeable issue is that in many places the code says
TimeZoneInfo.Local.GetUtcOffset(DateTime.Now)
. This is only correct in operations specifically referring to.now
or the current time, as UTC offset is different for different times of year.For example, in Victoria, Australia, the offset on Jan 1st is one hour different from that on July 1st, so
TimeZoneInfo.Local.GetUtcOffset(new DateTime(2018,1,1))
(11 hours) is different toTimeZoneInfo.Local.GetUtcOffset(new DateTime(2018,7,1))
(10 hours) so the use of.Now
will give incorrect readings for six months of the year in UTC related operations.The same applies to functions such as
setHour
, where the time must be correctly used in local structure for the calculation, so the offset is critical to get correct before setting individual parts of the date.I'd suggest abandoning ticks as as the underlying value, and use the native DateTime object instead. This simplifies things hugely, as it already honours DST, and supports UTC and local natively. There's an example I adapted from Jurassic here: https://github.com/questmetrics/NiL.JS/blob/develop/NiL.JS/BaseLibrary/Date.new.cs
The text was updated successfully, but these errors were encountered: