Как правильно преобразовать время во временные интервалы?

Скажем, пользователь в CA, США выбирает дату, время и часовой пояс:

Всемирный пивной марафон начинается на 8/15/2013 10:00, UTC-08: 00

Другой пользователь в Центральной Европе открывает страницу, на которой отображаются эта дата и время. Он не хочет делать расчеты времени (уже было немного пива). Он просто хочет видеть эту дату и время:

8/15/2013 19:00

Учитывая, что браузер получает информацию о дате и времени, введенную пользователем в Калифорнии:

Есть ли способ, в javascript, без внешних веб-сервисов, сделать правильное преобразование? То есть, чтобы обнаружить, что 10 утра UTC-08: 00 действительно должно быть 10 утра UTC-07: 00, так как это переход на летнее время.

Возможно, я неправильно понял это с самого начала, но я не хочу, чтобы пользователь ввода мог подумать, следует ли ему выбирать UTC-08: 00 (PST) или UTC-07: 00 (PDT). Я предполагаю, что, поскольку стандартный часовой пояс в СА - это PST, люди не переключаются на размышления в PDT в летнее время. Или они?!

В центральной Европе стандартная дата - UTC + 01: 00, дата перехода на летнее время - UTC + 02: 00. Таким образом, разница между CA и Европой должна составлять 9 часов, за исключением двух периодов в году, когда одна или другая область переключается между режимами Standard и Daylight Saving.

Update:

После того, как мы больше думаем и читаем комментарии, мне в идеале понадобится следующее:

var utcOffset = f('2013-08-15T10:00', 'America/Los_Angeles');
// utcOffset == "-07:00"
var utcOffset = f('2013-11-15T10:00', 'America/Los_Angeles');
// utcOffset == "-08:00"

Пока это выглядит как moment.js/timezone plugin, предложенный Guido Preite, способен сделать это (более или менее).

Любой другой способ, используя API-интерфейсы браузера?

Ответ 1

Есть ли способ, в javascript, без внешних веб-сервисов, сделать правильное преобразование? То есть, чтобы обнаружить, что 10 утра UTC-08: 00 действительно должно быть 10 утра UTC-07: 00, так как это переход на летнее время.

10: 00-8 и 10: 00-7 - два разных момента времени. Они равны 18: 00Z и 17: 00Z соответственно (Z = UTC). Когда вы измеряете с точки зрения смещения, переход на летнее время не происходит. Когда-нибудь.

Я предполагаю, что, поскольку стандартный часовой пояс в СА - это PST, люди не переключаются на размышления в PDT в летнее время. Или они?!

В общем, люди просто думают в "Тихоокеанском времени", а это значит, что и PST зимой, и PDT летом. Но компьютеры точнее. Когда вы видите PST, это означает UTC-8. Когда вы видите PDT, это означает UTC-7. Было бы неверно использовать ярлык с использованием одной формы, одновременно ссылаясь на смещение другого.

Сокращения часовых поясов может быть неоднозначным. В идеале, при обращении к зоне программно, вы должны использовать имя зоны IANA, например America/Los_Angeles. Однако в настоящее время это невозможно во всех исполняемых файлах JavaScript без библиотеки. (Они работают над этим, хотя.)

В центральной Европе стандартная дата - UTC + 01: 00, дата перехода на летнее время - UTC + 02: 00. Таким образом, разница между CA и Европой должна составлять 9 часов, за исключением двух периодов в году, когда одна или другая область переключается между режимами Standard и Daylight Saving.

Правильно. Они могут быть разделены на 8, 9 или 10 часов. Они переключаются в совершенно разные времена, поэтому не пытайтесь управлять этим самостоятельно.

До сих пор похоже, что плагин moment.js/timezone, предложенный Guido Preite, способен на это (более или менее).

Moment-timezone - отличная библиотека. Однако, из описанного вами сценария, я не думаю, что вам нужно беспокоиться о преобразовании часового пояса так же, как вы думаете. Посмотрите, можете ли вы следовать этой логике:

  • Пользователь в Калифорнии вводит дату и время в текстовое поле.
  • Вы читаете это значение текстового поля в строке и разбираете его в дату:

    var dt = new Date("8/15/2013 10:00");
    

    или используя moment.js:

    var m = moment("8/15/2013 10:00", "M/D/YYYY HH:mm");
    
  • Поскольку это выполняется на пользовательском компьютере, JavaScript автоматически предполагает, что это локальная дата и время. Вам не нужно предоставлять информацию о каком-либо смещении или часовом поясе.

  • Это означает, что из-за переходов DST, что введенное время может быть недействительным или неоднозначным. JavaScript не делает такую ​​отличную работу при обработке, что на самом деле - вы получите разные результаты в разных браузерах. Если вы хотите быть недвусмысленным, тогда вы предоставите смещение.

    // PST
    var dt = new Date("3/11/2013 1:00 UTC-08:00");
    
    // PDT
    var dt = new Date("3/11/2013 1:00 UTC-07:00");
    
  • Как только у вас есть Date (или moment), вы можете оценить его эквивалент UTC:

    var s = dt.toISOString();  //  2013-08-15T17:00:00Z
    

    это то же самое с moment.js, но у вас будет лучшая поддержка браузера:

    var s = m.toISOString();  //  2013-08-15T17:00:00Z
    
  • Вы сохраняете это значение UTC в своей базе данных.

  • Другой пользователь в Центральной Европе приходит и загружает данные.

  • Вы загружаете его в Date или moment в JavaScript:

    var dt = new Date("2013-08-15T17:00:00Z");
    

    или с moment.js(опять же, лучше поддержка браузера)

    var m = moment("2013-08-15T17:00:00Z")
    
  • Поскольку JavaScript знает правила часовых поясов локального компьютера, вы можете отобразить эту дату, и она будет представлена ​​часовым поясом Центральной Европы:

    var s = dt.ToString();  //  browser specific output
    // ex: "Thu Aug 15 2013 19:00:00 GMT+0200 (Central Europe Daylight Time)"
    

    или с помощью момента .js, вы можете лучше управлять форматом вывода

    var s = m.format("DD/MM/YYYY HH:mm"); // "15/08/2013 19:00"
    

    вы также можете позволить moment.js решить, какой локализованный формат должен выводиться:

    var s = m.format("llll"); // "Thu, 15 Aug 2013 19:00"
    

Подводя итог - если вы заинтересованы только в преобразовании в локальный часовой пояс (в любой зоне, которая может быть), и вы можете сделать это всего лишь с помощью Date. Moment.js упростит анализ и форматирование, но это не совсем необходимо.

Есть только несколько сценариев, для которых требуется библиотека часовых поясов (например, момент-время или другие).

  • Вы хотите конвертировать в зону или из зоны, которая не является местным часовым поясом или UTC.

  • Вы работаете с датами, которые были в прошлом, и с тех пор произошли изменения правил часового пояса или правил летнего времени, и у вас есть даты, которые будут интерпретироваться по-другому в соответствии с новыми правилами, чем со старыми. Это немного технически, но это происходит. Подробнее здесь и здесь.

Ответ 2

Конструктор по умолчанию создает экземпляр локального времени

var localDate = new Date(); 

Я не могу проверить это прямо сейчас, но вы должны быть в состоянии предоставить ваше datetime (как параметр для конструктора).

var eventDate = [SOMEDATE];
var localDate = new Date(eventDate);

.., и тогда вы должны иметь возможность вызывать функции объекта Date, такие как getMonth, которая возвращает данные в локальный часовой пояс. Как написано на: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date

Примечание1: Без сервера = вообще нет сервера | db? Если есть, дата должна быть сохранена как UTC в db и загружать ее как локальное время для каждого пользователя.. таким образом вам не придется беспокоиться о конверсиях.

Примечание2: у этого вопроса есть код, показывающий, как получить разницу в часовом поясе: Как получить точное местное время клиента?

Ответ 3

Я разработал это решение на основе других примеров... надеюсь, что это сработает для вас! Доступно на jsfiddle.

/* 
* Author: Mohammad M. AlBanna
* Website: MBanna.me
* Description: Get the current time in different time zone 
*/

//Check daylight saving time prototype
Date.prototype.stdTimezoneOffset = function() {
    var jan = new Date(this.getFullYear(), 0, 1);
    var jul = new Date(this.getFullYear(), 6, 1);
    return Math.max(jan.getTimezoneOffset(), jul.getTimezoneOffset());
}

Date.prototype.dst = function() {
    return this.getTimezoneOffset() < this.stdTimezoneOffset();
}

var today = new Date();
var isDST = today.dst() ? true : false;
var pstOffset = isDST ? 7 : 8;
var cstOffset = isDST ? 5 : 6;
var estOffset = isDST ? 4 : 5;
var gmtOffset = 1;

pstOffset = pstOffset * 60 * 60 * 1000;
cstOffset = cstOffset * 60 * 60 * 1000;
estOffset = estOffset * 60 * 60 * 1000;
gmtOffset = gmtOffset * 60 * 60 * 1000;

var todayMillis = today.getTime();
var timeZoneOffset = (today.getTimezoneOffset() * 60 * 1000);

var curretPST = todayMillis - pstOffset; 
var curretCST = todayMillis - cstOffset; 
var curretEST = todayMillis - estOffset;
var curretGMT = todayMillis - gmtOffset;

addP("PST Time : " + new Date(curretPST).toUTCString());
addP("CST Time : " + new Date(curretCST).toUTCString());
addP("EST Time : " + new Date(curretEST).toUTCString());
addP("GMT Time : " + new Date(curretGMT).toUTCString());
addP("Local Time : " + new Date(today.getTime() - timeZoneOffset ).toUTCString());

function addP(value){
    var p = document.createElement("p");
    p.innerHTML = value;
    document.body.appendChild(p);
}