Programing

Date.parse가 왜 잘못된 결과를 줍니까?

lottogame 2020. 3. 6. 08:19
반응형

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 # toStringDate # toUTCString에 대한 출력을 구문 분석해야 하지만 해당 문자열의 형식은 지정되지 않았습니다.

ECMAScript 2019 (9 버전)부터 Date # toStringDate # toUTCString 형식은 (각각) 다음과 같이 지정되었습니다.

  1. ddd MMM DD YYYY HH : mm : ss ZZ [(시간대 이름)]
    예 : 2018 년 7 월 10 일 화요일 18:39:58 GMT + 0530 (IST)
  2. 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기능과 출력 내용입니다. 통지 toUTCStringtoISOString내 컴퓨터에 기능 출력 오전 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



반응형