objective-c: Преобразование между часовыми поясами

У меня проблемы с преобразованием строки времени в другой часовой пояс.

Это пример строки, которую я получил с сервера: @ "14.05.2013, 4:19"

Я знаю, что часовой пояс - Америка / Нью-Йорк, и я хочу преобразовать его в мой местный часовой пояс: Европа / Рим.

Вот код, который я написал для его проверки:

-(void) convertTimeZone
{   

    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    dateFormatter.timeZone=[NSTimeZone timeZoneWithAbbreviation:@"GMT"];
    dateFormatter.dateFormat=@"MM/dd/yyyy HH:mma";
    NSString *sourceDateString = @"5/14/2013 4:19am";

    NSTimeZone *sourceTimeZone = [[NSTimeZone alloc] initWithName:@"America/New_York"];
    NSTimeZone *destinationTimeZone = [NSTimeZone localTimeZone];
    NSInteger sourceGMToffset = sourceTimeZone.secondsFromGMT;
    NSInteger destinationGMToffset = destinationTimeZone.secondsFromGMT;
    NSInteger interval = destinationGMToffset-sourceGMToffset;


    NSLog(@"DateFormatter TimeZone: %@", dateFormatter.timeZone);
    NSLog(@"Source TimeZone: %@", sourceTimeZone);
    NSLog(@"Destination TimeZone: %@", destinationTimeZone);
    NSLog(@"sourceOffset: %u destinationOffset: %u interval: %u", sourceGMToffset, destinationGMToffset, interval);

    NSLog(@"----------------------------------------------------------------------------------------------------");

    NSLog(@"sourceDateString : %@", sourceDateString);

    //Convert from string to date

    NSDate *dateObject = [dateFormatter dateFromString:sourceDateString];
    NSLog(@"From string to date: %@", dateObject);

    //Now back from date to string
    NSLog(@"From date to string: %@", [dateFormatter stringFromDate:dateObject]);

    //Convert from sourceTimeZone to destinationTimeZone
    NSDate *newDate = [[NSDate alloc] initWithTimeInterval: interval sinceDate:dateObject];     
    NSLog(@"destinationDateString: %@", [dateFormatter stringFromDate: newDate]);

}

вывод:


DateFormatter TimeZone: GMT (GMT) смещение 0

Источник TimeZone: America / New_York (GMT-04: 00), смещение -14400 (дневной свет)

Часовой пояс места назначения: местный часовой пояс (Европа / Рим (CEST), смещение 7200 (дневной свет))

sourceOffset: 4294952896 destinationOffset: 7200 интервал: 21600

sourceDateString: 14.05.2013, 4:19

От строки до даты: 2013-05-14 00:19:00 +0000

От даты до строки: 14.05.2013 00:19

destinationDateString: 14.05.2013 06:19


Я злюсь !!!!

Если исходная дата - «14.05.2013, 4:19», ПОЧЕМУ средство форматирования даты меняет ее на «14.05.2013 00:19» ????????? Если бы он правильно сохранил его до «14.05.2013 04:19 AM +0000», преобразование было бы идеальным (6 часов между двумя часовыми поясами) !!!

Намек?

Спасибо

Никола


ИЗМЕНИТЬ

Установив эти параметры в соответствии с рекомендациями lithu-t-v:

dateFormatter.timeZone=[NSTimeZone timeZoneWithAbbreviation:@"GMT"];

NSString *sourceDateString = @"5/14/2013 4:19am -0400";

Кажется, работает, но это не так.

Я говорю «кажется», потому что:

sourceDateString: 14.05.2013, 04:19 -0400

От строки до даты: 2013-05-13 04:19:00 +0000 (ОК)

От даты до строки: 14.05.2013, 04:19 (ОК)

destinationDateString: 14.05.2013, 10:19 (ПРАВИЛЬНО)

правильно, НО, если я попробую в поздний час:

sourceDateString: 14.05.2013 22:19 -0400

От строки до даты: 2013-05-14 16:19:00 +0000 (НЕПРАВИЛЬНО)

От даты до строки: 14.05.2013 16:19

destinationDateString: 14.05.2013 22:19 (НЕПРАВИЛЬНО!)

Правильный результат должен быть: 15.05.2013, 04:19.


person nico9T    schedule 14.05.2013    source источник
comment
Попробуйте это: agilewarrior. wordpress.com/2012/06/27/   -  person trojanfoe    schedule 14.05.2013
comment
Спасибо, но похоже, что проблема в преобразовании STRING в DATE.   -  person nico9T    schedule 14.05.2013
comment
он преобразует его в дневное время +0000, а затем вычисляет время в соответствии с часовым поясом.   -  person Dipen Panchasara    schedule 14.05.2013
comment
Проблема в преобразовании строки в дату. См. Мой ответ ниже, но есть две проблемы: 1. вы используете неправильный указатель часа, 2 вы используете неправильный часовой пояс, вы должны использовать время Нью-Йорка для выполнения первого преобразования.   -  person JeremyP    schedule 15.05.2013
comment
Спасибо! идеальный ответ   -  person nico9T    schedule 15.05.2013


Ответы (3)


Компонент +0000 определяет дату с часовым поясом и предоставляет фактическое время. Объект NSDate также включает эту часть. Поскольку эта часть отсутствует, возникает разница во времени относительно местного часового пояса

Здесь вы установили часовой пояс, но не настроили дату по дате. Установите часовой пояс в формат даты и попробуйте

Добавьте к строке +0000 и сделайте оставшееся - это сработает.

person Lithu T.V    schedule 14.05.2013
comment
Если я изменю свои dateFormatter.dateFormat и sourceDateString следующим образом: dateFormatter.dateFormat=@MM/dd/yyyy HH: mma Z; NSString * sourceDateString = @ 14.05.2013 4:19 +0000; Я по-прежнему получаю тот же результат: 14.05.2013 4:19 +0000 От строки до даты: 2013-05-14 00:19:00 +0000 Я не думаю, что это проблема. - person nico9T; 14.05.2013
comment
@NicolaP. : самый простой способ - добавить +0000 к вашей строке и выполнить оставшиеся - person Lithu T.V; 14.05.2013

Вот чего вы хотите:

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat=@"dd/MM/yyyy h:mma"; // Note:  lower case h
NSString *sourceDateString = @"14/5/2013 5:19am"; // in New Yourk

NSTimeZone *sourceTimeZone = [[NSTimeZone alloc] initWithName:@"America/New_York"];
NSTimeZone *destinationTimeZone = [NSTimeZone localTimeZone];
dateFormatter.timeZone = sourceTimeZone;

NSLog(@"DateFormatter TimeZone: %@", dateFormatter.timeZone);
NSLog(@"Source TimeZone: %@", sourceTimeZone);
NSLog(@"Destination TimeZone: %@", destinationTimeZone);

NSLog(@"---------------------------------------");

NSLog(@"sourceDateString : %@", sourceDateString);

 //Convert from string to date

NSDate *dateObject = [dateFormatter dateFromString:sourceDateString];
NSLog(@"From string to date should be in GMT: %@", dateObject);

//Convert from sourceTimeZone to destinationTimeZone
dateFormatter.timeZone = destinationTimeZone;
NSLog(@"Hopefully works: %@", [dateFormatter stringFromDate: dateObject]);

Выход:

Test Case '-[TestOrderedList testFoo]' started.
2013-05-15 11:44:04.263 LogicSim[43238:303] DateFormatter TimeZone: America/New_York (EDT) offset -14400 (Daylight)
2013-05-15 11:44:04.264 LogicSim[43238:303] Source TimeZone: America/New_York (EDT) offset -14400 (Daylight)
2013-05-15 11:44:04.264 LogicSim[43238:303] Destination TimeZone: Local Time Zone (Europe/London (BST) offset 3600 (Daylight))
2013-05-15 11:44:04.264 LogicSim[43238:303] ---------------------------------------
2013-05-15 11:44:04.264 LogicSim[43238:303] sourceDateString : 14/5/2013 5:19am
2013-05-15 11:44:04.265 LogicSim[43238:303] From string to date should be in GMT: 2013-05-14 09:19:00 +0000
2013-05-15 11:44:04.265 LogicSim[43238:303] Hopefully works: 14/05/2013 10:19AM
Test Case '-[TestOrderedList testFoo]' passed (0.002 seconds).

Первая ошибка, которую вы сделали, была в спецификации формата даты HH - время в 24-часовом формате. При использовании со спецификатором am / pm он, кажется, всегда анализирует час как 0. Ваши тестовые данные по совпадению имели час 4, что совпадает с смещением между GMT и Нью-Йорком, что заставляет вас предположить, что он просто получил смещение неправильное. Я изменил указатель часа на h, чтобы получить 12-часовое время. Я также изменил время теста, чтобы не было путаницы.

Вторая ошибка заключалась в том, чтобы возиться с объектом NSDate, в этом заключается безумие. NSDates всегда по Гринвичу. Не добавляйте и не вычитайте временные интервалы для корректировки часовых поясов, просто установите часовой пояс в средстве форматирования даты соответствующим образом. Итак, мой код устанавливает часовой пояс на Нью-Йорк и анализирует дату. Затем он устанавливает часовой пояс на местное время (я нахожусь в Великобритании по BST) и преобразует дату в строку. Работа сделана.

person JeremyP    schedule 15.05.2013

Спасибо всем за подсказки! После множества испытаний я закончил писать функцию, использующую DateComponent:

-(NSString*) convertToLocalTimeZoneDate: (NSString*) sourceDate
                                   Time: (NSString*) sourceTime
{
    //Date and time parsing

    //Expected: NSString *sourceDate = @"5/13/2013";
    //Expected: NSString *sourceTime = @"04:19am";

    NSArray *dateArray = [sourceDate componentsSeparatedByString:@"/"];
    NSDateComponents *dateComps = [[NSDateComponents alloc] init];
    dateComps.calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
    dateComps.year = [[dateArray objectAtIndex:2] integerValue];
    dateComps.month = [[dateArray objectAtIndex:0] integerValue];
    dateComps.day = [[dateArray objectAtIndex:1] integerValue];

    NSString *timeInDay = [sourceTime substringFromIndex:5];

    if ([[timeInDay uppercaseString] isEqualToString:@"PM"]){
        dateComps.hour = 12 + [[sourceTime substringWithRange:NSMakeRange(0, 2)] integerValue];
    } else {
        dateComps.hour = [[sourceTime substringWithRange:NSMakeRange(0, 2)] integerValue];
    }

    dateComps.minute = [[sourceTime substringWithRange:NSMakeRange(3, 2)] integerValue];
    dateComps.timeZone = [[NSTimeZone alloc] initWithName:@"America/New_York"];

    NSLog(@"Original Date Time: %@ %@", sourceDate, sourceTime);
    NSLog(@"GMT Date Time: %@", dateComps.date);

    //Return a string with the local date and time

    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    dateFormatter.locale = [NSLocale currentLocale];
    dateFormatter.dateStyle = NSDateFormatterShortStyle;
    dateFormatter.timeStyle = NSDateFormatterLongStyle;

    return[dateFormatter stringFromDate:dateComps.date];
}

Он возвращает правильный результат:

Исходная дата Время: 13.05.2013, 04:19 (я знаю, что это Америка / Нью-Йорк)

GMT Дата Время: 2013-05-13 08:19:00 +0000 (ОК)

Выход: 13.05.13 10:19:00 CEST

person nico9T    schedule 15.05.2013