admin管理员组

文章数量:1026943

Firstly I hope this is not a duplicate. I have read many similar questions but can't find one with this particular issue.

I have a javascript datepicker which uses javascript date internally which has an unintended side effect. When I pick 30th April 2016 it returns a date object for midnight (00:00) on that date, but if you are in a different time zone and it is using UTC internally it returns an object which pensates for your UTC offset. So, because it is BST here the date I get back is the 30th April 00:00 GTM + 1:00 which when you turn it into an ISO string is actually 23:00 on the 29th April.

I want to send the correct date (30th April, no time) back to the server but the date string I currently get when doing this:

var newDate =  moment(newValue).toISOString();
console.log(newDate);

is this:

2016-05-19T23:00:00.000Z

So, my understanding on this is weak, but I think the datepicker is using my local time offset initially to take an hour off if and store 23:00 on the 19th as the UTC date internally, so it's already A UTC date, converting to UTC won't help.

What I need to do is use moment.js to pensate for the utcOffset and shift the date so that it is midnight on the date I chose in UTC.

Firstly I hope this is not a duplicate. I have read many similar questions but can't find one with this particular issue.

I have a javascript datepicker which uses javascript date internally which has an unintended side effect. When I pick 30th April 2016 it returns a date object for midnight (00:00) on that date, but if you are in a different time zone and it is using UTC internally it returns an object which pensates for your UTC offset. So, because it is BST here the date I get back is the 30th April 00:00 GTM + 1:00 which when you turn it into an ISO string is actually 23:00 on the 29th April.

I want to send the correct date (30th April, no time) back to the server but the date string I currently get when doing this:

var newDate =  moment(newValue).toISOString();
console.log(newDate);

is this:

2016-05-19T23:00:00.000Z

So, my understanding on this is weak, but I think the datepicker is using my local time offset initially to take an hour off if and store 23:00 on the 19th as the UTC date internally, so it's already A UTC date, converting to UTC won't help.

What I need to do is use moment.js to pensate for the utcOffset and shift the date so that it is midnight on the date I chose in UTC.

Share Improve this question asked May 1, 2016 at 15:12 jonhobbsjonhobbs 28k39 gold badges118 silver badges179 bronze badges 5
  • So, to clarify, your datepicker gives you a native JS date object. The UTC value of that date object is the value that you wish Moment to interpret as local time? – Maggie Pint Commented May 1, 2016 at 16:54
  • No, it's the opposite isn't it? Why not just call .format('YYYY-MM-DD') on your moment? In the scenario above that would give you '2016-05-20' if you are on British Summer Time. – Maggie Pint Commented May 1, 2016 at 17:17
  • It is storing a UTC date of 19th at 23:00 internally. Converting it to iso gives me that as a string which I don't want. However, javascript sees this as midnight on 20th and using .format() does indeed give me the string I want with the 20th, presumably because javascript sees the date as the 20th because it's adding in my offset automatically. I find it odd that .toISOString() will convert the UTC date to a string but .format() will format the local date. Your answer is correct though so if you put it as an answer I'll mark it correct. – jonhobbs Commented May 1, 2016 at 18:08
  • I have realised though that if the user picks a date just before midnight when the clocks change to daylight saving, then submits it to the server after midnight then it will post the wrong date to the server, but that's not something I have the energy to get involved in solving :) – jonhobbs Commented May 1, 2016 at 18:11
  • If that is indeed the behavior that you want, I can explain the why :-). Answer ing. – Maggie Pint Commented May 1, 2016 at 18:20
Add a ment  | 

1 Answer 1

Reset to default 6

What you are seeing here is the fact that the JS Date object and MomentJS both contain, internally, a Unix Time stamp in milliseconds. These time stamps are a reference to a point on the global timeline that can be converted to local time if desired.

When you use the default moment() constructor, you are telling Moment to operate in 'local' mode. What this means is that when Moment displays the date that it contains, it will convert from the UTC Unix time stamp that it contains internally, to the local time of the user.

If you wanted to keep the UTC time (which you don't) you could pass the JS Date object that you are getting from your date picker to the moment.utc() function, and then when you called .format() on that moment, you would always see the UTC time.

As an example, I am on United States Central Daylight Time right now, making my offset -5.

If I take your example UTC time stamp and pass it to the default moment constructor, I get the following:

moment('2016-05-19T23:00:00.000Z').format()
"2016-05-19T18:00:00-05:00"

As you can see, for display purposes, Moment has converted to my local time zone.

If I were to use UTC though:

moment.utc('2016-05-19T23:00:00.000Z').format()
"2016-05-19T23:00:00+00:00"

No change.

You do not need to worry about the clock change that you are talking about in your ment. Since your date picker is giving you an exact point on the global timeline, moment will always be able to correctly convert to local.

As to why .toISOString() always gives you a UTC date when you call it on a JS Date object - you can thank the TC39 mittee for that one. That is how it is supposed to work per the ES2015 spec: http://www.ecma-international/ecma-262/6.0/#sec-date.prototype.toisostring

Moment also always provides UTC for .toISOString() for the sake of consistency with the way native date works.

Firstly I hope this is not a duplicate. I have read many similar questions but can't find one with this particular issue.

I have a javascript datepicker which uses javascript date internally which has an unintended side effect. When I pick 30th April 2016 it returns a date object for midnight (00:00) on that date, but if you are in a different time zone and it is using UTC internally it returns an object which pensates for your UTC offset. So, because it is BST here the date I get back is the 30th April 00:00 GTM + 1:00 which when you turn it into an ISO string is actually 23:00 on the 29th April.

I want to send the correct date (30th April, no time) back to the server but the date string I currently get when doing this:

var newDate =  moment(newValue).toISOString();
console.log(newDate);

is this:

2016-05-19T23:00:00.000Z

So, my understanding on this is weak, but I think the datepicker is using my local time offset initially to take an hour off if and store 23:00 on the 19th as the UTC date internally, so it's already A UTC date, converting to UTC won't help.

What I need to do is use moment.js to pensate for the utcOffset and shift the date so that it is midnight on the date I chose in UTC.

Firstly I hope this is not a duplicate. I have read many similar questions but can't find one with this particular issue.

I have a javascript datepicker which uses javascript date internally which has an unintended side effect. When I pick 30th April 2016 it returns a date object for midnight (00:00) on that date, but if you are in a different time zone and it is using UTC internally it returns an object which pensates for your UTC offset. So, because it is BST here the date I get back is the 30th April 00:00 GTM + 1:00 which when you turn it into an ISO string is actually 23:00 on the 29th April.

I want to send the correct date (30th April, no time) back to the server but the date string I currently get when doing this:

var newDate =  moment(newValue).toISOString();
console.log(newDate);

is this:

2016-05-19T23:00:00.000Z

So, my understanding on this is weak, but I think the datepicker is using my local time offset initially to take an hour off if and store 23:00 on the 19th as the UTC date internally, so it's already A UTC date, converting to UTC won't help.

What I need to do is use moment.js to pensate for the utcOffset and shift the date so that it is midnight on the date I chose in UTC.

Share Improve this question asked May 1, 2016 at 15:12 jonhobbsjonhobbs 28k39 gold badges118 silver badges179 bronze badges 5
  • So, to clarify, your datepicker gives you a native JS date object. The UTC value of that date object is the value that you wish Moment to interpret as local time? – Maggie Pint Commented May 1, 2016 at 16:54
  • No, it's the opposite isn't it? Why not just call .format('YYYY-MM-DD') on your moment? In the scenario above that would give you '2016-05-20' if you are on British Summer Time. – Maggie Pint Commented May 1, 2016 at 17:17
  • It is storing a UTC date of 19th at 23:00 internally. Converting it to iso gives me that as a string which I don't want. However, javascript sees this as midnight on 20th and using .format() does indeed give me the string I want with the 20th, presumably because javascript sees the date as the 20th because it's adding in my offset automatically. I find it odd that .toISOString() will convert the UTC date to a string but .format() will format the local date. Your answer is correct though so if you put it as an answer I'll mark it correct. – jonhobbs Commented May 1, 2016 at 18:08
  • I have realised though that if the user picks a date just before midnight when the clocks change to daylight saving, then submits it to the server after midnight then it will post the wrong date to the server, but that's not something I have the energy to get involved in solving :) – jonhobbs Commented May 1, 2016 at 18:11
  • If that is indeed the behavior that you want, I can explain the why :-). Answer ing. – Maggie Pint Commented May 1, 2016 at 18:20
Add a ment  | 

1 Answer 1

Reset to default 6

What you are seeing here is the fact that the JS Date object and MomentJS both contain, internally, a Unix Time stamp in milliseconds. These time stamps are a reference to a point on the global timeline that can be converted to local time if desired.

When you use the default moment() constructor, you are telling Moment to operate in 'local' mode. What this means is that when Moment displays the date that it contains, it will convert from the UTC Unix time stamp that it contains internally, to the local time of the user.

If you wanted to keep the UTC time (which you don't) you could pass the JS Date object that you are getting from your date picker to the moment.utc() function, and then when you called .format() on that moment, you would always see the UTC time.

As an example, I am on United States Central Daylight Time right now, making my offset -5.

If I take your example UTC time stamp and pass it to the default moment constructor, I get the following:

moment('2016-05-19T23:00:00.000Z').format()
"2016-05-19T18:00:00-05:00"

As you can see, for display purposes, Moment has converted to my local time zone.

If I were to use UTC though:

moment.utc('2016-05-19T23:00:00.000Z').format()
"2016-05-19T23:00:00+00:00"

No change.

You do not need to worry about the clock change that you are talking about in your ment. Since your date picker is giving you an exact point on the global timeline, moment will always be able to correctly convert to local.

As to why .toISOString() always gives you a UTC date when you call it on a JS Date object - you can thank the TC39 mittee for that one. That is how it is supposed to work per the ES2015 spec: http://www.ecma-international/ecma-262/6.0/#sec-date.prototype.toisostring

Moment also always provides UTC for .toISOString() for the sake of consistency with the way native date works.

本文标签: javascriptCompensate for utcOffset in MomentjsStack Overflow