admin管理员组文章数量:1134247
I have a date object that's created by the user, with the timezone filled in by the browser, like so:
var date = new Date(2011, 05, 07, 04, 0, 0);
> Tue Jun 07 2011 04:00:00 GMT+1000 (E. Australia Standard Time)
When I stringify it, though, the timezone goes bye-bye
JSON.stringify(date);
> "2011-06-06T18:00:00.000Z"
The best way I can get a ISO8601 string while preserving the browser's timezone is by using moment.js and using moment.format()
, but of course that won't work if I'm serializing a whole command via something that uses JSON.stringify
internally (in this case, AngularJS)
var command = { time: date, contents: 'foo' };
$http.post('/Notes/Add', command);
For completeness, my domain does need both the local time and the offset.
I have a date object that's created by the user, with the timezone filled in by the browser, like so:
var date = new Date(2011, 05, 07, 04, 0, 0);
> Tue Jun 07 2011 04:00:00 GMT+1000 (E. Australia Standard Time)
When I stringify it, though, the timezone goes bye-bye
JSON.stringify(date);
> "2011-06-06T18:00:00.000Z"
The best way I can get a ISO8601 string while preserving the browser's timezone is by using moment.js and using moment.format()
, but of course that won't work if I'm serializing a whole command via something that uses JSON.stringify
internally (in this case, AngularJS)
var command = { time: date, contents: 'foo' };
$http.post('/Notes/Add', command);
For completeness, my domain does need both the local time and the offset.
Share Improve this question asked Jun 28, 2015 at 4:23 XwipeoutXXwipeoutX 4,9455 gold badges31 silver badges41 bronze badges8 Answers
Reset to default 111Assuming you have some kind of object that contains a Date
:
var o = { d : new Date() };
You can override the toJSON
function of the Date
prototype. Here I use moment.js to create a moment
object from the date, then use moment's format
function without parameters, which emits the ISO8601 extended format including the offset.
Date.prototype.toJSON = function(){ return moment(this).format(); }
Now when you serialize the object, it will use the date format you asked for:
var json = JSON.stringify(o); // '{"d":"2015-06-28T13:51:13-07:00"}'
Of course, that will affect all Date
objects. If you want to change the behavior of only the specific date object, you can override just that particular object's toJSON
function, like this:
o.d.toJSON = function(){ return moment(this).format(); }
I'd always be inclined to not mess with functions in the prototype of system objects like the date, you never know when that's going to bite you in some unexpected way later on in your code.
Instead, the JSON.stringify method accepts a "replacer" function (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#The_replacer_parameter) which you can supply, allowing you to override the innards of how JSON.stringify performs its "stringification"; so you could do something like this;
var replacer = function(key, value) {
if (this[key] instanceof Date) {
return this[key].toUTCString();
}
return value;
}
console.log(JSON.stringify(new Date(), replacer));
console.log(JSON.stringify({ myProperty: new Date()}, replacer));
console.log(JSON.stringify({ myProperty: new Date(), notADate: "I'm really not", trueOrFalse: true}, replacer));
Based on Matt Johnsons 's answer, I re-implemented toJSON
without having to depend on moment
(which I think is a splendid library, but a dependency in such a low level method like toJSON
bothers me).
Date.prototype.toJSON = function () {
var timezoneOffsetInHours = -(this.getTimezoneOffset() / 60); //UTC minus local time
var sign = timezoneOffsetInHours >= 0 ? '+' : '-';
var leadingZero = (Math.abs(timezoneOffsetInHours) < 10) ? '0' : '';
//It's a bit unfortunate that we need to construct a new Date instance
//(we don't want _this_ Date instance to be modified)
var correctedDate = new Date(this.getFullYear(), this.getMonth(),
this.getDate(), this.getHours(), this.getMinutes(), this.getSeconds(),
this.getMilliseconds());
correctedDate.setHours(this.getHours() + timezoneOffsetInHours);
var iso = correctedDate.toISOString().replace('Z', '');
return iso + sign + leadingZero + Math.abs(timezoneOffsetInHours).toString() + ':00';
}
The setHours
method will adjust other parts of the date object when the provided value would "overflow". From MDN:
If a parameter you specify is outside of the expected range, setHours() attempts to update the date information in the Date object accordingly. For example, if you use 100 for secondsValue, the minutes will be incremented by 1 (minutesValue + 1), and 40 will be used for seconds.
When I stringify it, though, the timezone goes bye-bye
That’s because Tue Jun 07 2011 04:00:00 GMT+1000 (E. Australia Standard Time)
is actually the result of the toString
method of the Date
object, whereas stringify
seems to call the toISOString
method instead.
So if the toString
format is what you want, then simply stringify that:
JSON.stringify(date.toString());
Or, since you want to stringify your “command” later on, put that value in there in the first place:
var command = { time: date.toString(), contents: 'foo' };
I've created a small library that preserves the timezone with ISO8601 string after JSON.stringify
. The library lets you easily alter the behavior of the native Date.prototype.toJSON
method.
npm: https://www.npmjs.com/package/lbdate
Example:
lbDate().init();
const myObj = {
date: new Date(),
};
const myStringObj = JSON.stringify(myObj);
console.log(myStringObj);
// {"date":"2020-04-01T03:00:00.000+03:00"}
The library also gives you options to customize the serialization result if necessary.
If you have a JS Date Object and want to stringify it to preserve the timezone, then you should definitely use toLocaleDateString()
.
It is a very powerful helper function that can help you format your Date object in every way possible.
For example, if you want to print "Friday, February 1, 2019, Pacific Standard Time",
const formatDate = (dateObject : Date) => {
const options: any = {
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric',
timeZoneName: 'long'
};
return dateObject.toLocaleDateString('en-CA', options);
};
Thus, by modifying the options
object, you can achieve different styles of formatting for your Date Object.
For more information regarding the ways of formatting, refer to this Medium article: https://medium.com/swlh/use-tolocaledatestring-to-format-javascript-dates-2959108ea020
let date = new Date(JSON.parse(JSON.stringify(new Date(2011, 05, 07, 04, 0, 0))));
bvgheluwe's answer providing a modified Date.prototype.toJSON() is a good start, but does not work for non-integer timezones (Adelaide UTC+9.5, Marquesas Islands UTC -9.5 etc)
Based on his answer I provide an update that works in all timezones
Date.prototype.toJSON = function () {
const offsetHoursDecimalMins = -this.getTimezoneOffset() / 60; //Will give 9.5 for Adelaide Australia (UTC +9.5) and -9.5 for Marquesas Islands ( UTC -9.5)
const sign= offsetHoursDecimalMins>0?'+':'-';
const nAbsOffsetHours = Math.abs(Math.trunc(offsetHoursDecimalMins)); //Absolute value of offset hours with decimal truncated
const offsetMins = Math.abs(this.getTimezoneOffset() % 60); //Will give 30 for Adelaide Australia and 30 for Marquesas Islands
const strUTCOffset = `${sign}${nAbsOffsetHours.toString().padStart(2, '0')}:${offsetMins.toString().padStart(2, '0')}`; //"-09:30" for Marquesas Islands
/*The method Date.toISOString() returns UTC time in the format "2025-08-19T23:15:32.000Z",
but we want Local Time in this same format. To achieve this we create a new
date object (we don't want to change this one), and then add the offset hours
and mins and call toISOString() on this new object*/
const correctedDate = new Date(this.getFullYear(), this.getMonth(),
this.getDate(), this.getHours(), this.getMinutes(), this.getSeconds(),
this.getMilliseconds());
correctedDate.setHours(this.getHours() + offsetHoursDecimalMins); //Will add Hours and Mins (e.g 9.5 for Adelaide, -9.5 for Marquesas Islands )
const x = correctedDate.toISOString().replace('Z', '');
return `${x}${strUTCOffset}`;
};
本文标签: How to JSON stringify a javascript Date and preserve timezoneStack Overflow
版权声明:本文标题:How to JSON stringify a javascript Date and preserve timezone - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736823633a1954396.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论