2016-08-29 2 views
5

Целью является создание функции, которая преобразует время из одного часового пояса в другое, используя Nodatime. Я не просто ищу отзыв о том, корректен ли результат, но обратная связь, специфичная для «как» я делаю это (действительно ли это правильно или есть тонкие дыры).Это правильный способ конвертировать между часовыми поясами в Nodatime?

Вот функция:

static ZonedDateTime ConvertDateTimeToDifferentTimeZone(DateTime p_from_datetime, string p_from_zone, string p_to_zone) 
{ 
    DateTimeZone from_zone = DateTimeZoneProviders.Tzdb[p_from_zone]; 
    LocalDateTime from_local = new LocalDateTime(p_from_datetime.Year, p_from_datetime.Month, p_from_datetime.Day, p_from_datetime.Hour, p_from_datetime.Minute); 
    ZonedDateTime from_datetime = from_zone.AtStrictly(from_local); 

    var from_instant = from_datetime.ToInstant(); 

    DateTimeZone to_zone = DateTimeZoneProviders.Tzdb[p_to_zone]; 
    ZonedDateTime to_datetime = to_zone.AtStrictly(from_local); 

    var to_offset_datetime = from_instant.WithOffset(to_datetime.Offset); 

    return to_zone.AtStrictly(to_offset_datetime.LocalDateTime); 
} 

Путь я бы назвал это выглядит следующим образом:

DateTime from_datetime = new DateTime(2016, 10, 15, 16, 30, 0); 
    string from_zone = "US/Central"; 
    string to_zone = "US/Eastern"; 
    var x = ConvertDateTimeToDifferentTimeZone(from_datetime, from_zone, to_zone); 

    Console.WriteLine(from_datetime.ToString() + " (" + from_zone + ") = " + " (" + x.ToString() + " (" + to_zone + ")"); 

Я пропускаю что-нибудь или делать что-нибудь неправильно?

ответ

4

Я бы придерживаться типов Нода времени, насколько это возможно (и конвенций .NET именования). Преобразование между зонами должно быть выполнено с помощью ZonedDateTime.WithZone, что означает, что вы действительно спрашиваете о конвертации в ZonedDateTime. Если вы действительно, действительно должны использовать DateTime вместо типов Нода времени, вы, вероятно, хотите что-то вроде:

public static DateTime ConvertDateTimeToDifferentTimeZone(
    DateTime fromDateTime, 
    string fromZoneId, 
    string tozoneId) 
{ 
    LocalDateTime fromLocal = LocalDateTime.FromDateTime(fromDateTime); 
    DateTimeZone fromZone = DateTimeZoneProviders.Tzdb[fromZoneId]; 
    ZonedDateTime fromZoned = fromLocal.InZoneLeniently(fromZone); 

    DateTimeZone toZone = DateTimeZoneProviders.Tzdb[toZoneId]; 
    ZonedDateTime toZoned = fromZoned.WithZone(toZone); 
    LocalDateTime toLocal = toZoned.LocalDateTime; 
    return toLocal.ToDateTimeUnspecified(); 
} 

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

Трудно понять, как будет выглядеть метод, если бы вы использовали Noda Time повсюду, так как мы не знаем, начинаете ли вы с LocalDateTime или ZonedDateTime. Например, вы могли бы:

public static LocalDateTime ConvertDateTimeToDifferentTimeZone(
    LocalDateTime fromLocal, 
    string fromZoneId, 
    string tozoneId) 
{ 
    DateTimeZone fromZone = DateTimeZoneProviders.Tzdb[fromZoneId]; 
    ZonedDateTime fromZoned = fromLocal.InZoneLeniently(fromZone); 

    DateTimeZone toZone = DateTimeZoneProviders.Tzdb[toZoneId]; 
    ZonedDateTime toZoned = fromZoned.WithZone(fromZone); 
    return toZoned.LocalDateTime; 
} 
+0

Спасибо за ваши комментарии и инструкцию Jon. Основой этого является приложение для календаря. Конкретная цель заключается в том, чтобы владелец события мог ввести дату и время вместе с часовым поясом для конкретного события календаря. В идеале это будет единственная информация, которая будет сохранена, хотя у меня нет проблемы с сохранением смещения, если это упростит ситуацию. С другой стороны, получатель/потребитель-получатель событий сможет видеть точную дату и время в выбранном им часовом поясе (возможно, извлеченные из настроек браузера или их желаемого часового пояса). – CINCHAPPS

+0

@TomWesson: Нужно выработать то, что вы хотите сделать, если они предоставляют дату/время, которое не существует или происходит дважды из-за изменений DST. Возможно, 'InZoneLeniently' делает то, что вы хотите, но вы shoudl принимаете это решение явно. (Хранение смещения также позволит вам рассогласовать.) –

+0

Вы быстро Джон, я сделал изменение к моему комментарию выше. – CINCHAPPS

1

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

static ZonedDateTime ConvertDateTimeToDifferentTimeZone(DateTime p_from_datetime, string p_from_zone, string p_to_zone) 
{ 
    DateTimeZone from_zone = DateTimeZoneProviders.Tzdb[p_from_zone]; 
    var from_local = LocalDateTime.FromDateTime(p_from_datetime); 
    ZonedDateTime from_datetime = from_zone.AtStrictly(from_local); 

    DateTimeZone to_zone = DateTimeZoneProviders.Tzdb[p_to_zone]; 
    return from_datetime.WithZone(to_zone); 
} 
+2

Не нужно проходить через «Мгновенный». Просто назовите 'WithZone'. –

+0

@MattJohnson Спасибо, исправлено это – fsacer