[javascript] 특정 시간대로 JavaScript 날짜를 초기화하는 방법

특정 시간대의 날짜 시간을 문자열로 가지고 있으며 이것을 현지 시간으로 변환하고 싶습니다. 그러나 Date 객체에서 시간대를 설정하는 방법을 모르겠습니다.

예를 들어, Feb 28 2013 7:00 PM ET,나는 할 수있다

var mydate = new Date();
mydate.setFullYear(2013);
mydate.setMonth(02);
mydate.setDate(28);
mydate.setHours(7);
mydate.setMinutes(00);  

내가 아는 한 UTC 시간이나 현지 시간을 설정할 수 있습니다. 그러나 다른 시간대에서 시간을 어떻게 설정합니까?

UTC에서 오프셋을 더하기 / 빼기를 ​​사용하려고했지만 일광 절약에 대처하는 방법을 모르겠습니다. 내가 올바른 방향으로 가고 있는지 확실하지 않습니다.

Javascript에서 다른 시간대에서 현지 시간으로 시간을 변환하는 방법은 무엇입니까?



답변

배경

JavaScript의 Date객체는 내부적으로 UTC로 시간을 추적하지만 일반적으로 입력을 받아들이고 실행중인 컴퓨터의 현지 시간으로 출력을 생성합니다. 다른 시간대의 시간 작업을위한 시설은 거의 없습니다.

Date객체 의 내부 표현은 단일 숫자이며 1970-01-01 00:00:00 UTC윤초와 상관없이 이후 경과 한 밀리 초 수를 나타냅니다 . Date 객체 자체에는 표준 시간대 나 문자열 형식이 저장되어 있지 않습니다. Date객체 의 다양한 기능을 사용하면 컴퓨터의 현지 시간대가 내부 표현에 적용됩니다. 함수가 문자열을 생성하면 컴퓨터의 로캘 정보를 고려하여 해당 문자열을 생성하는 방법을 결정할 수 있습니다. 세부 사항은 기능마다 다르며 일부는 구현에 따라 다릅니다.

Date로컬이 아닌 시간대로 개체가 수행 할 수 있는 유일한 작업 은 다음과 같습니다.

  • 모든 시간대에서 숫자 UTC 오프셋이 포함 된 문자열을 구문 분석 할 수 있습니다. 이를 사용하여 구문 분석되는 값을 조정하고 UTC에 해당하는 값을 저장합니다. 원래 로컬 시간과 오프셋은 결과 Date개체에 유지되지 않습니다 . 예를 들면 다음과 같습니다.

    var d = new Date("2020-04-13T00:00:00.000+08:00");
    d.toISOString()  //=> "2020-04-12T16:00:00.000Z"
    d.valueOf()      //=> 1586707200000  (this is what is actually stored in the object)
  • ECMASCript Internationalization API (일명 “Intl”)를 구현 한 환경 에서 Date객체는 지정된 시간대 식별자로 조정 된 로캘 별 문자열을 생성 할 수 있습니다. 이는 timeZone옵션 toLocaleString및 변형 을 통해 수행됩니다 . 대부분의 구현은와 같은 IANA 시간대 식별자를 지원 'America/New_York'합니다. 예를 들면 다음과 같습니다.

    var d = new Date("2020-04-13T00:00:00.000+08:00");
    d.toLocaleString('en-US', { timeZone: 'America/New_York' })
    //=> "4/12/2020, 12:00:00 PM"
    // (midnight in China on Apring 13th is noon in New York on April 12th)

    대부분의 최신 환경은 전체 IANA 표준 시간대 식별자를 지원합니다 ( 호환성 표 참조 ). 그러나 Intl에서 지원하는 데 필요한 유일한 식별자 는 'UTC'이므로 이전 브라우저 나 비정형 환경 (예 : 경량 IoT 장치)을 지원해야하는지주의 깊게 확인해야합니다.

도서관

시간대 작업에 사용할 수있는 몇 가지 라이브러리가 있습니다. 여전히 Date객체를 다르게 작동 시킬 수는 없지만 일반적으로 표준 IANA 표준 시간대 데이터베이스를 구현하고 JavaScript에서 사용할 수있는 기능을 제공합니다. 최신 라이브러리는 Intl API에서 제공 한 시간대 데이터를 사용하지만 데이터베이스가 약간 커질 수 있기 때문에 특히 웹 브라우저에서 실행중인 경우 오래된 라이브러리에는 일반적으로 오버 헤드가 있습니다. 이러한 라이브러리 중 일부를 사용하면 표준 시간대가 지원되는 작업 및 / 또는 작업 할 수있는 날짜 범위에 따라 데이터 세트를 선택적으로 줄일 수 있습니다.

고려해야 할 라이브러리는 다음과 같습니다.

국제 도서관

새로운 개발은 시간대 데이터에 Intl API를 사용하는 다음 구현 중 하나를 선택해야합니다.

비 국제 도서관

이러한 라이브러리는 유지 관리되지만 자체 시간대 데이터를 패키징해야하는 부담이 있으며 이는 상당히 클 수 있습니다.

* Moment 및 Moment-Timezone이 이전에 권장되었지만 Moment 팀은 이제 사용자가 새로운 개발에 Luxon을 선택하는 것을 선호합니다.

단종 된 라이브러리

이 라이브러리는 공식적으로 중단되었으며 더 이상 사용해서는 안됩니다.

향후 제안

TC39 임시 제안의 목적은 자바 스크립트 언어 자체의 날짜 및 시간을 사용한 작업 표준 객체의 새로운 세트를 제공합니다. 여기에는 표준 시간대 인식 개체에 대한 지원이 포함됩니다.


답변

매트 존슨이 말했듯이

최신 웹 브라우저로 사용을 제한 할 수 있다면 특별한 라이브러리없이 다음을 수행 할 수 있습니다.

new Date().toLocaleString("en-US", {timeZone: "America/New_York"})

이것은 포괄적 인 솔루션은 아니지만 UTC 또는 현지 시간에서 특정 시간대로의 출력 변환 만 필요한 다른 시나리오에서는 작동하지 않는 많은 시나리오에서 작동합니다.

따라서 브라우저가 날짜를 만들 때 IANA 시간대를 읽을 수 없거나 기존 Date 객체의 시간대를 변경하는 방법이 있지만 주변에 해킹이있는 것 같습니다.

function changeTimezone(date, ianatz) {

  // suppose the date is 12:00 UTC
  var invdate = new Date(date.toLocaleString('en-US', {
    timeZone: ianatz
  }));

  // then invdate will be 07:00 in Toronto
  // and the diff is 5 hours
  var diff = date.getTime() - invdate.getTime();

  // so 12:00 in Toronto is 17:00 UTC
  return new Date(date.getTime() + diff);

}

// E.g.
var there = new Date();
var here = changeTimezone(there, "America/Toronto");

console.log(`Here: ${here.toString()}\nToronto: ${there.toString()}`);


답변

에 시간대 오프셋을 지정할 수 있습니다 new Date(). 예를 들면 다음과 같습니다.

new Date('Feb 28 2013 19:00:00 EST')

또는

new Date('Feb 28 2013 19:00:00 GMT-0500')

DateUTC 시간을 저장 하기 때문에 (즉 getTime, UTC로 반환) javascript는 시간을 UTC로 변환하고, javascript와 같은 것을 호출 toString하면 UTC 시간을 브라우저의 현지 시간대로 변환하고 현지 시간대로 문자열을 반환합니다. UTC+8:

> new Date('Feb 28 2013 19:00:00 GMT-0500').toString()
< "Fri Mar 01 2013 08:00:00 GMT+0800 (CST)"

또한 일반적인 getHours/Minute/Second방법을 사용할 수 있습니다 .

> new Date('Feb 28 2013 19:00:00 GMT-0500').getHours()
< 8

(이것은 8시간이 현지 시간으로 변환 된 후 UTC+8시간 숫자가임을 의미 8합니다.)


답변

이렇게하면 문제가 해결 될 것입니다. 수정 프로그램을 제공하십시오. 이 방법은 주어진 날짜의 일광 절약 시간도 고려합니다.

dateWithTimeZone = (timeZone, year, month, day, hour, minute, second) => {
  let date = new Date(Date.UTC(year, month, day, hour, minute, second));

  let utcDate = new Date(date.toLocaleString('en-US', { timeZone: "UTC" }));
  let tzDate = new Date(date.toLocaleString('en-US', { timeZone: timeZone }));
  let offset = utcDate.getTime() - tzDate.getTime();

  date.setTime( date.getTime() + offset );

  return date;
};

시간대 및 현지 시간과 함께 사용하는 방법 :

dateWithTimeZone("America/Los_Angeles",2019,8,8,0,0,0)


답변

타사 라이브러리에 대해 걱정하지 않고이 작업을 수행하는 가장 지원되는 방법 getTimezoneOffset은 적절한 타임 스탬프를 계산하거나 시간을 업데이트 한 다음 일반적인 방법을 사용하여 필요한 날짜와 시간을 얻는 것입니다.

var mydate = new Date();
mydate.setFullYear(2013);
mydate.setMonth(02);
mydate.setDate(28);
mydate.setHours(7);
mydate.setMinutes(00);

// ET timezone offset in hours.
var timezone = -5;
// Timezone offset in minutes + the desired offset in minutes, converted to ms.
// This offset should be the same for ALL date calculations, so you should only need to calculate it once.
var offset = (mydate.getTimezoneOffset() + (timezone * 60)) * 60 * 1000;

// Use the timestamp and offset as necessary to calculate min/sec etc, i.e. for countdowns.
var timestamp = mydate.getTime() + offset,
    seconds = Math.floor(timestamp / 1000) % 60,
    minutes = Math.floor(timestamp / 1000 / 60) % 60,
    hours   = Math.floor(timestamp / 1000 / 60 / 60);

// Or update the timestamp to reflect the timezone offset.
mydate.setTime(mydate.getTime() + offset);
// Then Output dates and times using the normal methods.
var date = mydate.getDate(),
    hour = mydate.getHours();

편집하다

UTC날짜 변환을 수행 할 때 이전에 메소드를 사용 하고 있었는데 잘못되었습니다. 시간에 오프셋을 추가하면 로컬 get함수를 사용 하여 원하는 결과를 반환합니다.


답변

단위 테스트와 비슷한 문제가 발생했습니다 (특히 단위 테스트가 로컬로 실행되어 스냅 샷을 만든 다음 CI 서버가 다른 시간대에서 실행되어 스냅 샷 비교가 실패하는 경우 jest). 나는 우리 Date와 일부 지원 방법을 조롱했습니다 .

describe('...', () => {
  let originalDate;

  beforeEach(() => {
    originalDate = Date;
    Date = jest.fn(
      (d) => {
        let newD;
        if (d) {
          newD = (new originalDate(d));
        } else {
          newD = (new originalDate('2017-05-29T10:00:00z'));
        }
        newD.toLocaleString = () => {
          return (new originalDate(newD.valueOf())).toLocaleString("en-US", {timeZone: "America/New_York"});
        };
        newD.toLocaleDateString = () => {
          return (new originalDate(newD.valueOf())).toLocaleDateString("en-US", {timeZone: "America/New_York"});
        };
        newD.toLocaleTimeString = () => {
          return (new originalDate(newD.valueOf())).toLocaleTimeString("en-US", {timeZone: "America/New_York"});
        };
        return newD;
      }
    );
    Date.now = () => { return (Date()); };
  });

  afterEach(() => {
    Date = originalDate;
  });

});


답변

npm에서 ctoc을 사용해보십시오.
https://www.npmjs.com/package/ctoc_timezone

시간대 (대부분의 시간대는 약 400)를 변경하는 간단한 기능과 모든 사용자 정의 형식을 표시하고 싶습니다.