Как определить часовой пояс по смещению UTC?
-
16-09-2019 - |
Вопрос
У меня есть сценарий, в котором у меня есть смещение часового пояса (в минутах), и мне нужно определить для него часовой пояс.Я знаю, что все данные недоступны (например, может быть несколько часовых поясов со смещением -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
}
}
Это работает «достаточно хорошо» в том смысле, что я могу показать пользователю правильное время, когда летнее время не действует, и примерно на 70% правильно во время летнего времени.Все еще...это какой-то ужасный код для моих глаз.
Есть лучший способ сделать это?Было бы хорошо, если бы было больше элегантности, а еще лучше — больше точности.
Обновлять
Технически у меня есть доступ к любой информации, которую Javascript может получить относительно даты.У меня есть страница, на которой я разместил скрытое поле под названием «смещение».У меня есть функция JQuery, которая заполняет поле смещения с помощью DateTime().getTimezoneOffset().Хотя я не вижу в объекте DateTime ничего, что могло бы помочь, возможно, это откроет другие возможности для идей.
Решение
Короткий ответ:ты не можешь.
Летнее время делает это невозможным.Например, невозможно определить, исключительно по смещению UTC, разницу между Аризоной и Калифорнией летом или Аризоной и Нью-Мексико зимой (поскольку в Аризоне не наблюдается летнее время).
Существует также вопрос о том, в какое время в разных странах соблюдается летнее время.Например, в США летнее время начинается раньше и заканчивается позже, чем в Европе.
Возможна близкая догадка (т.+/- час), но если вы используете его для отображения времени пользователям, вы неизбежно будете показывать неправильное время некоторым из них.
Обновлять:Судя по комментариям, ваша основная цель — отобразить временную метку в местном часовом поясе пользователя.Если это то, что вы хотите сделать, вам следует отправить время как метку времени UTC, а затем просто переписать его в браузере пользователя с помощью Javascript.В случае, если у них не включен Javascript, они все равно будут видеть полезную метку времени UTC.Вот функция, которую я придумал в этот вопрос, который я использовал в этот скрипт Greasemonkey.Возможно, вы захотите настроить его в соответствии со своими потребностями.
//@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;
}
Другие советы
Зная только смещение от UTC, вы не сможете определить, в каком часовом поясе вы находитесь, из-за летнего времени.Вы могли бы подумать о том, чтобы посмотреть на время в определенный момент времени, чтобы попытаться угадать, действовало ли тогда летнее время или нет, но политические соображения делают это практически невозможным, поскольку разные юрисдикции меняют определение летнего времени.