Вопрос по datetime, timezone, c# – C #: Убедитесь, что DateTime.Now возвращает время по Гринвичу + 1

9

я используюDateTime.Now чтобы показать что-то в соответствии с сегодняшней датой, и когда вы работаете локально (Мальта, Европа), время отображается правильно (очевидно, из-за часового пояса), но, конечно, когда я загружаю его на свой хостинг-сервер (США),DateTime.Now не представляет правильный часовой пояс.

Поэтому в моем кодеhow can I convert DateTime.Now to correctly return the time from a GMT + 1 timezone ?

Ваш Ответ

3   ответа
14

что вы подразумеваете под «часовой пояс GMT + 1». Вы имеете в виду постоянно UTC + 1 или UTC + 1 или UTC + 2 в зависимости от летнего времени?

Если вы используете .NET 3.5, используйтеTimeZoneInfo чтобы получить соответствующий часовой пояс, затем используйте:

// Store this statically somewhere
TimeZoneInfo maltaTimeZone = TimeZoneInfo.FindSystemTimeZoneById("...");
DateTime utc = DateTime.UtcNow;
DateTime malta = TimeZoneInfo.ConvertTimeFromUtc(utc, maltaTimeZone );

Вам нужно будет определить системный идентификатор для часового пояса Мальты, но это легко сделать, запустив этот код локально:

Console.WriteLine(TimeZoneInfo.Local.Id);

Судя по вашим комментариям, этот бит будет неактуален, но только для других ...

Если выnot При использовании .NET 3.5 вам необходимо самостоятельно отработать переход на летнее время. Если честно, тоeasiest способ сделать это будет простой справочной таблицы. Отработайте изменения DST на следующие несколько лет, затем напишите простой метод, чтобы вернуть смещение в определенное время UTC с жестко закодированным списком. Вы могли бы просто хотеть отсортированныйList<DateTime> с известными изменениями, и чередуются от 1 до 2 часов, пока ваша дата не станет после последнего изменения:

// Be very careful when building this list, and make sure they're UTC times!
private static readonly IEnumerable<DateTime> DstChanges = ...;

static DateTime ConvertToLocalTime(DateTime utc)
{
    int hours = 1; // Or 2, depending on the first entry in your list
    foreach (DateTime dstChange in DstChanges)
    {
        if (utc < dstChange)
        {
            return DateTime.SpecifyKind(utc.AddHours(hours), DateTimeKind.Local);
        }
        hours = 3 - hours; // Alternate between 1 and 2
    }
    throw new ArgumentOutOfRangeException("I don't have enough DST data!");
}
Ваше решение выдает это исключение в методе ConvertTimeFromUtc: преобразование не может быть завершено, поскольку в указанном DateTime не было правильно установлено свойство Kind. Например, когда свойство Kind имеет тип DateTimeKind.Local, часовой пояс источника должен быть TimeZoneInfo.Local. Имя параметра: sourceTimeZone Andreas Grech
Вы уверены, что передаете его DateTime.UtcNow, а не DateTime.Now?
да, я использую ваш точный фрагмент кода (очевидно, измените идентификатор на "W. Europe Standard Time") Andreas Grech
Джон, я отредактировал твой ответ, чтобы инвертировать параметры TimeZoneInfo.ConvertTimeFromUtc Andreas Grech
Ой, спасибо. Странно то, что я действительно сначала их проверил, а потом все равно ошибся!
4

что вы можете установить в своем коде свойство, которое заставит DateTime.Now возвращать что-либо еще, кроме текущего времени компьютера, на котором выполняется код. Если вы хотите иметь возможность всегда получать другое время, вам, вероятно, нужно будет включить другую функцию. Вы можете совершить круговое путешествие по UTC и добавить желаемое смещение:

private static DateTime GetMyTime()
{
    return DateTime.UtcNow.AddHours(1);
}

(пример кода обновлен после комментария Люка о внутренней работе DateTime.Now)

DateTime.Now использованияUtcNow за кулисами, так что ваш оригинальный код переводится в нечто вродеDateTime.UtcNow.ToLocalTime().ToUniversalTime().AddHours(1).
С помощьюDateTime.UtcNow.AddHours(1) вместо этого вы сэкономите время при наборе текста!
(Кстати, я думаю, что первое магическое число используется вUtcNow это конвертировать изFILETIME - отмечен с 01.01.16 поDateTime - клещи с 01.01.0001. Второе магическое число - это маска, используемая внутри для обозначенияDateTimeKind.Utc.)
Да, я понял это. Но тогда я не уверен, что они делают то же самое; UtcNow извлекает системное время и выполняет некоторые операции с «магическими числами», в то время как ToUniversalTime использует TimeZone.CurrentTimeZone для получения времени Utc. Я полагаю, они всегда будут возвращаться в одно и то же время; о)
Это точно; не думал об этом. Спасибо за указание на это. Обновлю ответ. Я не боюсь печатать, но когда такой код неэффективен, это другой вопрос.
15

Для этого вы должны установить DateTimeKind в DateTimeKind.Utc.

DateTime MyTime = new DateTime(1990, 12, 02, 19, 31, 30, DateTimeKind.Utc);

DateTime MyTimeInWesternEurope = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(MyTime, "W. Europe Standard Time");

Только если вы используете .Net 3.5!

Похожие вопросы