Date.parse가 왜 잘못된 결과를 줍니까?
사례 하나 :
new Date(Date.parse("Jul 8, 2005"));
산출:
2005 년 7 월 08 일 00:00:00 GMT-0700 (PST)
사례 2 :
new Date(Date.parse("2005-07-08"));
산출:
2005 년 7 월 7 일 목요일 17:00:00 GMT-0700 (PST)
두 번째 구문 분석이 왜 올바르지 않습니까?
5 판 사양이 나왔다까지, Date.parse
방법은 완전히이었다 의존 구현 ( new Date(string)
와 같습니다 Date.parse(string)
(A)보다 숫자가 아니라 후자의 반환을 제외시켰다 Date
). 제 5 판 사양에서는 단순화 된 (약간 틀린) ISO-8601 을 지원하기 위해 요구 사항이 추가되었습니다 ( JavaScript에서 유효한 날짜 시간 문자열이란 무엇입니까? 참조 ). 하지만 그 이외 없었다 어떤 무엇에 대한 요구 사항 Date.parse
/ new Date(string)
그들이 어떤 동의했다 그 이외의 동의한다 날짜 #의를 toString (했다 그 어떤 말도없이) 출력을.
ECMAScript 2017 (버전 8)부터 구현은 Date # toString 및 Date # toUTCString에 대한 출력을 구문 분석해야 하지만 해당 문자열의 형식은 지정되지 않았습니다.
ECMAScript 2019 (9 버전)부터 Date # toString 및 Date # toUTCString 형식은 (각각) 다음과 같이 지정되었습니다.
- ddd MMM DD YYYY HH : mm : ss ZZ [(시간대 이름)]
예 : 2018 년 7 월 10 일 화요일 18:39:58 GMT + 0530 (IST) - ddd, DD MMM YYYY HH : mm : ss Z
예 : 화 10 Jul 2018 13:09:58 GMT
Date.parse 가 새로운 구현에서 안정적으로 구문 분석해야하는 2 가지 형식을 추가로 제공 합니다 (지원이 어디에서나 사용되지 않으며 비준수 구현은 얼마 동안 계속 사용됨).
모호성을 피하기 위해 날짜 문자열을 수동으로 구문 분석하고 Date 생성자 를 연도, 월 및 일 인수와 함께 사용하는 것이 좋습니다 .
// parse a date in yyyy-mm-dd format
function parseDate(input) {
var parts = input.split('-');
// new Date(year, month [, day [, hours[, minutes[, seconds[, ms]]]]])
return new Date(parts[0], parts[1]-1, parts[2]); // Note: months are 0-based
}
최근 JS 통역사를 쓴 경험을 통해 ECMA / JS 날짜의 내부 작업에 많은 어려움을 겪었습니다. 그래서 여기에 2 센트를 넣을 것이라고 생각합니다. 이 자료를 공유하면 브라우저가 날짜를 처리하는 방식의 차이점에 대한 질문에 다른 사람들이 도움이 될 수 있기를 바랍니다.
입력측
모든 구현은 1/1/1970 UTC 이후의 밀리 초 수를 나타내는 64 비트 숫자로 내부적으로 날짜 값을 저장합니다 (GMT는 UTC와 동일 함). 이후 1/1/1970 00:00:00
에 발생한 날짜 는 양수이고 이전 날짜는 음수입니다.
따라서 다음 코드는 모든 브라우저에서 동일한 결과를 생성합니다.
Date.parse('1/1/1970');
내 시간대 (EST)에서 결과는 18000000입니다. 왜냐하면 5 시간 안에 몇 ms가 있습니까 (일광 절약 개월 동안 4 시간에 불과합니다). 시간대에 따라 값이 달라집니다. 모든 주요 브라우저는 동일한 방식으로 작동합니다.
여기 문지름이 있습니다. 입력 문자열 형식에는 주요 브라우저가 날짜로 구문 분석하는 데 약간의 차이가 있지만, 시간대 및 일광 절약과 관련하여 동일하게 해석합니다. 하나는 ISO 8601 형식입니다. ECMA-262 v.5 사양에 구체적으로 설명 된 유일한 형식입니다. 다른 모든 문자열 형식의 경우 해석은 구현에 따라 다릅니다. 아이러니하게도, 이것은 브라우저가 다를 수있는 형식입니다. 다음은 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 시간이며 저장하기 전에 오프셋이 필요하지 않음을 나타냅니다.
- "-0500"지정자는 입력이 GMT-05 : 00에 있음을 나타내므로 두 브라우저 모두 입력을 현지 시간대로 해석합니다. 이는 값이 저장되기 전에 UTC로 변환됨을 의미합니다. 제 경우에는 날짜의 내부 값에 18000000ms를 추가하여 현지 시간으로 되돌리려면 -18000000ms (-05 : 00) 이동이 필요합니다.
- 그러나 지정자가 없으면 FF는 입력을 현지 시간으로 처리하지만 Chrome은 입력을 UTC 시간으로 처리합니다. 나에게 이것은 저장된 값에서 5 시간의 차이를 생성하는데 문제가 있습니다. 구현
toString
에서 대체 시간대를 지정하지 않으면 출력 값을 입력 값과 일치시키기를 원 하기 때문에 FF로 사이딩했습니다 . 없는 지시자의 로컬 시간 입력을 추정한다.
그러나 FF는 ISO 8601 형식의 짧은 형식 ( "YYYY-MM-DD")을 긴 형식 ( "YYYY-MM-DDTHH : mm : ss : sssZ")과 다르게 처리합니다. 논리적 인 이유가 없습니다. 다음은 시간대 지정자가없는 길고 짧은 ISO 날짜 형식의 FF 출력입니다.
Date.parse('1970-01-01T00:00:00'); // 18000000
Date.parse('1970-01-01'); // 0
따라서 원래 질문의 질문에 직접 대답하는 "YYYY-MM-DD"
것은 ISO 8601 형식의 짧은 형식 "YYYY-MM-DDTHH:mm:ss:sssZ"
입니다. 따라서 UTC 시간으로 해석되고 다른 하나는 로컬 시간으로 해석됩니다. 그렇기 때문에
이것은 움직이지 않습니다 :
console.log(new Date(Date.parse("Jul 8, 2005")).toString());
console.log(new Date(Date.parse("2005-07-08")).toString());
이것은 :
console.log(new Date(Date.parse("Jul 8, 2005")).toString());
console.log(new Date(Date.parse("2005-07-08T00:00:00")).toString());
결론은 날짜 문자열을 구문 분석하는 것입니다. 브라우저에서 안전하게 구문 분석 할 수있는 유일한 ISO 8601 문자열은 긴 형식입니다. 그리고 항상 "Z"지정자를 사용하십시오. 그렇게하면 현지 시간과 UTC 시간 사이를 안전하게 이동할 수 있습니다.
이것은 IE9 이후의 브라우저에서 작동합니다.
console.log(new Date(Date.parse("2005-07-08T00:00:00Z")).toString());
다행히도 대부분의 최신 브라우저는 가장 자주 사용되는 '1/1/1970'및 '1/1/1970 00:00:00 AM'형식을 포함하여 다른 입력 형식을 동일하게 취급합니다. 다음 형식 (및 기타 형식)은 모든 브라우저에서 현지 시간 입력으로 취급되며 저장 전에 UTC로 변환됩니다. 따라서 브라우저 간 호환이 가능합니다. 이 코드의 출력은 내 시간대의 모든 브라우저에서 동일합니다.
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"));
출력측
출력 측에서 모든 브라우저는 시간대를 동일한 방식으로 변환하지만 문자열 형식을 다르게 처리합니다. 다음은 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"
이 답변이 도움이 되었기를 바랍니다.
광기에 대한 몇 가지 방법이 있습니다. 일반적으로 브라우저가 날짜를 ISO-8601로 해석 할 수있는 경우 날짜가 변경됩니다. "2005-07-08"이이 캠프에 속하므로 UTC로 구문 분석됩니다. "2005 년 7 월 8 일"은 현지 시간으로 구문 분석 할 수 없습니다.
페이지의 자바 스크립트와 날짜, 무엇 엉망! 이상.
다른 해결책은 날짜 형식으로 연관 배열을 작성한 다음 데이터를 다시 형식화하는 것입니다.
이 방법은 날짜가 비정상적인 방식으로 유용합니다.
예를 들면 :
mydate='01.02.12 10:20:43':
myformat='dd/mm/yy HH:MM:ss';
dtsplit=mydate.split(/[\/ .:]/);
dfsplit=myformat.split(/[\/ .:]/);
// creates assoc array for date
df = new Array();
for(dc=0;dc<6;dc++) {
df[dfsplit[dc]]=dtsplit[dc];
}
// uses assc array for standard mysql format
dstring[r] = '20'+df['yy']+'-'+df['mm']+'-'+df['dd'];
dstring[r] += ' '+df['HH']+':'+df['MM']+':'+df['ss'];
http://blog.dygraphs.com/2012/03/javascript-and-dates-what-mess.html 에 따르면 "yyyy / mm / dd"형식은 일반적인 문제를 해결합니다. "언제나 가능하면 날짜 문자열을"YYYY / MM / DD "로 고정하십시오. 보편적으로 지원되며 모호하지 않습니다.이 형식으로 모든 시간은 현지 시간입니다." 나는 일련의 테스트를했습니다 : http://jsfiddle.net/jlanus/ND2Qg/432/ 이 형식 : +는 YMD 주문 및 4 자리 연도 +를 사용하여 월과 일 주문 모호성을 피할 UTC 대 지역 문제를하지 방지 dygraphs guy 인 슬래시 + danvk를 사용하여 ISO 형식을 준수 하면이 형식이 모든 브라우저에서 적합하다고 말합니다.
moment.js 를 사용 하여 날짜를 구문 분석 하십시오 .
var caseOne = moment("Jul 8, 2005", "MMM D, YYYY", true).toDate();
var caseTwo = moment("2005-07-08", "YYYY-MM-DD", true).toDate();
세 번째 인수는 엄격한 구문 분석을 결정합니다 (2.3.0부터 사용 가능). 그것없이 moment.js는 또한 잘못된 결과를 줄 수 있습니다.
하지만 CMS가 올바른지 구문 분석 방법으로 문자열을 전달하는 것은 일반적으로 안전하지 않은 것으로, 새로운 ECMA-262 5 판 섹션 15.9.4.2에서 (ES5 일명) 사양은 알 수 Date.parse()
실제로 ISO 형식의 날짜를 처리해야합니다. 구 사양은 그런 주장을하지 않았다. 물론 이전 브라우저와 일부 최신 브라우저는 여전히이 ES5 기능을 제공하지 않습니다.
두 번째 예는 틀리지 않습니다. 에 의해 암시 된대로 UTC로 지정된 날짜 Date.prototype.toISOString()
이지만 현지 시간대로 표시됩니다.
이 간단한 날짜 구문 분석 라이브러리 는 모든 유사한 문제를 해결해야합니다. 확장하기가 쉽기 때문에 라이브러리가 마음에 듭니다. i18n으로 할 수도 있습니다 (매우 간단하지는 않지만 그렇게 어렵지는 않습니다).
구문 분석 예 :
var caseOne = Date.parseDate("Jul 8, 2005", "M d, Y");
var caseTwo = Date.parseDate("2005-07-08", "Y-m-d");
그리고 문자열로 다시 서식을 지정하면 두 경우 모두 정확히 동일한 결과를 얻을 수 있습니다.
console.log( caseOne.dateFormat("M d, Y") );
console.log( caseTwo.dateFormat("M d, Y") );
console.log( caseOne.dateFormat("Y-m-d") );
console.log( caseTwo.dateFormat("Y-m-d") );
다음은 @ drankin2112에서 자세히 설명한 것처럼 브라우저 간 안전한 방식으로 날짜 시간 문자열을 변환하는 짧고 유연한 스 니펫입니다.
var inputTimestamp = "2014-04-29 13:00:15"; //example
var partsTimestamp = inputTimestamp.split(/[ \/:-]/g);
if(partsTimestamp.length < 6) {
partsTimestamp = partsTimestamp.concat(['00', '00', '00'].slice(0, 6 - partsTimestamp.length));
}
//if your string-format is something like '7/02/2014'...
//use: var tstring = partsTimestamp.slice(0, 3).reverse().join('-');
var tstring = partsTimestamp.slice(0, 3).join('-');
tstring += 'T' + partsTimestamp.slice(3).join(':') + 'Z'; //configure as needed
var timestamp = Date.parse(tstring);
브라우저는 다음과 같은 타임 스탬프 결과를 제공해야합니다 Date.parse
.
(new Date(tstring)).getTime()
둘 다 정확하지만 두 시간대가 다른 날짜로 해석되고 있습니다. 따라서 사과와 오렌지를 비교했습니다.
// local dates
new Date("Jul 8, 2005").toISOString() // "2005-07-08T07:00:00.000Z"
new Date("2005-07-08T00:00-07:00").toISOString() // "2005-07-08T07:00:00.000Z"
// UTC dates
new Date("Jul 8, 2005 UTC").toISOString() // "2005-07-08T00:00:00.000Z"
new Date("2005-07-08").toISOString() // "2005-07-08T00:00:00.000Z"
Date.parse()
문자열 인수에서 자동으로 사용되므로 호출을 제거했습니다 . 또한 ISO8601 형식을 사용하여 날짜를 비교하여 현지 날짜와 UTC 날짜 사이의 날짜를 시각적으로 비교할 수 있습니다. 시간은 7 시간 간격이며, 이는 시간대 차이이며 테스트에서 두 가지 다른 날짜가 표시된 이유입니다.
동일한 현지 / UTC 날짜를 만드는 다른 방법은 다음과 같습니다.
new Date(2005, 7-1, 8) // "2005-07-08T07:00:00.000Z"
new Date(Date.UTC(2005, 7-1, 8)) // "2005-07-08T00:00:00.000Z"
그러나 나는 여전히 간단하지만 강력한 Moment.js 를 강력히 추천합니다 .
// parse string
moment("2005-07-08").format() // "2005-07-08T00:00:00+02:00"
moment.utc("2005-07-08").format() // "2005-07-08T00:00:00Z"
// year, month, day, etc.
moment([2005, 7-1, 8]).format() // "2005-07-08T00:00:00+02:00"
moment.utc([2005, 7-1, 8]).format() // "2005-07-08T00:00:00Z"
CMS에서 허용 대답이 올바른지, 난 그냥 몇 가지 기능을 추가했습니다 :
- 입력 공간 정리 및 청소
- 슬래시, 대시, 콜론 및 공백 구문 분석
- 기본 날짜와 시간이 있습니다
// parse a date time that can contains spaces, dashes, slashes, colons
function parseDate(input) {
// trimes and remove multiple spaces and split by expected characters
var parts = input.trim().replace(/ +(?= )/g,'').split(/[\s-\/:]/)
// new Date(year, month [, day [, hours[, minutes[, seconds[, ms]]]]])
return new Date(parts[0], parts[1]-1, parts[2] || 1, parts[3] || 0, parts[4] || 0, parts[5] || 0); // Note: months are 0-based
}
참고 URL : https://stackoverflow.com/questions/2587345/why-does-date-parse-give-incorrect-results
'Programing' 카테고리의 다른 글
왜 jquery의 .ajax () 메소드가 세션 쿠키를 보내지 않습니까? (0) | 2020.03.07 |
---|---|
파이썬에서 문자열 끝에서 부분 문자열을 어떻게 제거합니까? (0) | 2020.03.07 |
파이썬 : '사전'이 비어 있는지 확인하면 작동하지 않는 것 같습니다. (0) | 2020.03.06 |
Less in Unix를 사용하여 특정 줄 번호로 이동 (0) | 2020.03.06 |
파이썬에서 집합에 값 추가 (0) | 2020.03.06 |