JSON Stringify는 UTC로 인해 날짜 시간을 변경합니다.


99

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()날짜 개체에 있지만 이러한 나도 원하는 걸주지 않는다 ..

누구든지 나를 도울 수 있습니까?


17
2009-09-28T10:00:00Z 시간에 같은 순간을 나타내지 않는Mon Sep 28 10:00:00 UTC+0200 2009. Z에서 ISO 8601 날짜는 UTC를 의미하며, UTC 10시 방향입니다 시간에 다른 순간 0200에서 10시 방향. 날짜가 올바른 시간대로 직렬화되기를 바라는 것이 하나이지만, 명확하고 객관적으로 잘못된 표현으로 직렬화하는 데 도움을 요청하는 입니다.
Mark Amery

1
마크 주석에 추가하려면, 대부분의 경우 그것은 당신이 다른 시간대에있는 사용자를 지원할 수 있도록 UTC 시간으로 당신의 날짜 시간을 저장하는 것이 가장 좋습니다
JoeCodeFrog

답변:


69

최근에 같은 문제가 발생했습니다. 그리고 다음 코드를 사용하여 해결되었습니다.

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);
mark smith

11
이것은 당신의 코드가 시간대를 안전하지 않게 만들기 때문에 올바르지 않습니다. 날짜를 다시 읽을 때 시간대를 수정해야합니다.
olliej

4
이 대답은 틀 렸습니다. OP는 "2009-09-28T08 : 00 : 00Z"와 "Mon Sep 28 10:00:00 UTC + 0200 2009"가 정확히 같은 순간 이고 시간대 오프셋 조정이 실제로 생성 된다는 것을 인식하지 못합니다. 잘못된 시간.
RobG

41

JSON은 Date.prototype.toISOString현지 시간을 나타내지 않는 함수를 사용합니다 . 수정되지 않은 UTC의 시간을 나타냅니다. 날짜 출력을 보면 UTC + 2 시간이라는 것을 알 수 있습니다. 이것이 JSON 문자열이 2 시간 씩 변경되는 이유입니다. 그러나 이것이 여러 시간대에서 동일한 시간이 올바르게 표시되도록 허용하는 경우.


2
이것을 생각한 적이 없지만 당신이 옳습니다. 이것이 해결책입니다. 프로토 타이핑을 사용하여 선호하는 형식을 지정할 수 있습니다.
racs


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가 언급되어 있습니다.
aug jan

6

date.toJSON ()은 UTC-Date를 형식화 된 문자열로 인쇄합니다 (따라서 JSON 형식으로 변환 할 때 오프셋을 추가합니다).

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

6
일반적으로 코드가 수행하는 작업에 대한 설명을 추가하는 것이 좋습니다. 이를 통해 새로운 개발자는 코드 작동 방식을 이해할 수 있습니다.
Caleb Kleveter

답변의 코드가 작동해야하는 이유를 설명 할 수 있습니까?
Cristik

이것은 나에게도 효과가 있지만 어떻게 그랬는지 설명해 주시겠습니까?
Deven Patil

이 코드의 두 번째 줄에 대해 설명하겠습니다. date.getTime()시간을 밀리 초 단위로 반환하므로 두 번째 피연산자도 밀리 초로 변환해야합니다. 이후 date.getTimezoneOffset()반환 분의 오프셋 (offset), 우리는 1 분 60000milliseconds을 = 곱셈이 60000, 때문이다. 따라서 현재 시간에서 오프셋을 빼서 UTC로 시간을 얻습니다.
Maksim Pavlov

4

moment.js 를 사용하여 현지 시간으로 형식을 지정할 수 있습니다 .

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

공통 클래스 날짜를 덮어 쓰지 마십시오. 일부 외부 모듈을 사용하면 애플리케이션이 쉽게 중단 될 수 있습니다.
Viacheslav Dobromyslov

3

나는 조금 늦었지만 Prototype을 사용하는 Date의 경우 항상 toJson 함수를 덮어 쓸 수 있습니다.

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

제 경우에는 Util.getDateTimeString (this)이 다음과 같은 문자열을 반환합니다. "2017-01-19T00 : 00 : 00Z"


2
브라우저 전역을 덮어 쓰면 포함하는 타사 라이브러리가 손상 될 수 있으며 이는 큰 안티 패턴입니다. 프로덕션에서는이 작업을 수행하지 마십시오.
jakub.g

3

JSON.stringify시간대 를 강제로 무시하는 즉시 사용 가능한 솔루션 :

  • 순수 자바 스크립트 (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>


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

나는 그들이 미국 동부 해안에서만 일하고 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))을 뺄 것입니다.


1

다음은 정말 깔끔하고 간단합니다 (나는 그렇게 생각합니다 :)) 복제 할 날짜 조작이 필요하지 않으며 toJSON과 같은 브라우저의 기본 기능을 오버로드 할 필요가 없습니다 (참조 : JSON을 JSON 문자열로 지정하고 시간대를 유지하는 방법 문자열 , 법정 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.
*/

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");

당신은 당신의 시간대에 정확하게 당신의 날짜를 얻을 것입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.