2016-12-14 4 views
2

У меня проблема с печально известным летним временем.Летнее время и DateTime.AddHour()

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

DateTime timeIterator = new DateTime(year, 1, 1, 0, 0, 0); 

итерации его с

timeIterator = timeIterator.AddHours(1); 

и проверить на каждую итерацию, если момент времени присутствует в списке.

Проблема возникает, когда дело доходит до летнего времени. Im мой пример 2014 года, часы перемещаются на 30. марша с 0200 до 0300. Итак, после 0159 приходит 0300. Но DateTime.AddHours() полностью игнорирует переход на летнее время. Если TimeIterator находится в {30.03.2014 01:00:00}, и я вызываю AddHours (1), я получаю {30.03.2014 02:00:00}, которого явно не существует.

Если я сейчас тестирую список против этого datapoint, он (естественно) не входит в список, и я ошибаюсь в ошибке «отсутствует ошибка передачи данных».

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

Спасибо заранее,
Frank

+0

Ну, это действительно зависит, в какой стране вы говорите. –

+0

Ваш вопрос, связанный с [this] (http://stackoverflow.com/questions/5811267/net-accounting-for-daylight-savings), отвечает за TimezoneInfo. –

+0

Также читайте [здесь] (http://codeofmatt.com/2015/03/06/common-daylight-saving-time-mistakes-for-net-developers/), ищите * Подтвердите свои данные! *. –

ответ

2

Как я могу проверить, если мой DateTime является действительным момент времени?

Не проверяйте, убедитесь в этом. Вы можете рассчитывать часы в UTC и, например, переводить каждую точку в местное время.

DateTimeOffset timeIterator = new DateTimeOffset(new DateTime(year, 1, 1, 0, 0, 0, DateTimeKind.Local)); 
timeIterator = timeIterator.AddHours(1); 
timeIterator.LocalDateTime; 

// assuming you have a TimeZoneInfo object, you can also get different local times: 
TimeZoneInfo tzi = /* the timezone */; 
TimeZoneInfo.ConvertTimeFromUtc(timeIterator.UtcDateTime, tzi); 

Однако, как отметил Damien_The_Unbeliever, это решает только одну часть проблемы, программа больше не будет проверять наличие требуемого недопустимой даты. Другая проблема возникает, когда ваши данные хранятся с местным временем. Это означает, что переход от DST к обычному времени будет иметь два последовательных часа с одним и тем же локальным представлением DateTime. Чтобы избежать этой ситуации, данные должны храниться с полной информацией (UTC или явным смещением), чтобы было возможно последующее сравнение.

Edit:

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

TimeZoneInfo tzi = /* the timezone */; 
DateTime timeIterator = /* the time */; 
if (tzi.IsAmbiguousTime(timeIterator)) 
{ 
    /* Expect multiple data entries */ 
} 
if (tzi.IsInvalidTime(timeIterator)) 
{ 
    /* Expect no data entries */ 
} 
+0

Проблема в том, что если они продолжают хранить даты как локальные, они не найдут, если у них отсутствует информация на другой точке перехода в году. Например. если данные были сохранены как 0100 UTC, 0200 UTC и 0400 UTC, но в 03:00 UTC часы были установлены назад, они будут иметь данные в локальные моменты 0100, 0200 и 0300, но на самом деле у них отсутствуют данные, которые должны были быть созданы на 0300 UTC, который также отображается в местное время 0200, они все равно не найдут его здесь. –

+0

@Damien_The_Unbeliever Настоящая история. Если автор вопроса не проверяет внешние данные (нет влияния), то определенно время для улучшения хранилища datetime. Однако, если задача заключается в проверке существующих исторических данных, тогда урон будет выполнен, и двойное время больше не может быть разделено сравнением значений. Думаю, я должен отредактировать свой вопрос, чтобы прояснить некоторые вещи. – grek40

+0

Эй, ребята, я проверяю внешние данные - и моя проблема в том, что я в конце концов (переход на летнее время) проверю на недействительную дату. Дело в том, что я должен знать часовой пояс, чтобы избежать этого, потому что иначе я не могу знать, что это действительная дата или нет. Угадайте, я переключусь на NodaTime, чтобы справиться с этим с более сознательным ... – Aaginor

0

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

Тогда преобразование его (возможно использовать метод РАСШИРЕНИЯ)

private DateTime TransformToTimezone(DateTime datetime) 
{ 
      TimeZoneInfo beZone = TimeZoneInfo.FindSystemTimeZoneById("Romance Standard Time"); 

      //Convert to timezone 
      return TimeZoneInfo.ConvertTimeFromUtc(datetime, beZone); 
} 
+0

Да, или сохраните часовой пояс с моими данными (что я, вероятно, сделаю). ... и используя NodaTime, чтобы сделать это более понятным и прозрачным. – Aaginor

Смежные вопросы