Как игнорировать часовой пояс пользователя и заставить Date () использовать определенный часовой пояс - PullRequest
93 голосов
/ 05 мая 2010

В приложении JS я получаю метку времени (например, 1270544790922) с сервера (Ajax).

На основе этой временной метки я создаю Date объект, используя:

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

Теперь _date декодированная временная метка в текущем часовом поясе пользователя. Я этого не хочу.

Я бы хотел, чтобы _ date преобразовал эту временную метку в текущее время в городе Хельсинки в Европе (не учитывая текущий часовой пояс пользователя).

Как я могу это сделать?

Ответы [ 6 ]

61 голосов
/ 05 мая 2010

Базовое значение объекта Date находится в UTC. Чтобы доказать это, обратите внимание, что если вы наберете new Date(0), вы увидите что-то вроде: Wed Dec 31 1969 16:00:00 GMT-0800 (PST). 0 обрабатывается как 0 в GMT, но метод .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 для описания того, когда произойдут изменения часового пояса, это должно решить вашу проблему.

Заключение - Я думаю, что специально для этой цели вы должны использовать библиотеку дат, такую ​​как момент-часовой пояс .

17 голосов
/ 22 ноября 2011

Для учета миллисекунд и часового пояса пользователя используйте следующее:

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
13 голосов
/ 21 апреля 2016

Просто еще один подход

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);

Ура!

13 голосов
/ 10 октября 2012

У меня есть подозрение, что Ответ не дает правильного результата. В вопросе запрашивающий хочет конвертировать метку времени с сервера в текущее время в Хельсинки, не учитывая текущий часовой пояс пользователя.

Это факт, что часовой пояс пользователя может быть тем, чем когда-либо, поэтому мы не можем доверять ему.

Если, например. отметка времени 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);

Когда житель Нью-Йорка заходит на страницу, выводится предупреждение (_helsenkiTime):

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

А когда финляндер заходит на страницу, выдается предупреждение (_helsenkiTime):

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

Таким образом, эта функция верна, только если посетитель страницы имеет целевой часовой пояс (Европа / Хельсинки) на своем компьютере, но не работает почти во всех других частях мира. А поскольку временной меткой сервера обычно является метка времени UNIX, то есть по определению в UTC, то есть количество секунд, прошедшее с начала Unix (1 января 1970 года, 00:00:00 по Гринвичу), мы не можем определить DST или не-DST по метке времени. *

Таким образом, решение состоит в том, чтобы ОТКЛЮЧИТЬ текущий часовой пояс пользователя и реализовать какой-либо способ для вычисления смещения UTC независимо от того, указана ли дата в летнем времени или нет. Javascript не имеет собственного метода для определения истории перехода DST другого часового пояса, кроме текущего часового пояса пользователя. Этого проще всего добиться с помощью сценария на стороне сервера, поскольку у нас есть простой доступ к базе данных часовых поясов сервера со всей историей переходов всех часовых поясов.

Но если у вас нет доступа к базе данных часовых поясов сервера (или любого другого сервера) И временная метка указана в формате UTC, вы можете получить аналогичную функциональность, жестко закодировав правила DST в Javascript.

Чтобы охватить даты 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

Конечно, если вы можете вернуть временную метку в форме, в которой смещение (летнее или летнее) уже добавлено к временной метке на сервере, вам не нужно рассчитывать ее на стороне клиента, и вы можете значительно упростить функцию. НО не забывайте НЕ использовать timezoneOffset (), потому что тогда вам придется иметь дело с пользовательским часовым поясом, а это не желаемое поведение.

2 голосов
/ 29 марта 2017

Предполагая, что вы получите временную метку в хельсинкском времени, я бы создал объект даты, установленный на полночь 1 января 1970 года по Гринвичу (для игнорирования настроек часового пояса в браузере). Затем просто добавьте к нему необходимое количество миллисекунд.

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 голосов
/ 29 августа 2014

Вы можете использовать setUTCMilliseconds()

var _date = new Date();
_date.setUTCMilliseconds(1270544790922);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...