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


98

由于我所在的位置,我在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上的第二个参数),但问题是该值已被处理。

我也尝试在date对象上使用toString()and toUTCString(),但是这些也不能给我我想要的东西。

谁能帮我?


17
2009-09-28T10:00:00Z 在时间不表示同一时刻Mon Sep 28 10:00:00 UTC+0200 2009。将ZISO 8601日期指UTC和UTC在10点是不同的时间一瞬间到+0200 10点。希望将日期与正确的时区序列化是一回事,但是您要我们帮助您将日期序列化为明确,客观上是错误的表示形式。
Mark Amery

1
为了增加标志的评论,在大多数情况下,你的日期时间存储为UTC时间,因此可以支持用户在不同的时区的最佳实践
JoeCodeFrog

Answers:


67

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

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

是的,但这是如果该网站在我的国家/地区使用,或者在美国等其他国家/地区使用-不会是2 ...
mark smith

显然,应该计算该值。
Anatoliy

3
谢谢...实际上,我在这里找到了一个很棒的库,blog.stevenlevithan.com/archives/date-time-format为此, 您需要做的所有事情(也许会帮到您),您传递false并且不会转换。var something = dateFormat(myStartDate,“ isoDateTime”,false);
马克史密斯

11
这是不正确的,它使你的代码的非时区安全-你应该修正时区,当你阅读的日期了。
olliej

4
这个答案是错误的。OP并未意识到“ 2009-09-28T08:00:00Z”和“ Mon Sep 28 10:00:00 UTC + 0200 2009” 在时间完全相同,并且实际上正在调整时区偏移错误的时间。
RobG '17

41

JSON使用的Date.prototype.toISOString功能不代表本地时间-它代表未经修改的UTC时间-如果查看日期输出,您会看到自己处于UTC + 2小时,这就是JSON字符串更改两个小时的原因,但是如果这样允许在多个时区正确显示同一时间。


2
没想到这一点,但是你是对的。这是解决方案:我可以使用原型指定任何我喜欢的格式。
racs 2013年


9

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

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 :)

@Rohaan感谢您指出这一点,但问题上的标记提到了JavaScript。
2015年8

6

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

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

6
通常,最好对代码的功能进行解释。这使新开发人员可以了解代码的工作原理。
卡勒布

您能否解释答案中的代码为何起作用?
Cristik '17

这对我也有效,但是您能解释一下您是如何做到的吗?
Deven Patil '18

我将尝试解释此代码的第二行。. date.getTime()以毫秒为单位返回时间,因此我们也应将第二个操作数也转换为毫秒。由于date.getTimezoneOffset()返回的偏移量以分钟为单位,因此我们将其乘以60000,因为1分钟= 60000毫秒。因此,通过从当前时间减去偏移量,我们可以得到UTC时间。
Maksim Pavlov


3

我有点晚了,但是在使用Date的Date的情况下,您总是可以覆盖toJson函数,如下所示:

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

就我而言,Util.getDateTimeString(this)返回如下字符串:“ 2017-01-19T00:00:00Z”


2
请注意,覆盖浏览器全局变量可能会破坏您嵌入的第三方库,这是一个很大的反模式。绝对不要在生产中这样做。
jakub.g

2

通常,您希望将日期显示在每个用户自己的本地时间中,

这就是为什么我们使用GMT(UTC)。

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

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

在这种情况下,请使用Anatoly的方法。


2

通过使用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对象的时间与提供的本地时间匹配,但与日期选择器匹配。


2

开箱即用的解决方案,可强制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);

使用moment.js库:

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>


2

我碰到了一些遗留问题,这些遗留问题只在美国东海岸起作用,而不在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))-预计将添加时间到JSON()。


1

这是一件真正简洁的事情(至少我相信是这样:)),不需要克隆任何日期就可以操作或重载toJSON等浏览器的任何本机功能(参考:如何对JSON日期进行JSON字符串化并保留时区,Coursy 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.
*/

1

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

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

0

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

一个基于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'

如果您不希望正确实现时区逻辑,则最后一个可能是您要在数据库中使用的。


0

toJSON您可以使用格式功能代替,始终提供正确的日期和时间+GMT

这是最可靠的显示选项。它接受一串标记并将其替换为其相应的值。


0

我在角度8中尝试过:

  1. 创建模型:

    export class Model { YourDate: string | Date; }
  2. 在你的组件中

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

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

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

您将正确获取您所在时区的日期。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.