Как работать с часовыми поясами в ASP.NET?

Я работаю над проектом "система онлайн-напоминаний" (ASP.NET 2.0 (C#) / SQL Server 2005)

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

но я не получение если пользователь выбрал (+5.30) или что-то часовой пояс, то как обрабатывать этот часовой пояс в моем asp.net применение. Как работать в соответствии с часовым поясом.

и, пожалуйста, предложите, есть ли лучший способ обработки часовых поясов в этом приложении ??

спасибо

7 ответов


Первое, что нужно сделать, чтобы убедиться,в каком часовом поясе ваши данные. Я бы рекомендовал убедиться, что любое время DateTime, которое вы храните, хранится во времени 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-копии, хотя). Я хотел бы опубликовать образец из статьи, но я не хочу нарушать авторские права; однако, вот проект по созданию вспомогательной библиотеки и вся необходимая функциональность и документация (просто игнорировать вещи, которые вам не нужны).

UPDATE: статья была опубликована в интернете с образцом проекта новым издателем здесь.


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

вот почему вы можете использовать только текущее смещение за то, что происходит сейчас. Хотя я согласен со всеми остальными, что все время серверная часть (за исключением, возможно, тех, которые используются только для отображения) должна храниться в формате UTC.


вы можете посмотреть на использование DateTimeOffset структура вместо DateTime, если вы находитесь на 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);
}

в основном, все, что вам нужно сделать, это добавить смещение (часы + минуты) по местному времени, что пользователь ввел. Добавление смещения в основном дает вам DateTime в часовом поясе 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/