I have trouble with JS Date object.
I am working on timezone settings.
By creating a zic file (like /usr/share/zoneinfo/Europe/Paris) I'm able to manual set my local date time parameters.
For my tests, I'm doing an offet of 1 year.
Everything works fine on the system side :
date -u ==> Thu Jun 4 10:18:27 UTC 2015
date ==> Sat Jun 4 12:18:29 BST 2016
But
console.debug(new Date()) ==> Sun May 10 2015 13:50:27 GMT-k631 (BST)
Does someone have seen such strange behavior and Date object ?
Thanks
Thom
The browser Date object is using you clock to determine the time.
So if you set your location ( +2 hours, -5 hours etc ) there is going to be a difference between the system side and the client side.
You can "normalize" the date to Greenwich time ( +0 ) and then set the time object based on your current offset and the desired offset.
Related
Javascript Dates work with timezones. If I create a date, it sets the timezone. When I update the year of that date, I don't expect the timezone to change. It does, however. The worst thing is that it changes the timezone but not the time, causing the actual time to shift by one hour!
This causes the issue that if I have the person's birth date, and want to know his birthday this year, I cannot simply set the year to the current year using birthdate.setFullYear(2018), because it will return the birthday minus one hour. That means that it occurs one day before the actual birthday, at eleven 'o clock.
let test = new Date('1990-10-20');
console.log(test);
console.log(test.toISOString().substring(0, 10));
// 1990-10-20 ( Sat Oct 20 1990 01:00:00 GMT+0100 (Central European Standard Time) )
test.setFullYear(2000);
console.log(test);
console.log(test.toISOString().substring(0, 10));
// 2000-10-19 ( Fri Oct 20 2000 01:00:00 GMT+0200 (Central European Summer Time) === one hour too soon!! )
It might be that your timezone does not reproduce, here is my output:
"1990-10-20T00:00:00.000Z"
1990-10-20
"2000-10-19T23:00:00.000Z"
2000-10-19
The only workaround I found is substring the date and replace it as string values. How can I do it better using the Date object?
Hm, maybe it would be better to use setUTCFullYear(...) (MDN Docs) instead? At least in that case, it won't mess up the time.
let test = new Date('1990-10-20');
console.log(test);
console.log(test.toISOString().substring(0, 10));
// "1990-10-20T00:00:00.000Z")
test.setUTCFullYear(2000);
console.log(test);
console.log(test.toISOString().substring(0, 10));
// "2000-10-20T00:00:00.000Z"
BEWARE THE TIMEZONE If you want to work with just-a-date using the date object (and you more or less have to) your date objects should represent UTC midnight at the start of the date in question. In your case, to indicate a year, use UTC midnight at the start of the 1st January. This is a common and necessary convention, but it requires a lot of attention to make sure that the timezone doesn't creep back in, as you've discovered.
When you say "javascript dates work with timezones", a javascript date is a moment in time (ticks since the epoch) with handy static functions for converting that moment into a meaningful string in the local timezone (or a specified timezone). The date object itself does not have a timezone property.
So, you can create your UTC midnight year with something like...
var myDate = new Date(Date.UTC(2018,0,1)); // months are zero-indexed !
Then serialize it specifying UTC...
myDate.toISOString();
myDate.toLocaleDateString("en",{timezone:"UTC"});
I've got a UTC date through an Ajax call, e.g. "/Date(1517216466000+0100)/",
which is when printing to the console: Mon Jan 29 2018 10:01:06 GMT+0100 (W. Europe Standard Time).
What I need to do, is to let the user change the timezones: I can easily do it with e.g. moment(myDate).tz("Japan").
Then I need to save the date in it's UTC format, which I am not able to do.
I've been experimenting with moment.utc(), but for the input above, it returns 1 hour less.
How to deal with this situation? In summary:
1. Get a UTC time from a webservice
2. Let the user change the timezones
3. Save the modified date in UTC (without the timezone)
Working demo: https://stackblitz.com/edit/angular-kqrct7?file=app%2Fapp.component.html
EDIT for clarification:
Let's just have a look at the hours. What I get the date from the WCF, is 10 o'clock. The browser interprets it as 10 o'clock BUT in GMT+1 so when I convert it to UTC, it becomes 9 o'clock.
I want it to be 10 o'clock as UTC. Then, if I modify the timezone and e.g. the minutes of this date, I want to be able to get the UTC value of this date.
EDIT2: Made my question simplier for clarification
I've got a UTC date, which I get from a webservice like: "/Date(1517216466000+0100)/" which is: Mon Jan 29 2018 10:01:06 GMT+0100 (W. Europe Standard Time) when printed to console.
I add a timezone to it with moment(this.inputDate).tz("Europe/Berlin").format(), but it stays 10:01:06, I guess because of my browsers GMT+1.
I want the ORIGINAL string to be used as a UTC date AND it should remain 10:01:06, not 09:01:06 as you can see above (2nd moment example), so with the timezone "Europe/Berlin" would be 11:01:6
In the .NET JSON formatted date "/Date(1517216466000+0100)/" the timezone offset can be ignored. It represents "2018-01-29T09:01:06.000Z", where the source system was at a timezone offset of +0100. So if you don't care about the source timezone, just ignore it.
It is also an identical moment in time to Mon Jan 29 2018 10:01:06 GMT+0100 (W. Europe Standard Time), just with a different offset.
UTC is not a format, it's a time standard. If you want to use ISO 8601 format:
Extract the first numeric value
Convert to Number
Pass to the Date constructor
Call the toISOString method on the resulting Date
var s = '/Date(-1517216466000+0100)/';
console.log(new Date(+s.replace(/^[^\d-]+(-?\d+).*$/,'$1')).toISOString());
You can also parse and format it using moment.js, which according to the documentation can handle the .NET JSON format without needing to specify the format. So you can either do that or extract the time value and parse it with the "x" format token:
var s = '/Date(1517216466000+0100)/';
// Let moment.js guess the format
console.log(moment(s).utc());
// Extract time value and supply format
console.log(moment(s.replace(/^[^\d-]+(-?\d+).*$/,'$1'), 'x').utc());
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.20.1/moment.min.js"></script>
"/Date(1517216466000+0100)/" is a non-standard way to serialise a date/time. Take a look at ISO8601 which defines several standard ways to represent dates and times.
That being said let's take a look at what this gets evaluated as...
moment("/Date(1517216466000+0100)/").toDate()
gives Mon Jan 29 2018 09:01:06 GMT+0000 (GMT Standard Time) for me (in the UK)
taking just the timestamp value 1517216466000
new Date(1517216466000)
also gives Mon Jan 29 2018 09:01:06 GMT+0000 (GMT Standard Time)
this means that the +0100 is being ignored.
You're not actually modifying the time so why would you expect it to save back as anything other than Mon Jan 29 2018 09:01:06
UPDATE
But the "original" string represents Mon Jan 29 2018 09:01:06 UTC the +0100 is ignored and it's just coincidence that your offset to UTC is also +0100. An off.
Offset and timezone are 2 different things. A timezone encompasses offset to UTC as well as when/if daylight savings comes in to force. Just because it says +0100 doesn't necessarily mean (W. Europe Standard Time) as it could just as easily be (West Africa Time) which is also UTC+0100 but doesn't observe daylight savings at all.
The time you have "/Date(1517216466000+0100)/" doesn't convey enough information to say which timezone it is and JS/moment just uses the timestamp 1517216466000 and as such uses UTC. When you console.log() this the browser writes it to screen as local time Mon Jan 29 2018 10:01:06 GMT+0100 (W. Europe Standard Time) but this is only a representation of the underlying datetime.
By telling moment to use a specific time zone, it's only changing how the date/time gets displayed and doesn't actually change the time it represents.
If you use a date picker to change the date/time then you'll have to serialise the value to send to the backend in an appropriate way that the .Net app you cannot change will understand and conveys what you intend.
Example
Get date from server as var serverTime = "/Date(1517216466000+0100)/"
convert this to a JS Date using moment var time = new moment(serverTime)
Let user specify TimeZone i.e. Japan Standard Time (UTC+9) time = time.tz("Japan")
time still represents Mon Jan 29 2018 09:01:06 UTC but when displayed on screen with time.format() gives "2018-01-29T18:01:06+09:00"
You stated "I want it to be 10 o'clock as UTC". Unfortunately the value you've is NOT 10 O'clock UTC and will never be 10 O'clock UTC because it isn't. It is 9 O'clock UTC
You could parse the value you get from the server yourself but the time from the server IS 9am UTC. If you change it to 10 am UTC then you would see that as Mon Jan 29 2018 11:01:06 GMT+0100 (W. Europe Standard Time) - 11 O'clock local time.
Thanks everyone for your detailed answers, they helped me a lot in understanding my problem! However, the right solution was the following:
10 o'clock was a UTC time in the database and it got interpreted as 9 o'clock UTC in Moment.js because C# handled it as a local time. So, before sending the date to the client, I had to indicate that its a UTC:
var utcToClient = DateTime.SpecifyKind(downtime.DownTimeStartUTC, DateTimeKind.Utc)
Then, in Moment I could create a UTC with:
var jsUtc = moment.utc(downtime.DownTimeStartUTC)
Changing the timezones was a breeze with:
jsUtc.tz(userSelectedTimezone)
And saving the date in the database, I used this in C#:
var utcFromClient = Record.DownTimeStartUTC.ToUniversalTime()
I send this date from my controller in java (Spring-MVC) the type in mysql is datetime
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "..") public Date getYy() {
return this.yy;
}
as : [2015-09-30 00:00:00.0]
When i get this dates with ajax as 1443567600000 :
new Date(1443567600000) convert to Tue Sep 29 2015 23:00:00 GMT+0000 (Maroc)
So why i get wrong date off by one hour?
SOLUTION
We resolve it by
d = new Date(value) ;
d.setTime( d.getTime() - new Date().getTimezoneOffset()*60*1000 );
because it was Daylight saving time (DST) or summer time problem. good article
This JS handling of Date is a quite a head-flip.
I'm in the UK... "easy" because we're on GMT (UTC)... except during the summer months, when there's DST (British Summer Time, BST). Clocks go forward in summer and back in winter (stupidly by the way, but that's another issue!) by one hour. One day in March what is 4pm GMT is now called 5pm (BST).
summer month:
If you do new Date( '2017-08-08' ) this will give you (toString) 'Date 2017-08-08T00:00:00.000Z'.
If you do new Date( '2017-08-08 00:00' ), however, this will give you 'Date 2017-08-07T23:00:00.000Z'!
In the second case it appears JS is trying to be "helpful" by assuming that because you stipulated the hour you were specifying BST time. So it adjusts to GMT/UTC. Otherwise it doesn't... though (of course) it still produces a Date object which is specific right down to the milliseconds. Quite a gotcha!
Confirmation: a winter month... when BST is not applied:
new Date( '2018-01-01 00:00' )/ new Date( '2018-01-01' ): both give 'Date 2018-01-01T00:00:00.000Z'
As for adjusting, it appears that to undo the automatic adjustment you just go
jsDate.setTime( jsDate.getTime() + jsDate.getTimezoneOffset() * 60 * 1000 );
... this is a bit like what Youssef has written... except you have to obtain the offset from the specific Date in question... and my experiments seem to prove that you add this, not subtract it.
Really it would be much more helpful if the default string representation of JS Date gave the UTC time followed by the TZ (time zone) offset information, as with some of the ISO date formats: clearly, this information is included.
I think maybe this is a Daylight Saving Time problem. You can check your client's timezone, and your server's timezone. (web server or SQL Server)
We should probably need more data about it, but it could be that nothing is wrong here, it depends how you set and get back your date.
Basically 1443567600000 doesn't contains timezone. It represent Tue Sep 29 2015 23:00:00 from Greenwich. It's a moment in time that, of course, it different from any location that has a different timezone. The same moment, happens at different time (the midnight of GMT+1 is the 11pm of GMT).
You have to store both the time and the timezone in your DB, and possibly send back to JS, otherwise it will be always interpreted differently depends by the local time of the client.
To make an example:
var d = new Date(2015, 8, 30);
console.log(d.toJSON()); // In my case I got "2015-09-29T22:00:00.000Z"
console.log(d.toDateString()); // "Wed Sep 30 2015"
To be more specific
time = new Date("2018-06-01 " + time);
var offset = time.getTimezoneOffset();
offset = Math.abs(offset / 60);
time.setHours(time.getHours() + offset);
in this case time is equal to hours with leading zeros:minutes with leading zeros.
This will add the hours difference to the UTC.
If you pass a string to date it is treated as UTC.
I am receiving times in the an AJAX request and am converting them using the new Date() function.
I receive 2013-06-18T12:00:15Z
However, somehow I get the following after new Date():
Tue Jun 18 2013 08:00:15 GMT-0400 (EDT)
Why is it not:
Tue Jun 18 2013 12:00
See the following demo:
http://www.w3schools.com/js/tryit.asp?filename=tryjs_date_convert
This is a time zone problem. You must be in the EDT timezone (GMT-0400). To correctly parse the date you should tell the parser in which timezone your date is correct.
For you parse your date like this :
new Date('2013-06-18 12:00:15 GMT-0400')
"GMT-0400" means GMT time minus 4 hours
Or if you don't wish to reformat your string, you can use the date.getUTC* functions to get the time as you parsed it.
The full list is available at Mozilla's documentation.
I agree with Vaim Caen's answer that this is a timezone issue, but not with parsing - the date is being parsed fine, but into your local timezone, while you're expecting it to be parsed into UTC date.
This answer shows how to convert from your current timezone to UTC - applying this to the TryIt demo gives:
var msec = Date.parse("2013-06-18T12:00:15Z");
// or: var msec = Date.parse("Tue Jun 18 2013 08:00:15 GMT-0400 (EDT)");
var d = new Date(msec);
d.setTime( d.getTime() + d.getTimezoneOffset()*60*1000 );
document.getElementById("demo").innerHTML = d;
Edit: If you all you're interested in is displaying the date (no further manipulations) then you can use:
d.toUTCString()
which will show the date in GMT (for me it actually shows "GMT" so most likely not of use!)
The alternative is to add a function to the prototype to show the date in whatever format you want and use the date.getUTC* methods.
I am facing very strange issue kindly take a look at two examples below.
My Development Environment Time Zone: GMT+0500
When i use following function:
var d = new Date("Tue Mar 18 2014 00:00:00 GMT+0500");
var n = d.getUTCDate();
n = 17 which is correct (Return the UTC day of the month of a specific, local time, date-time) and everything works perfectly in my timezone.
My Clients Time Zone: GMT+0000
var d = new Date("Tue Mar 18 2014 00:00:00 GMT+0000");
var n = d.getUTCDate();
n = 18 which is wrong
any one put some light why is that? how to resolve this issue?
any help would be appreciated.
n = 18 which is wrong
No it's not. You supplied GMT+0000, which is the same as GMT or UTC. So the result from getUTCDate is of course the date you passed in.
I think you are confused because of how you worded this:
My Development Environment Time Zone: GMT+0500
My Clients Time Zone: GMT+0000
A time zone is not a numeric offset. A time zone can have an offset, or multiple offset, and includes the history of how the offsets have changed over time. See "Time Zone != Offset" in the timezone tag wiki.
So those might be the current offsets for you and your client, but that doesn't necessarily mean that they are always going to be in the same offset. If your client is in the UK, then they are at +0000 now, but they will soon be on +0100. See here for details.
Your first date is explicitly constructed with a time zone that results in the UTC date being 17. At midnight of the 18th in the timezone 5 hours ahead of UTC (GMT), it's still the 17th in London. Your second date is constructed with the explicit UTC timezone. At the time indicated by your second date, in other words, it's 5 o'clock in the morning in the first timezone.