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


232

특정 시간대의 날짜 시간을 문자열로 가지고 있으며 이것을 현지 시간으로 변환하고 싶습니다. 그러나 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에서 다른 시간대에서 현지 시간으로 시간을 변환하는 방법은 무엇입니까?



1
날짜 객체에는 시간대가 없으며 UTC입니다.
RobG

답변:


351

배경

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


1
표시된 타임 스탬프는 시간대와 무관 하므로 "represent"를 "output / parse"로 변경하십시오.
Bergi

1
@ Bergi-나는 이것을 다시 생각하고 당신과 동의합니다. 이에 따라 내 답변을 업데이트했습니다.
Matt Johnson-Pint

1
Firebug 콘솔 에서이 작업을 수행 할 때 : var date_time = new Date()의 값 date_time은 (AEST에서는 나를 위해) Date {Sun Aug 21 2016 22:18:47 GMT+1000 (AEST)}따라서 시간대 저장 한 것 같습니다 . date_time시간대를 포함하지 않고 순전히 UTC 시간을 보장하려면 어떻게해야 합니까?
user1063287

흠,이 답변에 따르면 ( stackoverflow.com/a/8047885/1063287 ), 이것은 다음과 같습니다 : new Date().getTime();
user1063287

1
@ user1063287- toString 메소드는 호스트 시간대 오프셋을 사용하여 "로컬"시간대의 날짜 및 시간을 생성합니다. 날짜 객체 자체의 시간 값은 1970-01-01T00 : 00 : 00Z에서 오프셋이므로 UTC가 유효합니다. UTC 날짜 및 시간을 보려면 toISOString을 사용 하십시오 .
RobG

69

매트 존슨이 말했듯이

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

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()}`);


6
이 답변이 더 이상 사랑을 얻지 못하는 이유가 궁금합니다. 내 목적을 위해 그것은 절대적으로 최고의 솔루션입니다. 내 응용 프로그램에서 모든 날짜는 UTC이지만 UI의 명시 적 IANA 시간대로 입력하거나 출력해야합니다. 이를 위해이 솔루션을 사용하며 완벽하게 작동합니다. 간단하고 효과적이며 표준입니다.
logidelic

2
@ logidelic 그것은 꽤 새로운 게시물입니다. 솔직히 말해서, 나는 당신이 toLocaleString역효과를 달성하는 데 사용할 수있는 것을 강타했을 때 놀랐습니다 . 그것에 대해 기사를 쓰고 나를 언급 :-)
commonpike

1
GMT에없는 노드 환경의 경우 위 코드를 var invdate = new Date (date.toLocaleString ( 'en-US', {timeZone : ianatz}))에서 변경해야합니다. var invdate로 = 새 날짜 ($ {date.toLocaleString ( 'en-US', {timeZone : ianatz})} GMT`);
Mike P.

5
브라우저는 toLocaleString 의 출력을 구문 분석 할 필요가 없으므로 잘못된 전제를 기반으로합니다.
RobG

3
"...이 답변이 더 이상 사랑을 얻지 못하는 이유는 무엇입니까?" - Date그것이 반환 하는 객체가 거짓말 이기 때문 입니다. 표시된 예에서도 문자열 출력에는 로컬 시스템의 시간대가 포함됩니다. 내 컴퓨터에서 결과 모두 "GMT-0700 (태평양 일광 절약 시간)"으로 표시되는데, 첫 번째 경우에만 정확합니다 (토론토는 실제로 동부 표준시입니다). 문자열 출력 외에도 Date개체 내에서 유지되는 타임 스탬프 는 다른 시점으로 이동했습니다. 이것은 유용한 기술 이 수 있지만 많은주의 사항이 있습니다. 주로 Date객체 기능에는 정상적인 출력이 없습니다.
Matt Johnson-Pint

30

에 시간대 오프셋을 지정할 수 있습니다 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합니다.)


16
ISO 8601 확장 형식 이외의 형식을 구문 분석하는 것은 구현에 따라 다르므로 의존해서는 안됩니다. 표준 시간대 약어에 대한 표준은 없습니다. 예를 들어 "EST"는 3 가지 다른 영역 중 하나를 나타낼 수 있습니다.
RobG

1
이 주석의 예제는 종종 인터넷 익스플로러에서 작동하지 않습니다. 이 게시물에 대한 이전 의견에서 언급했듯이 ISO 8601이 중요합니다. ECMA-262 (Javascript 5th) 에디션 언어 사양을 읽고 확인했습니다.
Dakusan

12

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

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)

이 솔루션은 내 필요에 적합했습니다. 일광 절약 시간을 정확하게 계산할 수 있는지 잘 모르겠습니다.
Hossein Amin

tzDate직접 돌아 오지 않습니까?
레위

8

타사 라이브러리에 대해 걱정하지 않고이 작업을 수행하는 가장 지원되는 방법 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함수를 사용 하여 원하는 결과를 반환합니다.


어디서 계산 timezone_offset했습니까?
Anand Somani

1
죄송합니다. 변수 중 하나에 라벨이 잘못되었습니다. , 또는 그 반대 timezone_offset여야합니다 offset. 올바른 변수 이름을 표시하기 위해 답변을 편집했습니다.
Shaun Cockerill

3

단위 테스트와 비슷한 문제가 발생했습니다 (특히 단위 테스트가 로컬로 실행되어 스냅 샷을 만든 다음 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;
  });

});


2

위의 답변을 바탕 으로이 기본 하나의 라이너를 사용하여 긴 시간대 문자열을 세 글자 문자열로 변환합니다.

var longTz = 'America/Los_Angeles';
var shortTz = new Date().
    toLocaleString("en", {timeZoneName: "short", timeZone: longTz}).
    split(' ').
    pop();

제공된 날짜에 따라 PDT 또는 PST를 제공합니다. 내 특정 사용 사례에서 Salesforce (Aura / Lightning)에서 개발하면 백엔드에서 사용자 시간대를 긴 형식으로 가져올 수 있습니다.


나는 때때로 부유을 재생하고자해서, '미국 / 로스 엔젤레스는'그것이 대해 "대표 위치"입니다, 시간대가 아닌 특정 오프셋과 일광 절약 규칙과 (당 이러한 변화의 역사 IANA 시간대 데이터베이스 ) . ;-)
RobG

하하, 당신은 여기에 여러 답변에 대한 의견을 게시해야합니다 : P
Shane

2

나는 3 년이 너무 늦다는 것을 알고 있지만 순간 시간대 라이브러리를 제외하고는 그가 여기에서 요구하는 것과 정확히 동일하지 않은 것을 발견하지 못했기 때문에 다른 누군가를 도울 수 있습니다.

나는 독일 시간대와 비슷한 것을했습니다. 일광 절약 시간과 366 일의 윤년으로 인해 조금 복잡합니다.

"isDaylightSavingTimeInGermany"함수를 사용하면 약간의 작업이 필요할 수 있지만 일광 절약 시간에 따라 시간대가 달라집니다.

어쨌든이 페이지를 확인하십시오 : https://github.com/zerkotin/german-timezone-converter/wiki

주요 메소드는 다음과 같습니다. convertLocalDateToGermanTimezone convertGermanDateToLocalTimezone

문서화에 노력을 기울 였으므로 혼란스럽지 않습니다.


이것은 의견이어야하며 대답이 아닙니다.
RobG

1

시도 : date-from-timezone , 기본적으로 제공되는 도움으로 예상 날짜를 해결합니다.Intl.DateTimeFormat .

나는 이미 몇 년 동안 내 프로젝트 중 하나 에서이 방법을 사용했지만 이제는 작은 OS 프로젝트로 게시하기로 결정했습니다. :)


0

이오니아 사용자의 .toISOString()경우 html 템플릿과 함께 사용해야하므로이 문제 가 발생했습니다.

이것은 현재 날짜를 잡을 것입니다. 물론 선택한 날짜의 이전 답변에 추가 할 수도 있습니다.

나는 이것을 사용하여 고정시켰다.

date = new Date();
public currentDate: any = new Date(this.date.getTime() - this.date.getTimezoneOffset()*60000).toISOString();

* 60000은 CST 인 UTC -6을 나타내므로 TimeZone이 필요한 모든 수와 차이를 변경할 수 있습니다.


이것은 질문자가 찾고있는 답이 아닙니다. 그는 날짜를 특정 시간대로 가져 오려고했습니다.
Richard Vergis

@RichardVergis이 질문은 사용자가 현지 시간으로 변경하기를 원하지만 어느 시간대에 있는지 명시하지는 않습니다. 내 시간대를 예로 들어 사용자가 내 예를 기반으로 명확하게 읽을 수 있으며 입력 할 수 있습니다 시간대 오프셋.
Stephen Romero

0

어쩌면 이것이 당신을 도울 것입니다

/**
 * Shift any Date timezone.
 * @param {Date} date - Date to update.
 * @param {string} timezone - Timezone as `-03:00`.
 */
function timezoneShifter(date, timezone) {
  let isBehindGTM = false;
  if (timezone.startsWith("-")) {
    timezone = timezone.substr(1);
    isBehindGTM = true;
  }

  const [hDiff, mDiff] = timezone.split(":").map((t) => parseInt(t));
  const diff = hDiff * 60 + mDiff * (isBehindGTM ? 1 : -1);
  const currentDiff = new Date().getTimezoneOffset();

  return new Date(date.valueOf() + (currentDiff - diff) * 60 * 1000);
}



const _now = new Date()
console.log(
  [
    "Here: " + _now.toLocaleString(),
    "Greenwich: " + timezoneShifter(_now, "00:00").toLocaleString(),
    "New York: " + timezoneShifter(_now, "-04:00").toLocaleString(),
    "Tokyo: " + timezoneShifter(_now, "+09:00").toLocaleString(),
    "Buenos Aires: " + timezoneShifter(_now, "-03:00").toLocaleString(),
  ].join('\n')
);


-2

같은 문제에 직면 하여이 문제를 사용했습니다.

Console.log (Date.parse ( "Jun 13, 2018 10:50:39 GMT + 1"));

당신이 확인할 수있는 밀리 초를 반환합니다 +100 팀 존 영국 시간을 초기화하는 것이 도움이되기를 바랍니다!


3
(이 게시물은 질문에 대한 양질의 답변 을 제공하지 않는 것 같습니다 . 답변 을 수정하거나 질문에 대한 의견으로 게시하십시오).
sɐunıɔ ןɐ qɐp
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.