Создание DateTime в определенном часовом поясе в C#

Я пытаюсь создать модульный тест, чтобы проверить случай, когда часовой пояс меняется на машине, потому что он был неправильно установлен, а затем исправлен.

В тесте мне нужно иметь возможность создавать объекты DateTime в часовом поясе, отличном от локального, чтобы люди, выполняющие тест, могли успешно выполнять это независимо от того, где они находятся.

Из того, что я вижу в конструкторе DateTime, я могу установить для TimeZone либо местный часовой пояс, либо часовой пояс UTC, либо не указанный.

Как мне создать DateTime с определенным часовым поясом, например PST?

Связанный вопрос - stackoverflow.com/questions/2532729/…

Oded 24.07.2010 00:27
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
180
1
210 027
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Для этого вам нужно будет создать собственный объект. Ваш настраиваемый объект будет содержать два значения:

Не уверен, существует ли уже предоставленный CLR тип данных, который имеет это, но, по крайней мере, компонент 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», чтобы было понятнее - я сам предпочитаю более короткие имена.

будет ли такая структура отображаться на интерфейс IQueryable на LinqToSql? coz каждый раз, когда я пытался использовать другой объект вместо DateTime или DateTime? на моем сопоставлении LinqToSql он терпит неудачу, когда я запрашиваю его .. Вы, наверное, знаете исключение: "..не удается преобразовать в SQL .."

Matt Kocaj 31.05.2009 14:39

Боюсь, я не знаю ни одной эквивалентной конструкции SQL Server. Я бы предложил указать имя часового пояса в одном столбце, а значение UTC в другом столбце. Получите их по отдельности, и тогда вы сможете довольно легко создавать экземпляры.

Jon Skeet 31.05.2009 15:39

Не уверен в ожидаемом использовании конструктора, который принимает DateTime и TimeZoneInfo, но, учитывая, что вы вызываете метод dateTime.ToUniversalTime (), я подозреваю, что вы предполагаете, что «возможно» он будет в местном времени. В этом случае, я думаю, вам действительно следует использовать переданный TimeZoneInfo, чтобы преобразовать его в UTC, поскольку они говорят вам, что он должен быть в этом часовом поясе.

IDisposable 16.09.2009 00:51

+1 - только что заметил ошибку в свойстве LocalTime - переменная должна быть «utcDateTime», а не «utcTime».

Ben Foster 27.05.2011 13:36

@JonSkeet спасибо за ответ. представлена ​​хорошая идея. небольшое примечание: вы устанавливаете частные поля как только чтение и даете им значение из .ctor, но типом является struct, а struct всегда имеют значение по умолчанию .ctor. С Уважением.

ravy amiry 31.01.2012 05:54

@Javad_Amiry: Да, это означает, что "значение по умолчанию" структуры, к сожалению, невозможно использовать. Вы потенциально можете сделать нулевой часовой пояс эквивалентом (скажем) UTC.

Jon Skeet 31.01.2012 10:19

Я создал библиотеку, которая использует аналогичный объект и помогает отображать штаты / страны в часовые пояса, конвертировать между ними и т. д. github.com/b9chris/TimeZoneInfoLib.Net - demo: timezoneinfolib.brass9.com

Chris Moschini 16.02.2012 22:12

@ChrisMoschini: Я бы на самом деле старался избегать использования сокращений, если это возможно. Они неоднозначны. Я также утверждаю, что имя «UtcTimeZone» на самом деле не то, что представляет ваш класс. Я ожидал, что это будет некий подкласс абстрактного типа часового пояса с некоторым описанием, представляющий зону UTC.

Jon Skeet 18.02.2012 00:49

Старый комментарий, но в конечном итоге я сохранил сокращения в своей библиотеке. Я считаю их очень полезными как в коде, так и в простом хранилище в базе данных (просто сохраните UTC и короткое имя часового пояса - DateTime и String, чтобы решить проблему @cottsak). Я считаю их очень удобочитаемыми, а не запутанными - но именно поэтому для многих задач существует более одной библиотеки - неудивительно, что авторы предпочитают свои собственные библиотеки.

Chris Moschini 14.05.2013 01:39

@ChrisMoschini: Как вы справляетесь с тем фактом, что сокращения не уникальны? На самом деле они не являются часовым поясом идентифицировать. Если ваш код используется только в США, это может быть нормально, но если вы когда-нибудь захотите расшириться в другом месте, я думаю, что будет разумно иметь уникальные идентификаторы.

Jon Skeet 14.05.2013 09:55

@JonSkeet Вы просто используете уникальные имена для каждого часового пояса - не сложно. Например, и в США, и в Австралии используется восточное стандартное время, поэтому вы используете EST для США и AUEST для Австралии. Вы по-прежнему можете отображать для пользователя стандартные, неуникальные сокращения, если хотите, чтобы в этом не было никакого вреда, и, как я уже сказал, это делает данные и код намного проще для чтения, чем какой-то сумасшедший числовой идентификатор или другой бессмысленный, но уникальный идентификатор. .

Chris Moschini 15.05.2013 04:02

@ChrisMoschini: В этот момент вы просто изобретаете свою собственную схему идентификации - схему, которую никто в мире не использует. Я буду придерживаться стандартной информации о зоне, спасибо. (Например, трудно понять, насколько бессмысленно «Европа / Лондон».)

Jon Skeet 15.05.2013 09:41

@JonSkeet Да, как я уже сказал, неудивительно, что авторы предпочитают собственные библиотеки. Мой подход позволяет легко хранить в базе данных и легко проверять быстро - я предпочитаю это, без сюрпризов.

Chris Moschini 15.05.2013 13:06

@ChrisMoschini: Безусловно, есть разница между «предпочитать собственную библиотеку» и «предпочитать общеотраслевой стандарт». Учитывая выбор между двумя библиотеками, в которых я участвовал не имел, я бы предпочел ту, которая использует стандартизированные идентификаторы. Это не случай NIH-синдрома.

Jon Skeet 15.05.2013 13:08

@JonSkeet На самом деле существует стандарт для этих сокращений: timeanddate.com/library/abbreviations/timezones (и мои извинения, Aus EST есть AEST, а не AUEST). Так что по вашим меркам разницы нет. Отличие заключается в том, что написанная мною библиотека лучше всего решает проблему, которую я искал, и, что неудивительно, я предпочитаю ее. Вы предпочитаете свое. Не думаю, что есть что еще сказать. У нас обоих могут быть свои библиотеки, кому бы они ни помогали, они помогают, мы не зарабатываем на них денег, поэтому нет особого смысла конкурировать. Я надеюсь, что люди сочтут их оба полезными.

Chris Moschini 18.05.2013 20:51

@ChrisMoschini: Да, есть сокращения, которые неоднозначны, поэтому не должны использоваться в качестве идентификаторов. (Например, CET.) Чтобы избежать двусмысленности, вы должны были отойти от стандарта. Существует значительная разница между тем, кто использует вашу библиотеку, и тем, кто использует Noda Time: любой, кто использует Noda Time, может взаимодействовать с любой другой системой, использующей TZDB. Их очень много. Сколько других систем используют ваш однозначный набор сокращений? (Есть и другие преимущества с точки зрения определения часового пояса, а не "половины" часового пояса (например, BST).)

Jon Skeet 18.05.2013 21:08

Возможно, вы смотрите слишком быстро - CET означает то же самое - это всегда UTC + 1. Никакой двусмысленности.

Chris Moschini 20.05.2013 01:02

@ChrisMoschini: Тогда другой пример: CST. Это UTC-5 или UTC-6? Как насчет IST - это Израиль, Индия или Ирландия в вашей базе данных? (И даже если вы знаете смещение прямо сейчас, разные страны, использующие одну и ту же аббревиатуру, могут меняться в разное время. Так что остается неясность, какой именно часовой пояс это означает. Часовой пояс! = Смещение.) Возвращаясь к вашему случаю: вы утверждаете, что что использование сокращений лучше всего решило вашу проблему. Чем было бы хуже использовать стандартные отраслевые идентификаторы часовых поясов?

Jon Skeet 20.05.2013 01:39

Я не пытаюсь кодировать регион, просто шаблон DST. И для проблемы, которую я пытаюсь решить, мы используем небольшое количество однозначных, приблизительных часовых поясов (если вы посмотрите на код, я заметил, что я даже не беспокоюсь о сложностях штата Индиана). Проще проверить и легче хранить. Это обсуждение продолжается слишком долго, поэтому я перестану отвечать здесь. Если вам не нравится моя библиотека, это нормально, но я не собираюсь заставлять ее работать так же, как ваша. Это решает проблему, которую я намеревался решить. Если решает чужое ... круто.

Chris Moschini 20.05.2013 11:09

@ChrisMoschini: Что ж, я продолжу рекомендовать использовать стандартные однозначные идентификаторы zoneinfo вместо неоднозначных сокращений. Это не вопрос, чья библиотека предпочтительнее - авторство библиотеки действительно не является проблемой. Если кто-то желает использовать другую библиотеку с выбором идентификатора хорошо, это нормально. Однако выбор идентификатора для часового пояса является важным, и я думаю, что очень важно, чтобы читатели знали, что сокращения являются неоднозначны, как я показал на примере IST.

Jon Skeet 20.05.2013 11:37

@JonSkeet Я установил часовой пояс как стандартное время Индии, и когда я пробую LocalTime.ToString (), вместо 13.12.2019 16:00:00 я получаю 13.12.2019 16:00:00 . Мне нужно установить это преобразование на основе часового пояса.

Gopi 10.12.2019 15:31

@Gopi: Вместо того, чтобы добавлять комментарий к сообщению, написанному более 10 лет назад, задайте новый вопрос с более подробной информацией, но имейте в виду, что формат и часовой пояс - это совершенно разные вещи.

Jon Skeet 10.12.2019 15:54

@JonSkeet Спасибо. Согласовано, Формат и Часовой пояс - это разные вещи, но я намерен отформатировать дату на основе часового пояса. Я создал отдельный вопрос. stackoverflow.com/questions/59279009/…

Gopi 11.12.2019 07:44

Структура 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));

Спасибо, это хороший способ добиться этого. После того, как вы получите объект DateTimeOffset в правильном часовом поясе, вы можете использовать свойство .UtcDateTime, чтобы получить время в формате UTC для созданного вами. Если вы храните свои даты в UTC, то конвертировать их в местное время для каждого пользователя не составит труда :)

Redth 21.04.2010 16:56

Я не думаю, что это правильно работает с переходом на летнее время, поскольку некоторые часовые пояса соблюдают его, а другие нет. Кроме того, «в тот день», когда летнее время начинается / заканчивается, части этого дня будут отключены.

crokusek 03.10.2015 00:36

Урок. Летнее время - это правило определенного часового пояса. DateTimeOffset не не связан не с каким часовым поясом. Не путайте значение смещения UTC, например -5, с часовым поясом. Это не часовой пояс, это смещение. Одно и то же смещение часто используется во многих часовых поясах, поэтому это неоднозначный способ обозначения часового пояса. Поскольку DateTimeOffset связан со смещением, а не с часовым поясом, он не может применять правила DST. Таким образом, 3:00 будет 3:00 в каждый день в году, без исключения в структуре DateTimeOffset (например, в ее свойствах Hours и TimeOfDay).

Triynko 19.02.2016 01:26

Вы можете запутаться, если посмотрите на свойство LocalDateTime DateTimeOffset. Это свойство НЕ является DateTimeOffset, это экземпляр DateTime с типом DateTimeKind.Local. Этот экземпляр связан с часовым поясом ... независимо от часового пояса локальной системы. Это свойство БУДЕТ отражать переход на летнее время.

Triynko 19.02.2016 01:28

Итак, настоящая проблема DateTimeOffset в том, что он не содержит достаточно информации. Он включает смещение, а не часовой пояс. Смещение неоднозначно для нескольких часовых поясов.

Triynko 19.02.2016 01:30

Если бы у него был определенный часовой пояс, связанный с ним, у него не только было бы смещение, но также были бы все правила, связанные с этим часовым поясом, включая время начала и окончания летнего времени (если он даже поддерживает его), величина смещения (обычно всего 1 час), независимо от того, начинается ли оно в фиксированную дату или гибкую дату, например, 1-е воскресенье марта, и даже является ли конкретный момент времени недействительным, неоднозначным или находится в пределах диапазона летнего времени. . Вам нужен TimeZoneInfo для всей информации. И теперь вы знаете, почему приведенная выше структура Джона Скита потрясающая.

Triynko 19.02.2016 01:30

Другие ответы здесь полезны, но они не охватывают конкретно, как получить доступ к Тихоокеанскому региону - вот вам:

public static DateTime GmtToPacific(DateTime dateTime)
{
    return TimeZoneInfo.ConvertTimeFromUtc(dateTime,
        TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time"));
}

Как ни странно, хотя «тихоокеанское стандартное время» обычно означает нечто иное, чем «тихоокеанское летнее время», в данном случае оно относится к тихоокеанскому времени в целом. Фактически, если вы используете FindSystemTimeZoneById для его получения, одно из доступных свойств - это логическое значение, указывающее, находится ли этот часовой пояс в настоящее время в летнем или нет.

Вы можете увидеть более общие примеры этого в библиотеке, которую я собрал вместе, чтобы иметь дело с DateTimes, которые мне нужны в разных часовых поясах, в зависимости от того, откуда пользователь запрашивает, и т. Д .:

https://github.com/b9chris/TimeZoneInfoLib.Net

Это не будет работать вне Windows (например, Mono в Linux), поскольку список времен взят из реестра Windows: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\

Под ним вы найдете ключи (значки папок в редакторе реестра); имена этих ключей - это то, что вы передаете FindSystemTimeZoneById. В Linux вам нужно использовать отдельный стандартный набор определений часовых поясов Linux, который я недостаточно изучил.

Кроме того, существует ConvertTimeBySystemTimeZoneId (), например: TimeZoneInfo.ConvertTimeBySystemTimeZoneId (DateTime.UtcNow, «Центральное стандартное время»)

Brent 10.08.2015 17:35

В окнах Список идентификаторов часовых поясов тоже можно увидеть этот ответ: stackoverflow.com/a/24460750/4573839

yu yang Jian 17.04.2020 12:09

Мне нравится ответ Джона Скита, но я хотел бы добавить одну вещь. Я не уверен, ожидал ли Джон, что ctor всегда будет передаваться в местном часовом поясе. Но я хочу использовать его в тех случаях, когда это что-то другое, чем местное.

Я читаю значения из базы данных и знаю, в каком часовом поясе находится эта база данных. Итак, в ctor я передам часовой пояс базы данных. Но тогда я бы хотел значение по местному времени. 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);
}

Я немного изменил Джон Скит ответ для Интернета с помощью метода расширения. Он также действует на лазурь, как амулет.

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);   
}
}

Использование класса Часовые пояса упрощает создание даты для конкретного часового пояса.

TimeZoneInfo.ConvertTime(DateTime.Now, TimeZoneInfo.FindSystemTimeZoneById(TimeZones.Paris.Id));

Извините, но он недоступен в Asp .NET Core 2.2 здесь, VS2017 предлагает мне установить пакет Outlook Nuget.

Machado 21.11.2019 00:47

пример => TimeZoneInfo.ConvertTime (DateTime.Now, TimeZoneInfo.FindSystemTimeZoneById ("Стандартное тихоокеанское время"))

AZ_ 16.03.2020 14:56

Другие вопросы по теме