119

由于我所在的位置,我在 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(),但这些也没有给我我想要的东西..

谁能帮我?

4

18 回答 18

73

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

x = new Date();
let hoursDiff = x.getHours() - x.getTimezoneOffset() / 60;
let minutesDiff = (x.getHours() - x.getTimezoneOffset()) % 60;
x.setHours(hoursDiff);
x.setMinutes(minutesDiff);
于 2009-09-28T11:39:56.760 回答
48

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

于 2009-09-28T17:50:39.180 回答
22

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

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

于 2009-09-28T18:18:49.407 回答
17

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

date = new Date();
new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toJSON();
于 2017-01-04T15:13:53.697 回答
12

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

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 :)
于 2014-07-25T00:50:29.187 回答
10

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 + moment-timezone 库:

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>

于 2019-04-29T14:41:31.477 回答
4

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

Date.prototype.toISOString = function () {
    return moment(this).format("YYYY-MM-DDTHH:mm:ss");
};
于 2018-12-02T10:04:46.763 回答
3

我有点晚了,但你总是可以覆盖 toJson 函数,以防 Date 使用 Prototype,如下所示:

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

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

于 2017-01-19T21:14:11.667 回答
3

我在处理遗留的东西时遇到了一些问题,它们只在美国东海岸工作,不以 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() 。

于 2019-08-06T00:02:48.000 回答
3

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

date = new Date();
date.setMinutes(date.getMinutes()-date.getTimezoneOffset())
JSON.stringify(date)
于 2020-02-25T12:01:07.227 回答
2

通常,您希望以每个用户自己的当地时间向每个用户显示日期 -

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

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

除非您希望向每位访问者显示您的当地时间。

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

于 2009-09-28T13:34:15.400 回答
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 对象的时间与提供的本地时间匹配,但与日期选择器匹配。

于 2017-05-20T09:33:49.047 回答
1

这是一些非常简洁和简单的东西(至少我相信:))并且不需要操作要克隆的日期或重载任何浏览器的本机函数,如 toJSON(参考:How to JSON stringify a javascript Date and preserve timezone,由 Shawson 提供)

将替换函数传递给 JSON.stringify ,将内容字符串化为您的心脏内容!!!这样您就不必进行小时和分钟差异或任何其他操作。

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

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.
*/
于 2019-06-11T13:21:42.973 回答
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'

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

于 2014-06-20T06:55:52.357 回答
0

而不是toJSON,您可以使用格式函数,它总是给出正确的日期和时间 +GMT

这是最强大的显示选项。它接受一串标记并用它们对应的值替换它们。

于 2016-05-19T17:45:18.667 回答
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");

您将使用您的时区正确获取您的日期。

于 2020-03-03T13:16:27.830 回答
0

在这种情况下,我认为您需要将日期转换为 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 和round.

于 2020-10-30T11:06:43.500 回答
0

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

  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"
于 2021-09-15T18:54:05.783 回答