Подтвердить что ты не робот

Как определить часовой пояс по смещению UTC?

У меня есть сценарий, в котором у меня есть смещение по часовой стрелке (в минутах), и вам нужно определить часовой пояс для него. Я знаю, что все данные недоступны (например, может быть несколько часовых поясов со смещением -240 минут), но приемлемо "лучшее предположение".

Мой первый проход выглядел так:

foreach (var info in TimeZoneInfo.GetSystemTimeZones())
{
    if (info.BaseUtcOffset.TotalMinutes == timezoneOffset)
    {
         // do something here if this is a valid timezone
    }
}

Эта сортировка работает, но мне нужно учитывать дневные сбережения, которые меня отбрасывают. Я добавил этот ужасный взлом:

foreach (var info in TimeZoneInfo.GetSystemTimeZones())
{
    var extra = info.IsDaylightSavingTime(DateTime.Now) ? 60 : 0;
    if (info.BaseUtcOffset.TotalMinutes + extra == timezoneOffset)
    {
         // do something here if this is a valid timezone
    }
}

Это работает "достаточно хорошо" в том, что я могу показать пользователю правильное время для них, когда переход на летнее время не действует, а во время DST около 70%. Тем не менее... это какой-то ужасный код для моих глазных яблок.

Есть ли лучший способ сделать это? Более элегантность была бы хорошей, и больше точности было бы еще лучше.

Обновление

Технически у меня есть доступ к любой информации, которую Javascript может получить относительно даты. У меня есть страница, на которой я разместил скрытое поле под названием "offset". У меня есть функция JQuery, которая заполняет поле смещения DateTime(). GetTimezoneOffset(). Хотя я ничего не вижу в объекте DateTime, который поможет, возможно, это откроет другие возможности для идей.

4b9b3361

Ответ 1

Короткий ответ: вы не можете.

Летнее время делает невозможным. Например, нет никакого способа определить, только из UTC-коррекции, разницу между Аризоной и Калифорнией летом, или Аризону и Нью-Мексико зимой (так как Аризона не наблюдает DST).

Существует также вопрос о том, во сколько раз в разных странах наблюдается ДСТ. Например, в США DST начинается раньше и заканчивается позже, чем в Европе.

Возможно близкое предположение (т.е. +/- час), но если вы используете его для отображения времени для пользователей, вы неизбежно покажете неправильное время для некоторых из них.


Обновить. Из комментариев, похоже, ваша основная цель - отобразить временную метку в пользовательском локальном часовом поясе. Если это то, что вы хотите сделать, вы должны отправить время как временную метку UTC, а затем просто переписать его в браузере пользователя с помощью Javascript. В случае, если у них нет Javascript, они все равно будут видеть временную метку UTC. Вот функция, которую я придумал в этом вопросе, который я использовал в этой Greasemonkey script. Вы можете настроить его в соответствии с вашими потребностями.

//@param timestamp An ISO-8601 timestamp in the form YYYY-MM-DDTHH:MM:SS±HH:MM
//Note: Some other valid ISO-8601 timestamps are not accepted by this function
function parseISO8601(timestamp)
{
  var regex = new RegExp("^([\\d]{4})-([\\d]{2})-([\\d]{2})T([\\d]{2}):([\\d]{2}):([\\d]{2})([\\+\\-])([\\d]{2}):([\\d]{2})$");
  var matches = regex.exec(timestamp);
  if(matches != null)
  {
    var offset = parseInt(matches[8], 10) * 60 + parseInt(matches[9], 10);
    if(matches[7] == "-")
      offset = -offset;

    return new Date(
      Date.UTC(
        parseInt(matches[1], 10),
        parseInt(matches[2], 10) - 1,
        parseInt(matches[3], 10),
        parseInt(matches[4], 10),
        parseInt(matches[5], 10),
        parseInt(matches[6], 10)
      ) - offset*60*1000
    );
  }
  return null;
}

Вот функция, которую я использую в своем блоге, чтобы отобразить анализируемую метку времени в пользовательском локальном часовом поясе. Опять же, вы можете настроить его в нужном формате.

var weekDays = new Array("Sunday", "Monday", "Tuesday", "Wednesday",
        "Thursday", "Friday", "Saturday");
var months = new Array("January", "February", "March", "April", "May", "June",
        "July", "August", "September", "October", "November", "December");

function toLocalTime(date)
{
  var hour = date.getHours();
  var ampm = (hour < 12 ? "am" : "pm");
  hour = (hour + 11)%12 + 1;

  var minutes = date.getMinutes();
  if(minutes < 10)
    minutes = "0" + minutes;

  return weekDays[date.getDay()] + ", "
       + months[date.getMonth()] + " "
       + date.getDate()          + ", "
       + date.getFullYear()      + " at "
       + hour                    + ":"
       + minutes                 + " "
       + ampm;
}

Ответ 2

Зная только смещение от UTC, вы не можете определить, в каком часовом поясе вы находитесь, из-за DST. Вы можете подумать о временной части времени, чтобы попытаться угадать, действовал ли DST тогда или нет, но политические соображения делают это почти невозможным, поскольку разные юрисдикции меняют определение DST.

Ответ 3

С некоторыми обманами вы можете быть в порядке 99% времени и закрыть остальные 1%. Проверьте jstimezonedetect для чрезвычайно тщательной реализации.

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