Как работать с часовыми поясами в ASP.NET? - PullRequest
27 голосов
/ 07 мая 2009

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

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

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

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

Спасибо

Ответы [ 7 ]

27 голосов
/ 07 мая 2009

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

Я бы порекомендовал всегда использовать время UTC (GMT) на стороне сервера (в коде позади, базе данных и т. Д.) И конвертировать время из UTC в местное время для отображения * Только 1004 *. Это означает, что все манипуляции с временем, включая экономию времени в базе данных, выполнение расчетов и т. Д., Должны выполняться с использованием 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). Я хотел бы опубликовать образец из статьи, но я не хочу нарушать авторские права; тем не менее, вот проект по созданию вспомогательной библиотеки , которая имеет всю необходимую функциональность и документацию (просто игнорируйте то, что вам не нужно).

ОБНОВЛЕНИЕ: статья была размещена в сети с примером проекта новым издателем здесь .

3 голосов
/ 12 мая 2009

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

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

2 голосов
/ 07 мая 2009

Возможно, вы захотите использовать DateTimeOffset вместо DateTime, если вы используете Framework 2.0 или более позднюю версию.

DateTimeOffset представляет момент времени относительно времени UTC, поэтому в этом случае с ним должно быть проще работать.

1 голос
/ 14 апреля 2015

Есть 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);
}
0 голосов
/ 12 мая 2009

Проблема в том, что смещение от UTC будет меняться в разное время года - у каждого часового пояса есть свои правила. (Я научился этому нелегко, когда разрабатывал приложение для планирования конференц-зала.)

Похоже, здесь есть встроенная поддержка: http://msdn.microsoft.com/en-us/library/system.timezoneinfo.converttime.aspx

Сам не пробовал, но, похоже, обещает правильное преобразование с учетом перехода на летнее время.

Если нет, вот (дорогой) коммерческий инструмент, который я использовал: http://www.worldtimeserver.com/time_zone_guide/

0 голосов
/ 07 мая 2009

По сути, все, что вам нужно сделать, это добавить смещение (часы + минуты) к местному времени, которое ввел пользователь. Добавление смещения в основном дает вам DateTime в часовом поясе UTC (в основном, по Гринвичу).

Обычно проще всего стандартизировать все время по UTC, чтобы логике приложения не приходилось иметь дело со смещениями.

На этой странице есть несколько хороших примеров: http://msdn.microsoft.com/en-us/library/bb546099.aspx

...