Как работать с часовыми поясами в ASP.NET ?
Вопрос
Я работаю над проектом "система онлайн-напоминаний" (ASP.NET 2.0 (C #) / SQL Server 2005)
Поскольку это сервис напоминаний, который будет отправлять почту пользователям в определенные даты.Но проблема в том, что пользователи не из какой-то конкретной страны, они со всего мира и из разных часовых поясов.Теперь, когда я регистрируюсь, я запрашиваю часовой пояс пользователей точно так же, как Windows запрашивает наш часовой пояс во время установки.
Но я не получаю, если пользователь выбрал (+5.30) или что-то часовому поясу, тогда как обрабатывать эту зону раз в моем приложении ASP.NET .Как работать в зависимости от часового пояса.
И, пожалуйста, подскажите, есть ли какой - нибудь лучший способ обработки часовых поясов в этом приложении??
Спасибо
Решение
Первое, что нужно сделать, это убедиться, в каком часовом поясе находятся ваши данные.Я бы рекомендовал убедиться, что любая дата-время, которую вы сохраняете, хранится по времени UTC (используйте DateTime.ToUniversalTime()
чтобы заполучить его).
Когда вы хотите сохранить напоминание для пользователя, вам понадобится текущее время UTC, добавьте или удалите разницу в часовых поясах пользователя и преобразуйте это новое время обратно в UTC;это то, что вы хотите сохранить в базе данных.
Затем, когда вы захотите проверить, нужно ли отправлять напоминания, вам просто нужно поискать в базе данных напоминания, которые нужно отправить сейчас, в соответствии со временем UTC;по сути, получите все напоминания, у которых есть временная метка, то есть до DateTime.Now.ToUniversalTime()
.
Обновить с некоторыми особенностями реализации:Вы можете получить список часовых поясов из TimeZoneInfo.GetSystemTimeZones()
способ;вы можете использовать их для отображения списка часовых поясов для пользователя.Если вы храните Id
используя свойство из выбранного часового пояса, вы можете создать из него экземпляр класса TimeZoneInfo и вычислить время UTC для заданного значения локальной даты / времени:
TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById("<the time zone id>");
// May 7, 08:04:00
DateTime userDateTime = new DateTime(2009, 5, 7, 8, 4, 0);
DateTime utcDateTime = userDateTime.Subtract(tzi.BaseUtcOffset);
Другие советы
Я бы рекомендовал всегда используйте время UTC (GMT) на стороне сервера (в коде, базе данных и т.д.) И преобразует время из UTC в местное время для отображения Только.Это означает, что все временные манипуляции - включая экономию времени в базе данных, выполнение вычислений и т.д. - должны выполняться с использованием UTC.
Проблема в том, что:как ваш программный код узнает, каков часовой пояс клиентского браузера?Допустим, пользователь вводит некоторое значение даты / времени (например, 12/30/2009 14:30) в форме и отправляет ее на сервер.Предполагая, что пользователь указал местное время, откуда сервер знает, как преобразовать это значение в UTC?
Приложение может попросить пользователя указать часовой пояс (и сохранить его в постоянном файле cookie или базе данных), но это требует дополнительных усилий от пользователя, и вашему приложению потребуется реализовать логику и экраны для этого.Было бы лучше, если бы приложение могло автоматическое определение часового пояса клиента.
Я решил эту проблему с помощью JavaScript getTimezoneOffset Получение времени функция, которая является единственным API, который может сообщать серверу о разнице во времени между местным временем на клиенте и GMT.Поскольку это клиентский API, я сделал следующее:на стороне сервера проверьте, есть ли пользовательский файл cookie сеанса, содержащий значение временного смещения, и, если он недоступен, перезагрузите страницу (только во время вызовов GET, а не POST) с добавлением некоторой логики JavaScript для генерации временного смещения и сохранения его в файле cookie.Со стороны клиента это почти прозрачно (один раз во время сеанса я перезагружаю страницу в GET).Как только у меня есть смещение в файле cookie, я применяю его к функциям управления временем в зависимости от направления преобразования времени (UTC в местное время или местное время в UTC).
Это может показаться немного сложным, и так оно и есть, но после того, как я написал вспомогательные функции, интеграция этой функции на сайт стала вопросом создания одиночный вызов в Page_Load (страниц, которым требовалось преобразование по времени) и использование процедур преобразования по времени при отправке и извлечении значений времени в браузер и из браузера.Вот пример того, как это можно использовать:
using My.Utilities.Web;
...
// Derive the form class from BaseForm instead of Page.
public class WebForm1: BaseForm
{
...
private void Page_Load(object sender, System.EventArgs e)
{
// If we only want to load the page to generate the time
// zone offset cookie, we do not need to do anything else.
if (InitializeLocalTime())
return;
// Assume that txtStartDate is a TextBox control.
if (!IsPostback)
{
// To display a date-time value, convert it from GMT (UTC)
// to local time.
DateTime startDate = GetStartDateFromDB(...);
txtStartDate.Text = FormatLocalDate(startDate);
...
}
else
{
// To save a date-time value, convert it from local
// time to GMT (UTC).
DateTime tempDate = DateTime.Parse(txtStartDate.Text);
DateTime startDate = ConvertLocalTimeToUtc(tempDate);
SaveStartDateInDB(startDate, ...);
...
}
}
...
}
Если вам нужна более подробная информация, ознакомьтесь с Самое время:Локализация времени в ASP.NET Приложениях статья (извините, но у меня нет прямой ссылки на статью на сайте издателя, поскольку asp.NetPro ограничивает доступ только для платных подписчиков;однако там есть ссылки на копии в формате PDF).Я хотел бы опубликовать образец из статьи, но я не хочу нарушать авторские права;однако, вот проект по созданию вспомогательной библиотеки это имеет весь необходимый функционал и документация (просто игнорируйте то, что вам не нужно).
Обновить:Статья была размещена в Интернете вместе с образцом проекта новым издателем здесь.
Проблема со всеми ответами на данный момент заключается в том, что они не учитывают того, чего пытается достичь Прашант.Если пользователь его системы за день до перехода на летнее время имеет смещение + 12 и устанавливает напоминание на следующий день, его смещение, когда напоминание должно сработать, вместо этого будет + 13.
Вот почему вы можете использовать текущее смещение только для того, что происходит сейчас.Хотя я согласен со всеми остальными, что все значения времени на стороне сервера (за исключением, возможно, тех, которые используются только для отображения) должны храниться в UTC.
Возможно, вы захотите рассмотреть возможность использования DateTimeOffset Дата - время смещения структура вместо даты и времени, если вы используете framework 2.0 или более позднюю версию.
DateTimeOffset представляет собой момент времени относительно времени UTC, поэтому в этом случае с ним должно быть проще работать.
Есть 2 шага:
Обнаружение другого часового пояса на стороне клиента с помощью Javascript:
var dt = new Date(); var diffInMinutes = -dt.getTimezoneOffset();
Затем на стороне сервера используйте C # код для преобразования серверного времени в клиентское на основе обнаруженного выше смещения часового пояса:
------------------------;
string queryStr = Request.QueryString["diffInMinutes"];
int diffInMinutes = 0;
if (Int32.TryParse(queryStr, out diffInMinutes))
{
clientTime = serverTime.ToUniversalTime().AddMinutes(diffInMinutes);
}
По сути, все, что вам нужно сделать, это добавить смещение (часы + минуты) к местному времени, введенному пользователем.Добавление смещения в основном дает вам дату и время в часовом поясе UTC (в основном GMT).
Обычно проще всего стандартизировать все ваше время в соответствии с UTC, чтобы логике вашего приложения не приходилось иметь дело со смещениями.
На этой странице есть несколько хороших примеров: http://msdn.microsoft.com/en-us/library/bb546099.aspx
Проблема в том, что смещение от UTC будет разным в разное время года - в каждом часовом поясе свои правила.(Я научился этому на собственном горьком опыте, когда разрабатывал приложение для планирования конференц-зала.)
Похоже, здесь есть встроенная поддержка: http://msdn.microsoft.com/en-us/library/system.timezoneinfo.converttime.aspx
Сам не пробовал, но, похоже, он обещает правильное преобразование с учетом перехода на летнее время.
Если нет, то вот (дорогой) коммерческий инструмент, который я использовал: http://www.worldtimeserver.com/time_zone_guide/