JSON Stringify изменяет время даты из-за UTC
-
18-09-2019 - |
Вопрос
Мои объекты date в 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);
Я попытался передать параметр replacer (второй параметр в stringify), но проблема в том, что значение уже было обработано.
Я также пробовал использовать toString()
и toUTCString()
на объекте date, но они тоже не дают мне того, что я хочу..
Кто-нибудь может мне помочь?
Решение
Недавно я столкнулся с такой же проблемой.И это было решено с помощью следующего кода:
x = new Date();
let hoursDiff = x.getHours() - x.getTimezoneOffset() / 60;
let minutesDiff = (x.getHours() - x.getTimezoneOffset()) % 60;
x.setHours(hoursDiff);
x.setMinutes(minutesDiff);
Другие советы
JSON использует Date.prototype.toISOString
функция, которая не представляет местное время - она представляет время в неизмененном UTC - если вы посмотрите на свой вывод даты, вы увидите, что вы находитесь в UTC + 2 часа, вот почему строка JSON изменяется на два часа, но если это позволяет корректно отображать одно и то же время в нескольких часовых поясах.
Просто на заметку, помните, что последняя буква "Z" в "2009-09-28T08:00:00Z" означает, что время действительно указано в UTC.
Видишь http://en.wikipedia.org/wiki/ISO_8601 для получения подробной информации.
Вот еще один ответ (и лично я считаю его более подходящим)
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 :)
Я немного опоздал, но вы всегда можете перезаписать функцию toJSON в случае даты, используя Prototype вот так:
Date.prototype.toJSON = function(){
return Util.getDateTimeString(this);
};
В моем случае Util.getDateTimeString(this) возвращает строку, подобную этой:"2017-01-19T00:00:00Z"
date.toJSON() выводит дату UTC в формате строки (поэтому добавляет к ней смещение при преобразовании в формат JSON).
date = new Date();
new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toJSON();
Обычно вы хотите, чтобы даты были представлены каждому пользователю по его собственному местному времени-
вот почему мы используем GMT (UTC).
Используйте Date.parse(jsondatestring), чтобы получить строку местного времени,
если только ты хотеть ваше местное время отображается каждому посетителю.
В таком случае воспользуйтесь методом Анатолия.
Удалось обойти эту проблему, используя 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 соответствует указанному местному времени, за исключением средства выбора даты.
вы можете использовать moment.js для форматирования по местному времени:
Date.prototype.toISOString = function () {
return moment(this).format("YYYY-MM-DDTHH:mm:ss");
};
Готовое решение для принудительного JSON.stringify
игнорировать часовые пояса:
- Чистый javascript (основанный на ответе Анатолия):
// 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>
Вот что-то действительно аккуратное и простое (по крайней мере, я так считаю :)) и не требует клонирования даты или перегрузки какой-либо из встроенных функций браузера, таких как toJSON (ссылка: Как в формате JSON упорядочить дату javascript и сохранить часовой пояс, кортси Шоусон)
Передайте функцию замены в JSON.stringify, которая упорядочивает материал сколько душе угодно!!!Таким образом, вам не нужно выполнять часовые и минутные различия или какие-либо другие манипуляции.
Я ввел консоль.регистрирует промежуточные результаты, чтобы было ясно, что происходит и как работает рекурсия.Это показывает нечто, достойное внимания:параметр value для replacer уже преобразован в формат даты 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.
*/
Я немного столкнулся с этим, работая с устаревшими материалами, где они работают только на восточном побережье США и не хранят даты в 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().
Все сводится к тому, зависит ли серверная часть вашего сервера от часового пояса или нет.Если это не так, то вам нужно предположить, что часовой пояс сервера совпадает с часовым поясом клиента, или передать информацию о часовом поясе клиента и включить это также в вычисления.
пример, основанный на серверной части 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'
Последнее, вероятно, это то, что вы хотите использовать в базе данных, если вы не хотите должным образом реализовать логику часового пояса.
Вместо того , чтобы toJSON
, вы можете использовать формат функция, которая всегда выдает правильную дату и время + GMT
Это самый надежный вариант отображения.Он принимает строку токенов и заменяет их соответствующими значениями.