사용자의 시간대를 무시하고 Date ()가 특정 시간대를 사용하도록하는 방법


104

JS 앱 1270544790922에서 서버 (Ajax)에서 타임 스탬프 (eq. )를 받습니다 .

해당 타임 스탬프 Date를 기반으로 다음을 사용하여 객체를 만듭니다 .

var _date = new Date();
_date.setTime(1270544790922);

이제 _date현재 사용자 로케일 시간대의 디코딩 된 타임 스탬프입니다. 나는 그것을 원하지 않는다.

_ date이 (가)이 타임 스탬프를 유럽 헬싱키시의 현재 시간으로 변환하고 싶습니다 (사용자의 현재 시간대 무시).

어떻게 할 수 있습니까?


헬싱키의 시간대 오프셋은 겨울에는 +2이고 DST에서는 +3입니다. 그러나 DST가 언제인지 누가 압니까? JS에서 사용할 수없는 일부 로케일 메커니즘 만
warpech

가능하지만 자바 스크립트의 기본 메소드를 사용하지 않는 것은 자바 스크립트가 사용자 시스템의 현재 시간대 이외의 다른 시간대의 시간대 전환 기록을 결정하는 방법이 없기 때문입니다 (그리고 적어도 80 년대 날짜로 이동하면 브라우저에 따라 다릅니다). 그러나 이렇게하면 가능합니다 : stackoverflow.com/a/12814213/1691517 그리고 내 대답이 올바른 결과를 제공한다고 생각합니다.
Timo Kähkönen

답변:


64

Date 객체의 기본 값은 실제로 UTC입니다. 이를 증명하기 위해 입력 new Date(0)하면 다음과 같은 내용이 표시 Wed Dec 31 1969 16:00:00 GMT-0800 (PST)됩니다.. 0은 GMT에서 0으로 처리되지만 .toString()메서드는 현지 시간을 표시합니다.

참고로 UTC는 세계 시간 코드를 의미 합니다. 현재 두 곳의 다른 위치에있는 현재 시간은 동일한 UTC이지만 출력 형식은 다르게 지정할 수 있습니다.

여기서 필요한 것은 몇 가지 서식입니다.

var _date = new Date(1270544790922); 
// outputs > "Tue Apr 06 2010 02:06:30 GMT-0700 (PDT)", for me
_date.toLocaleString('fi-FI', { timeZone: 'Europe/Helsinki' });
// outputs > "6.4.2010 klo 12.06.30"
_date.toLocaleString('en-US', { timeZone: 'Europe/Helsinki' });
// outputs > "4/6/2010, 12:06:30 PM"

이것은 작동하지만 .... 사용자의 시간대를 설명하기 때문에 목적에 따라 다른 날짜 방법을 실제로 사용할 수 없습니다. 원하는 것은 헬싱키 시간대와 관련된 날짜 개체입니다. 이 시점에서 귀하의 옵션은 타사 라이브러리를 사용하거나 (권장) 날짜 개체를 해킹하여 대부분의 방법을 사용할 수 있도록하는 것입니다.

옵션 1-순간 시간대와 같은 타사

moment(1270544790922).tz('Europe/Helsinki').format('YYYY-MM-DD HH:mm:ss')
// outputs > 2010-04-06 12:06:30
moment(1270544790922).tz('Europe/Helsinki').hour()
// outputs > 12

이것은 우리가 다음에 할 일보다 훨씬 더 우아하게 보입니다.

옵션 2-날짜 개체 해킹

var currentHelsinkiHoursOffset = 2; // sometimes it is 3
var date = new Date(1270544790922);
var helsenkiOffset = currentHelsinkiHoursOffset*60*60000;
var userOffset = _date.getTimezoneOffset()*60000; // [min*60000 = ms]
var helsenkiTime = new Date(date.getTime()+ helsenkiOffset + userOffset);
// Outputs > Tue Apr 06 2010 12:06:30 GMT-0700 (PDT)

여전히 GMT-0700 (PDT)이라고 생각하지만 너무 세게 쳐다 보지 않으면 목적에 유용한 날짜 개체로 착각 할 수 있습니다.

나는 편리하게 부분을 건너 뛰었다. 정의 할 수 있어야합니다 currentHelsinkiOffset. date.getTimezoneOffset()서버 측에서 사용할 수 있거나 일부 if 문을 사용하여 시간대 변경이 발생할 때를 설명하면 문제가 해결됩니다.

결론 -특히이 목적을 위해 moment-timezone 과 같은 날짜 라이브러리를 사용해야한다고 생각 합니다 .


또한 ... 한 위치에서 gmt 오프셋을 사용하여 유사한 작업을 수행 할 수 있습니다. 이 경우 자바 스크립트가 전혀 필요하지 않습니다.
Parris

미안하지만 정반대를 의미합니다. :) 질문을 편집했습니다. 아마도 이제 더 명확 해졌습니다
warpech

좋아, 내 솔루션을 변경했습니다. 나는 이것이 당신이 찾고있는 것이라고 생각합니다.
Parris

불행히도 그것이 제가 생각 해낸 유일한 것입니다. 브라우저가 나를 위해 "_helsinkiOffset"을 생성 할 수 있다고 생각했습니다.
warpech

2
저는 믿습니다 *60*60대신해야 *60000getTime를 밀리 초에서와 같이, 그리고에, getTimezoneOffset가있는 분에 60000 밀리 초, 아니 60 * 60 == 3600가있는 분에
AaronLS

20

밀리 초와 사용자의 시간대를 고려하려면 다음을 사용하십시오.

var _userOffset = _date.getTimezoneOffset()*60*1000; // user's offset time
var _centralOffset = 6*60*60*1000; // 6 for central time - use whatever you need
_date = new Date(_date.getTime() - _userOffset + _centralOffset); // redefine variable

중앙에 고정 오프셋을 사용하여 대체하기 위해 고정 시간이 00:00 인 CST를 사용하여 날짜를 만든 다음 해당 날짜의 getUTCHHours를 사용하는 개념을 사용했습니다.
grantwparks

+1 이것은 나를 위해 일했습니다. 밀리 초를 처리하지 않고 'the'답변이 어떻게 작동하는지 확실하지 않습니다.
Chris Wallis

2
@Ehren은 gmt에 도달하기 위해 timezoneOffset을 추가 한 다음 중앙 오프셋을 빼야하지 않습니까?
coder

15

또 다른 접근 방식

function parseTimestamp(timestampStr) {
  return new Date(new Date(timestampStr).getTime() + (new Date(timestampStr).getTimezoneOffset() * 60 * 1000));
};

//Sun Jan 01 2017 12:00:00
var timestamp = 1483272000000;
date = parseTimestamp(timestamp);
document.write(date);

건배!


2
일광 절약 시간으로 인해 의도하지 않은 결과가 발생할 수 있습니다. 클라이언트가 DST를 사용하는 시간대에있는 경우 구문 분석 결과가 한 시간 정도 떨어져있을 수 있습니다 (일부 영역에서는 한 시간의 일부를 사용함). 예 : 사용자는 뉴욕에 있으며 오늘은 7 월 4 일입니다. 이는 사용자가 GMT -0400 (DST가 시작된 이후 동부 일광 절약 시간대)에 있음을 의미합니다. 전달 된 타임 스탬프는 GMT-0500 (동부 표준 시간대-연중 DST 없음) 인 1 월 30 일에 대한 것입니다. getTimezoneOffset ()이 1 월에 있었던 오프셋이 아니라 지금 오프셋을 제공하기 때문에 결과는 한 시간 쉬게됩니다.
Dimitar Darazhanski

2
이 문제를 해결하려면, 당신이 할 필요가 당신은 사람 (현재 시간 이동)에 전달하는 날짜의 오프셋 시간이 걸릴 : new Date().getTimezoneOffset()로 변경해야합니다new Date(timestampStr).getTimezoneOffset()
디미타르 Darazhanski

13

답변 이 올바른 결과를 제공하지 않는다는 의심이 있습니다. 질문에서 asker는 사용자의 현재 시간대를 무시하고 서버에서 Hellsinki의 현재 시간으로 타임 스탬프를 변환하려고합니다.

사용자의 시간대가 될 수 있으므로 우리는 그것을 신뢰할 수 없습니다.

예. 타임 스탬프는 1270544790922이고 함수가 있습니다.

var _date = new Date();
_date.setTime(1270544790922);
var _helsenkiOffset = 2*60*60;//maybe 3
var _userOffset = _date.getTimezoneOffset()*60*60; 
var _helsenkiTime = new Date(_date.getTime()+_helsenkiOffset+_userOffset);

뉴요커가 페이지를 방문하면 alert (_helsenkiTime)은 다음을 인쇄합니다.

Tue Apr 06 2010 05:21:02 GMT-0400 (EDT)

핀란드 인이 페이지를 방문하면 alert (_helsenkiTime)이 출력합니다.

Tue Apr 06 2010 11:55:50 GMT+0300 (EEST)

따라서 페이지 방문자가 자신의 컴퓨터에 목표 시간대 (Europe / Helsinki)가 있지만 전 세계 거의 모든 지역에서 실패하는 경우에만 기능이 정확합니다. 그리고 서버 타임 스탬프는 일반적으로 Unix Epoch (1970 년 1 월 1 일 00:00:00 GMT) 이후의 시간 인 UTC로 정의 된 UNIX 타임 스탬프이므로 타임 스탬프에서 DST 또는 비 DST를 결정할 수 없습니다.

따라서 해결책은 사용자의 현재 시간대를 무시하고 날짜가 DST인지 여부에 관계없이 UTC 오프셋을 계산하는 방법을 구현하는 것입니다. Javascript에는 사용자의 현재 시간대가 아닌 다른 시간대의 DST 전환 이력을 결정하는 기본 방법이 없습니다. 우리는 모든 시간대의 전체 전환 이력으로 서버의 시간대 데이터베이스에 쉽게 액세스 할 수 있기 때문에 서버 측 스크립트를 사용하여 가장 간단하게이 작업을 수행 할 수 있습니다.

그러나 서버 (또는 다른 서버)의 시간대 데이터베이스에 액세스 할 수없고 타임 스탬프가 UTC 인 경우 Javascript에서 DST 규칙을 하드 코딩하여 유사한 기능을 얻을 수 있습니다.

유럽 ​​/ 헬싱키에서 1998-2099 년의 날짜를 다루기 위해 다음 함수 ( jsfiddled )를 사용할 수 있습니다 .

function timestampToHellsinki(server_timestamp) {
    function pad(num) {
        num = num.toString();
        if (num.length == 1) return "0" + num;
        return num;
    }

    var _date = new Date();
    _date.setTime(server_timestamp);

    var _year = _date.getUTCFullYear();

    // Return false, if DST rules have been different than nowadays:
    if (_year<=1998 && _year>2099) return false;

    // Calculate DST start day, it is the last sunday of March
    var start_day = (31 - ((((5 * _year) / 4) + 4) % 7));
    var SUMMER_start = new Date(Date.UTC(_year, 2, start_day, 1, 0, 0));

    // Calculate DST end day, it is the last sunday of October
    var end_day = (31 - ((((5 * _year) / 4) + 1) % 7))
    var SUMMER_end = new Date(Date.UTC(_year, 9, end_day, 1, 0, 0));

    // Check if the time is between SUMMER_start and SUMMER_end
    // If the time is in summer, the offset is 2 hours
    // else offset is 3 hours
    var hellsinkiOffset = 2 * 60 * 60 * 1000;
    if (_date > SUMMER_start && _date < SUMMER_end) hellsinkiOffset = 
    3 * 60 * 60 * 1000;

    // Add server timestamp to midnight January 1, 1970
    // Add Hellsinki offset to that
    _date.setTime(server_timestamp + hellsinkiOffset);
    var hellsinkiTime = pad(_date.getUTCDate()) + "." + 
    pad(_date.getUTCMonth()) + "." + _date.getUTCFullYear() + 
    " " + pad(_date.getUTCHours()) + ":" +
    pad(_date.getUTCMinutes()) + ":" + pad(_date.getUTCSeconds());

    return hellsinkiTime;
}

사용 예 :

var server_timestamp = 1270544790922;
document.getElementById("time").innerHTML = "The timestamp " + 
server_timestamp + " is in Hellsinki " + 
timestampToHellsinki(server_timestamp);

server_timestamp = 1349841923 * 1000;
document.getElementById("time").innerHTML += "<br><br>The timestamp " + 
server_timestamp + " is in Hellsinki " + timestampToHellsinki(server_timestamp);

var now = new Date();
server_timestamp = now.getTime();
document.getElementById("time").innerHTML += "<br><br>The timestamp is now " +
server_timestamp + " and the current local time in Hellsinki is " +
timestampToHellsinki(server_timestamp);​

그리고 이것은 사용자 시간대에 관계없이 다음을 인쇄합니다.

The timestamp 1270544790922 is in Hellsinki 06.03.2010 12:06:30

The timestamp 1349841923000 is in Hellsinki 10.09.2012 07:05:23

The timestamp is now 1349853751034 and the current local time in Hellsinki is 10.09.2012 10:22:31

물론 오프셋 (DST 또는 비 DST)이 이미 서버의 타임 스탬프에 추가 된 형태로 타임 스탬프를 반환 할 수 있다면 클라이언트 측에서 계산할 필요가 없으며 함수를 많이 단순화 할 수 있습니다. 그러나 timezoneOffset ()을 사용하지 않는 것을 기억하십시오. 사용자 시간대를 처리해야하고 이것은 원하는 동작이 아니기 때문입니다.


2
nb. 헬싱키에는 'l'이 하나뿐입니다. 이 실수는이 답변에서 정말로 손상됩니다.
Ben McIntyre

@BenMcIntyre 약간의 농담입니다. 아니면 그런 사람이어야합니다. :)
Timo Kähkönen

아, 절대 자신의 시간 / 시간대 구현을 코딩하지 마십시오 ...하지만 나는 -1에 너무 게으르다
mb21

3

헬싱키 시간으로 타임 스탬프를 받았다고 가정하면 1970 년 1 월 1 일 자정 UTC로 설정된 날짜 객체를 만듭니다 (브라우저의 현지 시간대 설정을 무시하기 위해). 그런 다음 필요한 밀리 초를 추가하십시오.

var _date	= new Date( Date.UTC(1970, 0, 1, 0, 0, 0, 0) );
_date.setUTCMilliseconds(1270544790922);

alert(_date); //date shown shifted corresponding to local time settings
alert(_date.getUTCFullYear());    //the UTC year value
alert(_date.getUTCMonth());       //the UTC month value
alert(_date.getUTCDate());        //the UTC day of month value
alert(_date.getUTCHours());       //the UTC hour value
alert(_date.getUTCMinutes());     //the UTC minutes value

날짜 개체에서 항상 UTC 값을 요청하려면 나중에주의하십시오. 이렇게하면 사용자는 로컬 설정에 관계없이 동일한 날짜 값을 볼 수 있습니다. 그렇지 않으면 날짜 값이 현지 시간 설정에 따라 이동됩니다.


0

당신은 사용할 수 있습니다 setUTCMilliseconds()

var _date = new Date();
_date.setUTCMilliseconds(1270544790922);

이 대답은 틀 렸습니다. setUTCMilliseconds는 지정된 밀리 초 수를 날짜에 추가합니다.
Tibor

@Tibor : MozDev에서 :이 setUTCMilliseconds()메서드는 표준시 에 따라 지정된 날짜의 밀리 초를 설정합니다. [...] 지정한 매개 변수가 예상 범위를 벗어나면 setUTCMilliseconds()그에 따라 Date 개체의 날짜 정보를 업데이트하려고합니다. 즉, DateUTC에서 주어진 Unix 타임 스탬프를 가진 객체를 생성합니다 .
jimasun 2017 년

w3schools에서 : setUTCMilliseconds () 메서드는 표준시에 따라 밀리 초 (0에서 999까지)를 설정합니다. 위의 답변을 시도하고 직접 확인하십시오.
Tibor

MDN에서 : 매개 변수 millisecondsValue : 밀리 초를 나타내는 0에서 999 사이의 숫자 ...
Tibor

new Date ()가 현재 현지 날짜로 날짜 객체를 만들기 때문에 예제가 예상대로 작동하지 않습니다. 그 후에 지정된 밀리 초 수를 추가합니다. 따라서 귀하의 예에서 현재 현지 날짜가 2017-05-04 인 경우 결과 날짜는 4027 년 이후의 날짜가됩니다.
Tibor
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.