Создание DateTime в определенном часовом поясе в c #
Я пытаюсь создать unit test, чтобы проверить случай, когда часовой пояс изменяется на машине, потому что он был неправильно установлен и затем исправлен.
В тесте мне нужно иметь возможность создавать объекты DateTime в не локальном часовом поясе, чтобы гарантировать, что люди, выполняющие тест, могут сделать это успешно независимо от того, где они находятся.
Из того, что я вижу из конструктора DateTime, я могу установить TimeZone как локальный часовой пояс, часовой пояс UTC или не указан.
Как создать DateTime с конкретным часовым поясом, например PST?
Ответы
Ответ 1
Джон ответ говорит о TimeZone, но я бы предложил вместо этого использовать TimeZoneInfo.
Лично мне нравится хранить вещи в UTC, где это возможно (по крайней мере, в прошлом; хранение UTC для будущего имеет потенциальные проблемы), поэтому я бы предложил такую структуру:
public struct DateTimeWithZone
{
private readonly DateTime utcDateTime;
private readonly TimeZoneInfo timeZone;
public DateTimeWithZone(DateTime dateTime, TimeZoneInfo timeZone)
{
var dateTimeUnspec = DateTime.SpecifyKind(dateTime, DateTimeKind.Unspecified);
utcDateTime = TimeZoneInfo.ConvertTimeToUtc(dateTimeUnspec, timeZone);
this.timeZone = timeZone;
}
public DateTime UniversalTime { get { return utcDateTime; } }
public TimeZoneInfo TimeZone { get { return timeZone; } }
public DateTime LocalTime
{
get
{
return TimeZoneInfo.ConvertTime(utcDateTime, timeZone);
}
}
}
Вы можете изменить имена "TimeZone" на "TimeZoneInfo", чтобы прояснить ситуацию - я предпочитаю более короткие имена самостоятельно.
Ответ 2
Структура DateTimeOffset была создана именно для этого типа использования.
См:
http://msdn.microsoft.com/en-us/library/system.datetimeoffset.aspx
Вот пример создания объекта DateTimeOffset с определенным часовым поясом:
DateTimeOffset do1 = new DateTimeOffset(2008, 8, 22, 1, 0, 0, new TimeSpan(-5, 0, 0));
Ответ 3
Другие ответы здесь полезны, но они не охватывают, как получить доступ к Тихоокеанскому региону, в частности:
public static DateTime GmtToPacific(DateTime dateTime)
{
return TimeZoneInfo.ConvertTimeFromUtc(dateTime,
TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time"));
}
Как ни странно, хотя "тихоокеанское стандартное время" обычно означает нечто отличное от "тихоокеанского летнего времени", в данном случае оно относится к тихоокеанскому времени в целом. Фактически, если вы используете FindSystemTimeZoneById
для его извлечения, одним из доступных свойств будет bool, сообщающий вам, находится ли данный часовой пояс в летнее время или нет.
Вы можете увидеть более обобщенные примеры этого в библиотеке, которую я бросил вместе, чтобы иметь дело с DateTimes, которые мне нужны в разных часовых поясах, в зависимости от того, откуда пользователь спрашивает, и т. Д.:
https://github.com/b9chris/TimeZoneInfoLib.Net
Это не будет работать за пределами Windows (например, Mono в Linux), поскольку список времени поступает из реестра Windows:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\
Под ним вы найдете ключи (значки папок в редакторе реестра); имена этих ключей - то, что вы передаете FindSystemTimeZoneById
. В Linux вы должны использовать отдельный набор стандартных часовых поясов для Linux, который я недостаточно изучил.
Ответ 4
Я изменил Jon Skeet answer для Интернета с расширением. Он также работает на лазури, как на шарм.
public static class DateTimeWithZone
{
private static readonly TimeZoneInfo timeZone;
static DateTimeWithZone()
{
//I added web.config <add key="CurrentTimeZoneId" value="Central Europe Standard Time" />
//You can add value directly into function.
timeZone = TimeZoneInfo.FindSystemTimeZoneById(ConfigurationManager.AppSettings["CurrentTimeZoneId"]);
}
public static DateTime LocalTime(this DateTime t)
{
return TimeZoneInfo.ConvertTime(t, timeZone);
}
}
Ответ 5
Вам нужно будет создать для него настраиваемый объект. Ваш пользовательский объект будет содержать два значения:
Не уверен, что уже есть тип данных, предоставляемых CLR, который имеет это, но по крайней мере компонент TimeZone уже доступен.
Ответ 6
Мне нравится Jon Skeet, но хотелось бы добавить одно. Я не уверен, что Джон ожидал, что ctor будет всегда передаваться в локальном часовом поясе. Но я хочу использовать его для случаев, когда это нечто иное, чем локальное.
Я читаю значения из базы данных, и я знаю, в какой временной зоне находится база данных. Поэтому в ctor я перейду в часовой пояс базы данных. Но тогда я хотел бы получить значение в местном времени. Jon LocalTime не возвращает исходную дату, преобразованную в локальную дату часового пояса. Он возвращает дату, преобразованную в исходный часовой пояс (независимо от того, что вы передали в ctor).
Я думаю, что эти имена свойств очищают его...
public DateTime TimeInOriginalZone { get { return TimeZoneInfo.ConvertTime(utcDateTime, timeZone); } }
public DateTime TimeInLocalZone { get { return TimeZoneInfo.ConvertTime(utcDateTime, TimeZoneInfo.Local); } }
public DateTime TimeInSpecificZone(TimeZoneInfo tz)
{
return TimeZoneInfo.ConvertTime(utcDateTime, tz);
}
Ответ 7
Использование класса TimeZones позволяет легко создавать дату для определенного часового пояса.
TimeZoneInfo.ConvertTime(DateTime.Now, TimeZoneInfo.FindSystemTimeZoneById(TimeZones.Paris.Id));