최근 JS 통역사를 쓴 경험을 통해 ECMA / JS 날짜의 내부 작업에 많은 어려움을 겪었습니다. 그래서 여기에 2 센트를 넣을 것이라고 생각합니다. 이 자료를 공유하면 브라우저가 날짜를 처리하는 방식의 차이점에 대한 질문에 다른 사람들이 도움이되기를 바랍니다.
입력측
모든 구현은 1970-01-01 UTC (GMT는 UTC와 동일 함) 이후 밀리 초 (ms) 수를 나타내는 64 비트 숫자로 내부적으로 날짜 값을 저장합니다. 이 날짜는 ECMAScript 시대이며 Java와 같은 다른 언어와 UNIX와 같은 POSIX 시스템에서도 사용됩니다. 신기원 이후에 발생한 날짜는 양수이고 이전 날짜는 음수입니다.
다음 코드는 모든 현재 브라우저에서 동일한 날짜로 해석되지만 현지 시간대 오프셋이 사용됩니다.
Date.parse('1/1/1970'); // 1 January, 1970
내 시간대 (EST, -05 : 00)에서 결과는 18000000입니다. 왜냐하면 5 시간 안에 몇 ms가 있기 때문입니다 (일광 절약 시간 동안 4 시간에 불과합니다). 시간대에 따라 값이 달라집니다. 이 동작은 ECMA-262에 지정되어 있으므로 모든 브라우저가 동일한 방식으로 작동합니다.
주요 브라우저가 날짜로 구문 분석하는 입력 문자열 형식에는 약간의 차이가 있지만, 구문 분석이 구현에 크게 의존하더라도 시간대와 일광 절약에 관한 한 기본적으로 동일하게 해석합니다.
그러나 ISO 8601 형식이 다릅니다. ECMAScript 2015 (ed 6)에 요약 된 두 가지 형식 중 하나이며 특히 모든 구현에서 동일한 방식으로 구문 분석해야합니다 (다른 형식은 Date.prototype.toString에 지정된 형식 임 ).
그러나 ISO 8601 형식 문자열의 경우에도 일부 구현에서는 잘못 구현됩니다. 다음은이 답변이 모든 구현에서 정확히 동일한 값으로 구문 분석 해야하는 ISO 8601 형식 문자열을 사용하여 내 컴퓨터에서 1/1/1970 (에포크)로 작성된 경우 Chrome과 Firefox의 비교 출력입니다 .
Date.parse('1970-01-01T00:00:00Z'); // Chrome: 0 FF: 0
Date.parse('1970-01-01T00:00:00-0500'); // Chrome: 18000000 FF: 18000000
Date.parse('1970-01-01T00:00:00'); // Chrome: 0 FF: 18000000
- 첫 번째 경우 "Z"지정자는 입력이 UTC 시간이므로 에포크에서 오프셋되지 않고 결과가 0임을 나타냅니다.
- 두 번째 경우 "-0500"지정자는 입력이 GMT-05 : 00에 있고 두 브라우저 모두 입력이 -05 : 00 시간대에있는 것으로 해석합니다. 즉, UTC 값은 에포크에서 오프셋되어 날짜의 내부 시간 값에 18000000ms를 추가하는 것을 의미합니다.
- 지정자가없는 세 번째 경우 는 호스트 시스템의 로컬로 처리 해야 합니다. FF는 입력을 현지 시간으로 올바르게 처리하는 반면 Chrome은 입력을 UTC로 처리하므로 다른 시간 값을 생성합니다. 나에게 이것은 저장된 값에서 5 시간의 차이를 생성하는데 문제가 있습니다. 오프셋이 다른 다른 시스템은 다른 결과를 얻습니다.
이 차이는 2020 년부터 수정되었지만 ISO 8601 형식 문자열을 구문 분석 할 때 브라우저간에 다른 문제가 있습니다.
그러나 악화됩니다. ECMA-262의 단점은 ISO 8601 날짜 전용 형식 (YYYY-MM-DD)을 UTC로 구문 분석해야하는 반면 ISO 8601은 로컬 형식으로 구문 분석해야한다는 점입니다. 시간대 지정자가없는 길고 짧은 ISO 날짜 형식의 FF 출력 결과는 다음과 같습니다.
Date.parse('1970-01-01T00:00:00'); // 18000000
Date.parse('1970-01-01'); // 0
따라서 첫 번째는 표준 시간대가없는 ISO 8601 날짜 및 시간이므로 로컬로 구문 분석되고 두 번째는 ISO 8601 날짜 만이므로 UTC로 구문 분석됩니다.
따라서 원래 질문에 직접 대답하려면 "YYYY-MM-DD"
ECMA-262에서 UTC로 해석해야하고 다른 질문은 로컬로 해석해야합니다. 그 이유는 다음과 같습니다.
이것은 동등한 결과를 생성하지 않습니다.
console.log(new Date(Date.parse("Jul 8, 2005")).toString()); // Local
console.log(new Date(Date.parse("2005-07-08")).toString()); // UTC
이것은 :
console.log(new Date(Date.parse("Jul 8, 2005")).toString());
console.log(new Date(Date.parse("2005-07-08T00:00:00")).toString());
결론은 날짜 문자열을 구문 분석하는 것입니다. 브라우저에서 안전하게 구문 분석 할 수있는 유일한 ISO 8601 문자열 은 오프셋 이있는 긴 형식 (± HH : mm 또는 "Z")입니다. 그렇게하면 현지 시간과 UTC 시간 사이를 안전하게 이동할 수 있습니다.
이것은 IE9 이후의 브라우저에서 작동합니다.
console.log(new Date(Date.parse("2005-07-08T00:00:00Z")).toString());
대부분의 최신 브라우저는 자주 사용되는 '1/1/1970'(M / D / YYYY) 및 '1/1/1970 00:00:00 AM'(M / D / YYYY hh)을 포함하여 다른 입력 형식을 동일하게 취급합니다. : mm : ss ap) 형식입니다. 다음 형식 (마지막 제외)은 모두 모든 브라우저에서 현지 시간 입력으로 처리됩니다. 이 코드의 출력은 내 시간대의 모든 브라우저에서 동일합니다. 오프셋은 타임 스탬프에 설정되어 있기 때문에 마지막 시간대는 호스트 시간대와 상관없이 -05 : 00으로 처리됩니다.
console.log(Date.parse("1/1/1970"));
console.log(Date.parse("1/1/1970 12:00:00 AM"));
console.log(Date.parse("Thu Jan 01 1970"));
console.log(Date.parse("Thu Jan 01 1970 00:00:00"));
console.log(Date.parse("Thu Jan 01 1970 00:00:00 GMT-0500"));
그러나 ECMA-262에 지정된 형식의 구문 분석도 일관되지 않으므로 내장 구문 분석기에 의존하지 말고 라이브러리를 사용하여 구문 분석기에 형식을 제공하는 등 항상 문자열을 수동으로 구문 분석하는 것이 좋습니다.
예를 들어 moment.js에서는 다음과 같이 작성할 수 있습니다.
let m = moment('1/1/1970', 'M/D/YYYY');
출력측
출력 측에서 모든 브라우저는 시간대를 동일한 방식으로 변환하지만 문자열 형식을 다르게 처리합니다. 다음은 toString
기능과 출력 내용입니다. 통지 toUTCString
및 toISOString
내 컴퓨터에 기능 출력 오전 5:00. 또한 시간대 이름은 약어 일 수 있으며 구현에 따라 다를 수 있습니다.
인쇄하기 전에 UTC에서 현지 시간으로 변환
- toString
- toDateString
- toTimeString
- toLocaleString
- toLocaleDateString
- toLocaleTimeString
저장된 UTC 시간을 직접 인쇄합니다
- toUTCString
- toISOString
Chrome에서
toString Thu Jan 01 1970 00:00:00 GMT-05:00 (Eastern Standard Time)
toDateString Thu Jan 01 1970
toTimeString 00:00:00 GMT-05:00 (Eastern Standard Time)
toLocaleString 1/1/1970 12:00:00 AM
toLocaleDateString 1/1/1970
toLocaleTimeString 00:00:00 AM
toUTCString Thu, 01 Jan 1970 05:00:00 GMT
toISOString 1970-01-01T05:00:00.000Z
Firefox에서
toString Thu Jan 01 1970 00:00:00 GMT-05:00 (Eastern Standard Time)
toDateString Thu Jan 01 1970
toTimeString 00:00:00 GMT-0500 (Eastern Standard Time)
toLocaleString Thursday, January 01, 1970 12:00:00 AM
toLocaleDateString Thursday, January 01, 1970
toLocaleTimeString 12:00:00 AM
toUTCString Thu, 01 Jan 1970 05:00:00 GMT
toISOString 1970-01-01T05:00:00.000Z
나는 일반적으로 문자열 입력에 ISO 형식을 사용하지 않습니다. 해당 형식을 사용하는 것이 유익한 유일한 날짜는 날짜를 문자열로 정렬해야 할 때입니다. ISO 형식은있는 그대로 정렬 할 수 있지만 다른 형식은 정렬 할 수 없습니다. 브라우저 간 호환성이 필요한 경우 시간대를 지정하거나 호환 가능한 문자열 형식을 사용하십시오.
코드 new Date('12/4/2013').toString()
는 다음과 같은 내부 의사 변환을 거칩니다.
"12/4/2013" -> toUCT -> [storage] -> toLocal -> print "12/4/2013"
이 답변이 도움이 되었기를 바랍니다.