2013-05-06 3 views
2

У меня есть следующая информация:Timezone от GMT к местным

string shippedTime = "10:53 AM"; 
string shippedDate = "12/12/2012"; 
string shippedTimeZone = "(GMT-05:00) Eastern Time (US & Canada)"; 

string receivedTime = "10:45 AM"; 
string receievedDate = "12/13/2012"; 

Мне нужно найти разницу между отгруженным временем и временем приема (в местном часовом поясе) в часах, принимая часовые пояса и экономии дневного света в Счет. Это данные, которые я вытащил из внешней системы слежения, и это именно то, что я получаю. Таким образом, формат shippedTimeZone является неизвестным - я не знаю, сколько часовых поясов в этой системе и что такое точный строковый формат, или, вернее, я не могу гарантировать, что формат всегда будет таким же, делая разбор типа хрупкий.

Помимо разбора всех этих строк, чтобы вытащить коррекцию и время конкатенации GMT, существуют ли дополнительные библиотеки, которые я должен изучить? Или более простой способ получить то, что мне нужно?

+0

вы пробовали 'DateTime.Parse + некоторая строка tricks' или [NodaTime] (https://code.google.com/p/noda -time /), прежде чем задавать этот вопрос? – I4V

+3

Возможно, вы захотите взглянуть на [Noda Time] (http://code.google.com/p/noda-time/) ([и его блог] (http://noda-time.blogspot.com/))) для конверсий и правильного дневного света. Я не думаю, что Noda Time проанализирует хрупкую строку Time Zone. – Jesse

+0

+1 для просмотра Noda Time. Конверсии часовых поясов могут выглядеть обманчиво простыми ... пока вы не начнете смотреть на крайние случаи. –

ответ

2

Это похоже на часовой пояс Windows, как и у вас с TimeZoneInfo, но сервис дал вам свойство DisplayName, а не Id. Это делает его немного громоздким. Тем более, что отображаемые имена локализованы - у вас есть английское имя. Это будет выглядеть по-другому на компьютере с разными настройками культуры.

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

Основываясь на том, что он говорит «GMT», а не «UTC», я бы предположил, что они были получены от более старого компьютера, такого как Windows XP, Windows Server 2003 или, возможно, Windows Embedded. Например, вы найдете его на this list.

Вы действительно должны вернуться к владельцам этой службы и попросить их дать вам значение TimeZoneInfo.Id, а не TimeZoneInfo.DisplayName. Предполагая, что вы не можете сделать это, вот один из способов вы можете идти о получении этого работать с тем, что у вас есть:

// Look up the time zone. This won't work on non-English language computers! 
// (setting an English CultureInfo won't help you here) 
var shippedTZ = TimeZoneInfo.GetSystemTimeZones() 
    .FirstOrDefault(x => x.DisplayName == shippedTimeZone.Replace("GMT", "UTC")); 
if (shippedTZ == null) 
    throw new Exception("Time Zone Not Found!"); 

// You may want to handle the exception by hardcoding some specific time zones 

// Let's turn your date/time strings into an actual DateTime 
var shippedDT = DateTime.ParseExact(shippedDate + " " + shippedTime, 
          "MM/dd/yyyy hh:mm tt", CultureInfo.InvariantCulture); 

// Then we'll use the time zone to get a DateTimeOffset. 
var shippedDTO = new DateTimeOffset(shippedDT, 
            shippedTZ.GetUtcOffset(shippedDT)); 

// And the same thing for the received date... 
var receivedTZ = TimeZoneInfo.Local; 
var receivedDT = DateTime.ParseExact(receievedDate + " " + receivedTime, 
          "MM/dd/yyyy hh:mm tt", CultureInfo.InvariantCulture); 
var receivedDTO = new DateTimeOffset(receivedDT, 
            receivedTZ.GetUtcOffset(receivedDT)); 

// Now you can subtract them 
TimeSpan elapsed = receivedDTO - shippedDTO; 

Другая вещь, которую вы должны знать, отсюда - если ни один из даты/времени значения неоднозначны, вы не можете получить правильный результат. Это произойдет во время перехода «спада», связанного с летним временем сбережения. Вы ничего не можете с этим поделать, потому что у вас нет какой-либо квалифицирующей информации в исходных данных.

NodaTime - в то время как выдающийся библиотека, не может сделать намного лучше, чем это для вашей конкретной проблемы. У вас все еще будут проблемы с разрешением часового пояса без правильного идентификатора и отображения неоднозначного локального дат-времени. Но только для хорошей мерой, здесь то же самое, используя NodaTime:

// Try to locate the time zone 
var bclZoneProvider = DateTimeZoneProviders.Bcl; 
var zoneShipped = bclZoneProvider.Ids 
    .Select(x => bclZoneProvider[x]) 
    .Cast<BclDateTimeZone>() 
    .FirstOrDefault(x => x.DisplayName == shippedTimeZone.Replace("GMT", "UTC")); 
if (zoneShipped == null) 
    throw new Exception("Time Zone Not Found!"); 

// You wanted the system time zone 
var zoneReceived = bclZoneProvider.GetSystemDefault(); 

// Parse the date/time values as a LocalDateTime 
var pattern = LocalDateTimePattern 
        .CreateWithInvariantCulture("MM/dd/yyyy hh:mm tt"); 
var ldtShipped = pattern.Parse(shippedDate + " " + shippedTime).Value; 
var ldtReceived = pattern.Parse(receievedDate + " " + receivedTime).Value; 

// Assign them to the zones. 
// "Leniently" means to use the standard offset when there is an ambiguity. 
var zdtShipped = ldtShipped.InZoneLeniently(zoneShipped); 
var zdtReceived = ldtReceived.InZoneLeniently(zoneReceived); 

// Subtract them to get the Duration you are looking for. 
Duration elapsed = zdtReceived.ToInstant() - zdtShipped.ToInstant(); 
+0

Это отличный ответ, спасибо Мэтту! Когда я прочитал первый пример (без ноды), мне пришлось смеяться, потому что это очень близко к тому, что я закончил. Я заметил, что замена GMT с помощью UTC позволила мне захватить сначала или по умолчанию из системных часовых поясов. Оттуда это было связано с получением смещения. Я сделал это еще на один шаг, а также посмотрел, не было ли какое-либо время в дневном свете, и если так было добавлено час. – Nicros

+1

DST уже учитывается вызовом GetUtcOffset. Не добавляйте лишний час. –

+0

А, хорошо знать! Я удалю +1 час. Благодаря! – Nicros

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

  • Нет связанных вопросов^_^