由于 UTC,JSON Stringify 更改了日期时间

发布于 2024-08-06 04:32:48 字数 620 浏览 5 评论 0原文

由于我所在的位置,我在 JavaScript 中的日期对象始终用 UTC +2 表示。因此,像这样的

Mon Sep 28 10:00:00 UTC+0200 2009

问题是做一个 JSON.stringify 将上面的日期转换为

2009-09-28T08:00:00Z  (notice 2 hours missing i.e. 8 instead of 10)

我需要的是要遵守的日期和时间,但它不是,因此它应该是

2009-09-28T10:00:00Z  (this is how it should be)

基本上我使用这个:

var jsonData = JSON.stringify(jsonObject);

我尝试通过替换参数(stringify 上的第二个参数),但问题是该值已被处理。

我还尝试在日期对象上使用 toString()toUTCString() ,但这些也没有给我我想要的东西..

有人可以帮助我吗?

My date objects in JavaScript are always represented by UTC +2 because of where I am located. Hence like this

Mon Sep 28 10:00:00 UTC+0200 2009

Problem is doing a JSON.stringify converts the above date to

2009-09-28T08:00:00Z  (notice 2 hours missing i.e. 8 instead of 10)

What I need is for the date and time to be honoured but it's not, hence it should be

2009-09-28T10:00:00Z  (this is how it should be)

Basically I use this:

var jsonData = JSON.stringify(jsonObject);

I tried passing a replacer parameter (second parameter on stringify) but the problem is that the value has already been processed.

I also tried using toString() and toUTCString() on the date object, but these don't give me what I want either..

Can anyone help me?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(21

时常饿 2024-08-13 04:32:48

最近我遇到了同样的问题。并使用以下代码解决了这个问题:

x = new Date();
let hoursDiff = x.getHours() - x.getTimezoneOffset() / 60;
let minutesDiff = (x.getHours() - x.getTimezoneOffset()) % 60;
x.setHours(hoursDiff);
x.setMinutes(minutesDiff);

Recently I have run into the same issue. And it was resolved using the following code:

x = new Date();
let hoursDiff = x.getHours() - x.getTimezoneOffset() / 60;
let minutesDiff = (x.getHours() - x.getTimezoneOffset()) % 60;
x.setHours(hoursDiff);
x.setMinutes(minutesDiff);
简单气质女生网名 2024-08-13 04:32:48

JSON 使用 Date.prototype.toISOString 函数,该函数不代表本地时间——它代表未修改的 UTC 时间——如果您查看日期输出,您可以看到当前处于 UTC+2 小时,这就是 JSON 字符串更改两个小时的原因,但如果这允许跨多个时区正确表示同一时间。

JSON uses the Date.prototype.toISOString function which does not represent local time -- it represents time in unmodified UTC -- if you look at your date output you can see you're at UTC+2 hours, which is why the JSON string changes by two hours, but if this allows the same time to be represented correctly across multiple time zones.

听风吹 2024-08-13 04:32:48

date.toJSON() 将 UTC 日期打印为格式化的字符串(因此在将其转换为 JSON 格式时添加偏移量)。

date = new Date();
new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toJSON();

date.toJSON() prints the UTC-Date into a String formatted (So adds the offset with it when converts it to JSON format).

date = new Date();
new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toJSON();
野侃 2024-08-13 04:32:48

仅供记录,请记住“2009-09-28T08:00:00Z”中的最后一个“Z”表示时间确实是 UTC 时间。

有关详细信息,请参阅 http://en.wikipedia.org/wiki/ISO_8601

Just for the record, remember that the last "Z" in "2009-09-28T08:00:00Z" means that the time is indeed in UTC.

See http://en.wikipedia.org/wiki/ISO_8601 for details.

红焚 2024-08-13 04:32:48

强制 JSON.stringify 忽略时区的开箱即用解决方案:

  • 纯 JavaScript(基于 Anatoliy 答案):
// Before: JSON.stringify apply timezone offset
const date =  new Date();
let string = JSON.stringify(date);
console.log(string);

// After: JSON.stringify keeps date as-is!
Date.prototype.toJSON = function(){
    const hoursDiff = this.getHours() - this.getTimezoneOffset() / 60;
    this.setHours(hoursDiff);
    return this.toISOString();
};
string = JSON.stringify(date);
console.log(string);

使用时刻+时刻时区库:

const date =  new Date();
let string = JSON.stringify(date);
console.log(string);

Date.prototype.toJSON = function(){
    return moment(this).format("YYYY-MM-DDTHH:mm:ss:ms");;
};
string = JSON.stringify(date);
console.log(string);
<html>
  <header>
    <script src="https://momentjs.com/downloads/moment.min.js"></script>
    <script src="https://momentjs.com/downloads/moment-timezone-with-data-10-year-range.min.js"></script>
</header>
</html>

Out-of-the-box solution to force JSON.stringify ignore timezones:

  • Pure javascript (based on Anatoliy answer):

// Before: JSON.stringify apply timezone offset
const date =  new Date();
let string = JSON.stringify(date);
console.log(string);

// After: JSON.stringify keeps date as-is!
Date.prototype.toJSON = function(){
    const hoursDiff = this.getHours() - this.getTimezoneOffset() / 60;
    this.setHours(hoursDiff);
    return this.toISOString();
};
string = JSON.stringify(date);
console.log(string);

Using moment + moment-timezone libraries:

const date =  new Date();
let string = JSON.stringify(date);
console.log(string);

Date.prototype.toJSON = function(){
    return moment(this).format("YYYY-MM-DDTHH:mm:ss:ms");;
};
string = JSON.stringify(date);
console.log(string);
<html>
  <header>
    <script src="https://momentjs.com/downloads/moment.min.js"></script>
    <script src="https://momentjs.com/downloads/moment-timezone-with-data-10-year-range.min.js"></script>
</header>
</html>

手心的温暖 2024-08-13 04:32:48

这是另一个答案(我个人认为更合适)

var currentDate = new Date(); 
currentDate = JSON.stringify(currentDate);

// Now currentDate is in a different format... oh gosh what do we do...

currentDate = new Date(JSON.parse(currentDate));

// Now currentDate is back to its original form :)

Here is another answer (and personally I think it's more appropriate)

var currentDate = new Date(); 
currentDate = JSON.stringify(currentDate);

// Now currentDate is in a different format... oh gosh what do we do...

currentDate = new Date(JSON.parse(currentDate));

// Now currentDate is back to its original form :)
稚然 2024-08-13 04:32:48

您可以使用 moment.js 来格式化本地时间:

Date.prototype.toISOString = function () {
    return moment(this).format("YYYY-MM-DDTHH:mm:ss");
};

you can use moment.js to format with local time:

Date.prototype.toISOString = function () {
    return moment(this).format("YYYY-MM-DDTHH:mm:ss");
};
久随 2024-08-13 04:32:48

我有点晚了,但你总是可以在使用原型的日期的情况下覆盖 toJson 函数,如下所示:

Date.prototype.toJSON = function(){
    return Util.getDateTimeString(this);
};

在我的例子中,Util.getDateTimeString(this) 返回一个像这样的字符串:“2017-01-19T00:00:00Z ”

I'm a little late but you can always overwrite the toJson function in case of a Date using Prototype like so:

Date.prototype.toJSON = function(){
    return Util.getDateTimeString(this);
};

In my case, Util.getDateTimeString(this) return a string like this: "2017-01-19T00:00:00Z"

悲歌长辞 2024-08-13 04:32:48

我在处理旧的东西时遇到了这个问题,它们只在美国东海岸工作,并且不以 UTC 存储日期,这都是 EST。我必须根据浏览器中的用户输入过滤日期,因此必须以 JSON 格式传递当地时间的日期。

只是为了详细说明已经发布的这个解决方案 - 这就是我使用的:

// Could be picked by user in date picker - local JS date
date = new Date();

// Create new Date from milliseconds of user input date (date.getTime() returns milliseconds)
// Subtract milliseconds that will be offset by toJSON before calling it
new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toJSON();

所以我的理解是,这将继续并根据时区偏移量(返回分钟)从开始日期减去时间(以毫秒为单位(因此 60000) - 预计toJSON() 的时间将会增加。

I run into this a bit working with legacy stuff where they only work on east coast US and don't store dates in UTC, it's all EST. I have to filter on the dates based on user input in the browser so must pass the date in local time in JSON format.

Just to elaborate on this solution already posted - this is what I use:

// Could be picked by user in date picker - local JS date
date = new Date();

// Create new Date from milliseconds of user input date (date.getTime() returns milliseconds)
// Subtract milliseconds that will be offset by toJSON before calling it
new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toJSON();

So my understanding is this will go ahead and subtract time (in milliseconds (hence 60000) from the starting date based on the timezone offset (returns minutes) - in anticipation for the addition of time toJSON() is going to add.

千纸鹤带着心事 2024-08-13 04:32:48

JavaScript 通常将本地时区转换为 UTC 。

date = new Date();
date.setMinutes(date.getMinutes()-date.getTimezoneOffset())
JSON.stringify(date)

JavaScript normally convert local timezone to UTC .

date = new Date();
date.setMinutes(date.getMinutes()-date.getTimezoneOffset())
JSON.stringify(date)
阳光①夏 2024-08-13 04:32:48

通常,您希望向每个用户显示其本地时间的日期 -

这就是我们使用 GMT (UTC) 的原因。

使用 Date.parse(jsondatestring) 获取本地时间字符串,

除非您希望向每个访问者显示本地时间。

在这种情况下,请使用阿纳托利的方法。

Usually you want dates to be presented to each user in his own local time-

that is why we use GMT (UTC).

Use Date.parse(jsondatestring) to get the local time string,

unless you want your local time shown to each visitor.

In that case, use Anatoly's method.

硬不硬你别怂 2024-08-13 04:32:48

通过使用 moment.js 库(非时区版本)解决了这个问题。

var newMinDate = moment(datePicker.selectedDates[0]);
var newMaxDate = moment(datePicker.selectedDates[1]);

// Define the data to ask the server for
var dataToGet = {"ArduinoDeviceIdentifier":"Temperatures",
                "StartDate":newMinDate.format('YYYY-MM-DD HH:mm'),
                "EndDate":newMaxDate.format('YYYY-MM-DD HH:mm')
};

alert(JSON.stringify(dataToGet));

我正在使用 flatpickr.min.js 库。创建的结果 JSON 对象的时间与提供的本地时间匹配,但与日期选择器匹配。

Got around this issue by using the moment.js library (the non-timezone version).

var newMinDate = moment(datePicker.selectedDates[0]);
var newMaxDate = moment(datePicker.selectedDates[1]);

// Define the data to ask the server for
var dataToGet = {"ArduinoDeviceIdentifier":"Temperatures",
                "StartDate":newMinDate.format('YYYY-MM-DD HH:mm'),
                "EndDate":newMaxDate.format('YYYY-MM-DD HH:mm')
};

alert(JSON.stringify(dataToGet));

I was using the flatpickr.min.js library. The time of the resulting JSON object created matches the local time provided but the date picker.

星光不落少年眉 2024-08-13 04:32:48

这是一些非常简洁的东西(至少我相信是这样:))并且不需要操作要克隆的日期或重载任何浏览器的本机函数,例如 toJSON (参考:如何 JSON 字符串化 javascript 日期并保留时区,礼貌 Shawson)

将替换函数传递给 JSON .stringify 将内容串成你喜欢的内容!!!这样您就不必进行小时和分钟的差异或任何其他操作。

我已放入 console.logs 中查看中间结果,以便清楚地了解发生了什么以及递归是如何工作的。这揭示了一些值得注意的事情:替换器的值参数已经转换为 ISO 日期格式:)。使用此[键]来处理原始数据。

var replacer = function(key, value)
{
    var returnVal = value;
    if(this[key] instanceof Date)
    {
        console.log("replacer called with key - ", key, " value - ", value, this[key]); 

        returnVal = this[key].toString();

        /* Above line does not strictly speaking clone the date as in the cloned object 
         * it is a string in same format as the original but not a Date object. I tried 
         * multiple things but was unable to cause a Date object being created in the 
         * clone. 
         * Please Heeeeelp someone here!

        returnVal = new Date(JSON.parse(JSON.stringify(this[key])));   //OR
        returnVal = new Date(this[key]);   //OR
        returnVal = this[key];   //careful, returning original obj so may have potential side effect

*/
    }
    console.log("returning value: ", returnVal);

    /* if undefined is returned, the key is not at all added to the new object(i.e. clone), 
     * so return null. null !== undefined but both are falsy and can be used as such*/
    return this[key] === undefined ? null : returnVal;
};

ab = {prop1: "p1", prop2: [1, "str2", {p1: "p1inner", p2: undefined, p3: null, p4date: new Date()}]};
var abstr = JSON.stringify(ab, replacer);
var abcloned = JSON.parse(abstr);
console.log("ab is: ", ab);
console.log("abcloned is: ", abcloned);

/* abcloned is:
 * {
  "prop1": "p1",
  "prop2": [
    1,
    "str2",
    {
      "p1": "p1inner",
      "p2": null,
      "p3": null,
      "p4date": "Tue Jun 11 2019 18:47:50 GMT+0530 (India Standard Time)"
    }
  ]
}
Note p4date is string not Date object but format and timezone are completely preserved.
*/

Here is something really neat and simple (atleast I believe so :)) and requires no manipulation of date to be cloned or overloading any of browser's native functions like toJSON (reference: How to JSON stringify a javascript Date and preserve timezone, courtsy Shawson)

Pass a replacer function to JSON.stringify that stringifies stuff to your heart's content!!! This way you don't have to do hour and minute diffs or any other manipulations.

I have put in console.logs to see intermediate results so it is clear what is going on and how recursion is working. That reveals something worthy of notice: value param to replacer is already converted to ISO date format :). Use this[key] to work with original data.

var replacer = function(key, value)
{
    var returnVal = value;
    if(this[key] instanceof Date)
    {
        console.log("replacer called with key - ", key, " value - ", value, this[key]); 

        returnVal = this[key].toString();

        /* Above line does not strictly speaking clone the date as in the cloned object 
         * it is a string in same format as the original but not a Date object. I tried 
         * multiple things but was unable to cause a Date object being created in the 
         * clone. 
         * Please Heeeeelp someone here!

        returnVal = new Date(JSON.parse(JSON.stringify(this[key])));   //OR
        returnVal = new Date(this[key]);   //OR
        returnVal = this[key];   //careful, returning original obj so may have potential side effect

*/
    }
    console.log("returning value: ", returnVal);

    /* if undefined is returned, the key is not at all added to the new object(i.e. clone), 
     * so return null. null !== undefined but both are falsy and can be used as such*/
    return this[key] === undefined ? null : returnVal;
};

ab = {prop1: "p1", prop2: [1, "str2", {p1: "p1inner", p2: undefined, p3: null, p4date: new Date()}]};
var abstr = JSON.stringify(ab, replacer);
var abcloned = JSON.parse(abstr);
console.log("ab is: ", ab);
console.log("abcloned is: ", abcloned);

/* abcloned is:
 * {
  "prop1": "p1",
  "prop2": [
    1,
    "str2",
    {
      "p1": "p1inner",
      "p2": null,
      "p3": null,
      "p4date": "Tue Jun 11 2019 18:47:50 GMT+0530 (India Standard Time)"
    }
  ]
}
Note p4date is string not Date object but format and timezone are completely preserved.
*/
罪歌 2024-08-13 04:32:48

我遇到了同样的问题。
我解决的方法是:

  var currentTime = new Date();

  Console.log(currentTime); //Return: Wed Sep 15 13:52:09 GMT-05:00 2021
  Console.log(JSON.stringify(currentTime));  //Return: "2021-09-15T18:52:09.891Z"

var currentTimeFixed = new Date(currentTime.setHours(currentTime.getHours() - (currentTime.getUTCHours() - currentTime.getHours())));

  Console.log(JSON.stringify(currentTimeFixed)); //Return:  "2021-09-15T13:52:09.891Z"

I ran into the same problem.
The way I resolvet it was:

  var currentTime = new Date();

  Console.log(currentTime); //Return: Wed Sep 15 13:52:09 GMT-05:00 2021
  Console.log(JSON.stringify(currentTime));  //Return: "2021-09-15T18:52:09.891Z"

var currentTimeFixed = new Date(currentTime.setHours(currentTime.getHours() - (currentTime.getUTCHours() - currentTime.getHours())));

  Console.log(JSON.stringify(currentTimeFixed)); //Return:  "2021-09-15T13:52:09.891Z"
软糖 2024-08-13 04:32:48

我编写了以下代码博客,它在其中进行服务调用。它将尝试在每次提交帖子中序列化 json,并再次将其格式化为本地日期。

protected async post(endPoint: string, data, panelName?: string, hasSuccessMessage: boolean = false): Promise<Observable<any>> {
            const options = this.InitHeader(true);
            const url: string = this._baseUrl + endPoint;
    
            Date.prototype.toJSON = function () {
                return moment(this).format("YYYY-MM-DDThh:mm:00.000Z");;
            };
    
            return await this._http.post(url, data, options).pipe(map(response => {
                return this.Map<any>(response, null);
            }));
        }

I wrote the following code blog where it makes service calls.. it will try to serializable the json in every post submission, it will format to local date it again.

protected async post(endPoint: string, data, panelName?: string, hasSuccessMessage: boolean = false): Promise<Observable<any>> {
            const options = this.InitHeader(true);
            const url: string = this._baseUrl + endPoint;
    
            Date.prototype.toJSON = function () {
                return moment(this).format("YYYY-MM-DDThh:mm:00.000Z");;
            };
    
            return await this._http.post(url, data, options).pipe(map(response => {
                return this.Map<any>(response, null);
            }));
        }
裸钻 2024-08-13 04:32:48

一切都归结为您的服务器后端是否与时区无关。
如果不是,那么您需要假设服务器的时区与客户端相同,或者传输有关客户端时区的信息并将其也包含在计算中。

基于 PostgreSQL 后端的示例:

select '2009-09-28T08:00:00Z'::timestamp -> '2009-09-28 08:00:00' (wrong for 10am)
select '2009-09-28T08:00:00Z'::timestamptz -> '2009-09-28 10:00:00+02'
select '2009-09-28T08:00:00Z'::timestamptz::timestamp -> '2009-09-28 10:00:00'

如果您不愿意正确实现时区逻辑,最后一个可能是您想要在数据库中使用的示例。

All boils down to if your server backend is timezone-agnostic or not.
If it is not, then you need to assume that timezone of server is the same as client, or transfer information about client's timezone and include that also into calculations.

a PostgreSQL backend based example:

select '2009-09-28T08:00:00Z'::timestamp -> '2009-09-28 08:00:00' (wrong for 10am)
select '2009-09-28T08:00:00Z'::timestamptz -> '2009-09-28 10:00:00+02'
select '2009-09-28T08:00:00Z'::timestamptz::timestamp -> '2009-09-28 10:00:00'

The last one is probably what you want to use in database, if you are not willing properly implement timezone logic.

风吹雪碎 2024-08-13 04:32:48

您可以使用 format 函数代替 toJSON,该函数始终给出正确的日期和时间 + GMT

这是最强大的显示选项。它需要一串令牌
并将它们替换为相应的值。

Instead of toJSON, you can use format function which always gives the correct date and time + GMT

This is the most robust display option. It takes a string of tokens
and replaces them with their corresponding values.

哎呦我呸! 2024-08-13 04:32:48

我在 Angular 8 中尝试过:

  1. 创建模型:

    导出类模型 { YourDate: string |日期; }
    
  2. 在您的组件中

    模型:型号;
    model.YourDate = new Date();
    
  3. 将日期发送到您的 API 进行保存

  4. 从 API 加载数据时,您将执行以下操作:

    model.YourDate = new Date(model.YourDate+"Z");

您将根据您的时区获得正确的日期。

I tried this in angular 8 :

  1. create Model :

    export class Model { YourDate: string | Date; }
    
  2. in your component

    model : Model;
    model.YourDate = new Date();
    
  3. send Date to your API for saving

  4. When loading your data from API you will make this :

    model.YourDate = new Date(model.YourDate+"Z");

you will get your date correctly with your time zone.

欢你一世 2024-08-13 04:32:48

在这种情况下,我认为您需要将日期转换为 UNIX 时间戳,

timestamp = testDate.getTime();
strJson = JSON.stringify(timestamp);

然后您可以重新使用它来创建日期对象并格式化它。使用 javascript 和 toLocaleDateString 的示例 (https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Date/toLocaleDateString

newDateObject = new Date(JSON.parse(strJson));
newDateObject = newDateObject.toLocalDateStrin([
  "fr-FR",
]);

如果你使用 stringify 来使用 AJAX,现在它没有用了。您只需发送时间戳并在脚本中获取它:

$newDateObject = new \DateTime();
$newDateObject->setTimestamp(round($timestamp/1000));

请注意,getTime() 将返回以毫秒为单位的时间,而 PHP 函数 setTimestamp 则以秒为单位获取时间。这就是为什么您需要除以 1000 并四舍五入

In this case I think you need transform the date to UNIX timestamp

timestamp = testDate.getTime();
strJson = JSON.stringify(timestamp);

After that you can re use it to create a date object and format it. Example with javascript and toLocaleDateString ( https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Date/toLocaleDateString )

newDateObject = new Date(JSON.parse(strJson));
newDateObject = newDateObject.toLocalDateStrin([
  "fr-FR",
]);

If you use stringify to use AJAX, now it's not useful. You just need to send timestamp and get it in your script:

$newDateObject = new \DateTime();
$newDateObject->setTimestamp(round($timestamp/1000));

Be aware that getTime() will return a time in milliseconds and the PHP function setTimestamp take time in seconds. It's why you need to divide by 1000 and round.

秋叶绚丽 2024-08-13 04:32:48

在 Angular 中,将以下内容放入 index.js 脚本部分:

setTimeout(function (){
    Date.prototype.toJSON = function(){
    return new Date(this).toLocaleDateString("en-US") + " "+new Date(this).toLocaleTimeString();
}},1000);

In Angular place the following in index.js script section:

setTimeout(function (){
    Date.prototype.toJSON = function(){
    return new Date(this).toLocaleDateString("en-US") + " "+new Date(this).toLocaleTimeString();
}},1000);
弱骨蛰伏 2024-08-13 04:32:48
    let startDate = new Date('2023-01-01');
    let date= new Date(Date.UTC(startDate.getFullYear(), startDate.getMonth(), startDate.getDate(),     startDate.getHours(), startDate.getMinutes()))
    
    let jsonString = JSON.stringify(date);
    console.log(jsonString);

    let startDate = new Date('2023-01-01');
    let date= new Date(Date.UTC(startDate.getFullYear(), startDate.getMonth(), startDate.getDate(),     startDate.getHours(), startDate.getMinutes()))
    
    let jsonString = JSON.stringify(date);
    console.log(jsonString);

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文