iOS: преобразование UTC NSDate в местный часовой пояс

Как мне преобразовать UTC NSDate в местный часовой пояс NSDate в Objective C и / или Swift?


person Community    schedule 12.08.2009    source источник
comment
У дат действительно есть часовые пояса.   -  person Glenn Maynard    schedule 03.12.2012
comment
Если это поможет, подумайте о температуре. Они могут быть выражены в градусах Фаренгейта, Цельсия или Кельвина. Но выражаемая информация (среднее движение молекул) не имеет внутренней единицы, хотя для нас она имеет смысл только тогда, когда выражена в некоторых единицах.   -  person software evolved    schedule 15.01.2013
comment
@DaveDeLong NSDate имеет часовой пояс. Из справочника по классу NSDate: этот метод возвращает значение времени относительно абсолютной ссылочной даты - первого момента 1 января 2001 г. по Гринвичу. Обратите внимание на четкую и конкретную ссылку на GMT.   -  person Murray Sagal    schedule 20.03.2013
comment
Я не согласен. NSDate НЕ имеет часового пояса. Чтобы указать часовой пояс для NSDate, вы используете объект NSCalendar или объект NSDateFormatter. Если вы создаете NSDate из строки, в которой не указан часовой пояс, тогда NSDate будет предполагать, что строка находится в GMT.   -  person Rickster    schedule 03.12.2013
comment
@MurraySagal Тот факт, что один конкретный метод возвращает значение времени относительно даты в определенном часовом поясе, не означает, что NSDate моделирует дату как относящуюся к часовому поясу.   -  person eremzeit    schedule 07.11.2014
comment
@eremzeit Конечно. Но вот снова цитата, на этот раз включая предложение, которое стоит перед ней. Единственный примитивный метод NSDate, timeIntervalSinceReferenceDate, обеспечивает основу для всех других методов в интерфейсе NSDate. Этот метод возвращает значение времени относительно абсолютной контрольной даты - первого момента 1 января 2001 г. по Гринвичу. Объекты NSDate привязаны к GMT. Подробное обсуждение здесь, если вам интересно: stackoverflow.com/questions/2615833/   -  person Murray Sagal    schedule 07.11.2014
comment
@Murray Я считаю, что вы ошибаетесь. Тот факт, что NSDates относятся к контрольной дате, которую Apple документирует для нас в формате GMT, не означает, что NSDates внутренне имеют часовые пояса, кроме, возможно, способа интерпретации времени по умолчанию, когда часовой пояс не указан. В документации можно было бы так же легко указать, что абсолютная контрольная дата - 1 января 2001 г., 02:00 по будапештскому времени. Таким образом, они так же привязаны к любому часовому поясу, как и GMT. См. Этот ответ stackoverflow.com/a/8866731/558352   -  person Brad Thomas    schedule 05.09.2016


Ответы (14)


NSTimeInterval seconds; // assume this exists
NSDate* ts_utc = [NSDate dateWithTimeIntervalSince1970:seconds];

NSDateFormatter* df_utc = [[[NSDateFormatter alloc] init] autorelease];
[df_utc setTimeZone:[NSTimeZone timeZoneWithName:@"UTC"]];
[df_utc setDateFormat:@"yyyy.MM.dd G 'at' HH:mm:ss zzz"];

NSDateFormatter* df_local = [[[NSDateFormatter alloc] init] autorelease];
[df_local setTimeZone:[NSTimeZone timeZoneWithName:@"EST"]];
[df_local setDateFormat:@"yyyy.MM.dd G 'at' HH:mm:ss zzz"];

NSString* ts_utc_string = [df_utc stringFromDate:ts_utc];
NSString* ts_local_string = [df_local stringFromDate:ts_utc];

// you can also use NSDateFormatter dateFromString to go the opposite way

Таблица параметров строки форматирования:

https://waracle.com/iphone-nsdateformatter-date-formatting-table/

Если производительность является приоритетом, вы можете рассмотреть возможность использования strftime

https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man3/strftime.3.html

person slf    schedule 31.08.2011
comment
вероятно, стоит упомянуть, что вы также можете использовать форматировщик для чтения дат из строк - person slf; 08.09.2011
comment
@DaveDeLong, все хорошо, если вы просто отображаете дату в виде строки. Но есть вполне веские причины для преобразования часовых поясов на свидании. Например, если вы хотите установить дату по умолчанию в UIDatePicker с помощью setDate :. Даты, возвращаемые веб-службами, часто являются временем в формате UTC, но представляют собой событие в местном часовом поясе пользователя, например телетрансляцию. При передаче непреобразованной даты в средстве выбора будет отображаться неправильное время. - person Christopher Pickslay; 16.10.2011
comment
Вы используете этот же метод для чтения дат из строк. Formatter выполняет преобразование в формат UTC и обратно за вас. - person slf; 17.10.2011
comment
Даты имеют значение не только для «человеческого потребления», они также имеют значение для веб-сервисов, которые могут ожидать дату в локальном формате (здесь летнее время - в ужасном состоянии). - person Diziet; 24.04.2012
comment
Приведенный выше код отлично работает для создания и обработки NSStrings. Но если вы хотите создать событие в календаре с использованием набора событий, чтобы событие создавалось в соответствии с местным часовым поясом, этот код не будет работать. какие изменения мне нужно сделать, чтобы он работал .....? - person Satyam; 09.06.2012
comment
@Satyamsvv EKEvent имеет свойство startDate, просто установите это - person slf; 12.06.2012
comment
+22 за неправильный ответ? @ Дэйв: Нет. Например, ежедневная агрегация событий по местному времени пользователя. - person Glenn Maynard; 20.07.2012
comment
@GlennMaynard, это не так; вот как вы форматируете дату для ее отображения в соответствии с другим часовым поясом. Если вам нужно сгруппировать даты по местному дню, вы можете получить NSCalendar, установить его часовой пояс на тот, который вам нужен, и начать преобразовывать даты в NSDateComponents и сравнивать их day. - person Dave DeLong; 20.07.2012
comment
@ Дэйв: Это явно неправильный ответ. Был задан вопрос, как получить NSDate; он ничего не спрашивал о форматировании. Этот ответ не имеет отношения к вопросу. - person Glenn Maynard; 20.07.2012
comment
@GlennMaynard Я не согласен. Суть этого ответа в том, что преобразование в объект NSDate не требуется, и это правильно. Преобразование в часовой пояс происходит при форматировании даты, а не при ее создании, поскольку в датах нет часовых поясов. - person Dave DeLong; 20.07.2012
comment
@DaveDeLong: Нет, там только сказано, как преобразовать дату в строку. Предположение, что OP может захотеть создать NSCalendarDate вместо этого, было бы хорошо, но этот ответ даже не намекал на это. - person Glenn Maynard; 21.07.2012
comment
@GlennMaynard ... за исключением того, что NSCalendarDate устарел. - person Dave DeLong; 21.07.2012
comment
Также обратите внимание на следующее: oleb .net / blog / 2011/11 /, где указано GMT! = UTC - person huggie; 16.08.2012
comment
@slf Как можно преобразовать дату строки для EST в NSDate для EST? - person NiKKi; 13.04.2016
comment
@NiKKi Я думаю, вы ищете строчные буквы z обратитесь к ссылкам, которые я добавил в сообщение - person slf; 13.04.2016

ИЗМЕНИТЬ Когда я писал это, я не знал, что мне следует использовать форматирование даты, что, вероятно, является лучшим подходом, поэтому также ознакомьтесь с ответом slf.

У меня есть веб-сервис, который возвращает даты в формате UTC. Я использую toLocalTime, чтобы преобразовать его в местное время, и toGlobalTime, чтобы преобразовать обратно, если необходимо.

Вот откуда я получил свой ответ:

https://agilewarrior.wordpress.com/2012/06/27/how-to-convert-nsdate-to-different-time-zones/

@implementation NSDate(Utils)

-(NSDate *) toLocalTime
{
  NSTimeZone *tz = [NSTimeZone defaultTimeZone];
  NSInteger seconds = [tz secondsFromGMTForDate: self];
  return [NSDate dateWithTimeInterval: seconds sinceDate: self];
}

-(NSDate *) toGlobalTime
{
  NSTimeZone *tz = [NSTimeZone defaultTimeZone];
  NSInteger seconds = -[tz secondsFromGMTForDate: self];
  return [NSDate dateWithTimeInterval: seconds sinceDate: self];
}

@end
person gyozo kudor    schedule 12.10.2011
comment
Не делай этого. NSDates всегда в формате UTC. Это просто сбивает с толку. - person JeremyP; 31.08.2012
comment
Это может быть очень полезно для упомянутого выше случая веб-сервиса. Допустим, у вас есть сервер, который хранит события в формате UTC, и клиент хочет запросить все события, которые произошли сегодня. Для этого клиенту необходимо получить текущую дату (UTC / GMT), а затем сдвинуть ее по смещению часового пояса перед отправкой на сервер. - person Taylor Lafrinere; 01.10.2012
comment
@JeremyP Было бы точнее сказать, что NSDates всегда в GMT. Из справочника по классу NSDate: этот метод возвращает значение времени относительно абсолютной ссылочной даты - первого момента 1 января 2001 г. по Гринвичу. Обратите внимание на четкую и конкретную ссылку на GMT. Между GMT и UTC есть техническая разница, но это в основном не имеет отношения к решениям, которые ищут большинство людей. - person Murray Sagal; 20.03.2013
comment
Лучшее и наиболее многоразовое решение моей проблемы :). Большое спасибо :) - person पवन; 26.11.2013
comment
Было бы неплохо отметить, откуда вы скопировали код: agilewarrior.wordpress.com/2012/06/27/ - person aryaxt; 25.03.2015
comment
@aryaxt ты прав, извини. Честно говоря, я не помнил, откуда я скопировал, когда разместил ответ. - person gyozo kudor; 26.03.2015
comment
Я искал такой ответ, для которого не требовалось устанавливать nsdateformatter! спасибо @gyozokudor - person Daniel Ran Lehmann; 15.06.2015
comment
Это, вероятно, вызовет некоторые проблемы с переходом на летнее время - смещение, используемое при преобразовании в локальное, может отличаться от того, которое используется при преобразовании обратно в глобальное. - person alex-i; 22.09.2015

Самый простой способ, который я нашел, таков:

NSDate *someDateInUTC = …;
NSTimeInterval timeZoneSeconds = [[NSTimeZone localTimeZone] secondsFromGMT];
NSDate *dateInLocalTimezone = [someDateInUTC dateByAddingTimeInterval:timeZoneSeconds];
person Sendoa    schedule 30.05.2014
comment
Этот ответ кажется более портативным. В приведенном ниже ответе предполагается, что часовой пояс фиксируется во время выполнения, тогда как приведенный выше ответ извлекает часовой пояс из платформы. - person bleeckerj; 07.07.2014
comment
Очень полезно. Одно дополнение, secondsFromGMTForDate следует использовать, если вы хотите учесть переход на летнее время. См. Apple Docs - person Sergey Markelov; 15.12.2014
comment
При этом не учитываются изменения летнего времени. - person lkraider; 17.11.2016

Swift 3+: от UTC до местного и от местного до UTC

extension Date {

    // Convert UTC (or GMT) to local time
    func toLocalTime() -> Date {
        let timezone = TimeZone.current
        let seconds = TimeInterval(timezone.secondsFromGMT(for: self))
        return Date(timeInterval: seconds, since: self)
    }

    // Convert local time to UTC (or GMT)
    func toGlobalTime() -> Date {
        let timezone = TimeZone.current
        let seconds = -TimeInterval(timezone.secondsFromGMT(for: self))
        return Date(timeInterval: seconds, since: self)
    }
}
person Krunal    schedule 15.05.2017
comment
Он преобразует любой часовой пояс в UTC или наоборот? - person Mitesh; 11.06.2020

Если вам нужна местная дата и время. Попробуйте этот код: -

NSString *localDate = [NSDateFormatter localizedStringFromDate:[NSDate date] dateStyle:NSDateFormatterMediumStyle timeStyle:NSDateFormatterMediumStyle];
person Mohd Iftekhar Qurashi    schedule 20.05.2013
comment
Отличный ответ! Это захватит текущую дату. Адаптация этого, использующая строку даты, заключалась бы в замене [NSDate date] на [NSDate dateWithNaturalLanguageString:sMyDateString]. - person Volomike; 20.01.2016

Преобразуйте дату UTC в местную дату

-(NSString *)getLocalDateTimeFromUTC:(NSString *)strDate
{
    NSDateFormatter *dtFormat = [[NSDateFormatter alloc] init];
    [dtFormat setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    [dtFormat setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]];
    NSDate *aDate = [dtFormat dateFromString:strDate];

    [dtFormat setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    [dtFormat setTimeZone:[NSTimeZone systemTimeZone]];

    return [dtFormat stringFromDate:aDate];
}

Использовать как это

NSString *localDate = [self getLocalDateTimeFromUTC:@"yourUTCDate"];
person Vvk    schedule 08.03.2016
comment
У меня не работает, мое местное время +3 и этот код возвращает +2 - person Fadi Abuzant; 25.10.2017

Здесь input представляет собой строку currentUTCTime (в формате 30.08.2012 11:11) преобразует время ввода в GMT в системное время зоны.

//UTC time
NSDateFormatter *utcDateFormatter = [[[NSDateFormatter alloc] init] autorelease];
[utcDateFormatter setDateFormat:@"MM/dd/yyyy HH:mm"];
[utcDateFormatter setTimeZone :[NSTimeZone timeZoneForSecondsFromGMT: 0]];

// utc format
NSDate *dateInUTC = [utcDateFormatter dateFromString: currentUTCTime];

// offset second
NSInteger seconds = [[NSTimeZone systemTimeZone] secondsFromGMT];

// format it and send
NSDateFormatter *localDateFormatter = [[[NSDateFormatter alloc] init] autorelease];
[localDateFormatter setDateFormat:@"MM/dd/yyyy HH:mm"];
[localDateFormatter setTimeZone :[NSTimeZone timeZoneForSecondsFromGMT: seconds]];

// formatted string
NSString *localDate = [localDateFormatter stringFromDate: dateInUTC];
return localDate;
person Ashwin Kumar    schedule 31.08.2012

Преобразовать date из календаря UTC на один с соответствующим локальным NSTimeZone.

person Community    schedule 12.08.2009

Я пишу этот метод для преобразования даты и времени в нашу LocalTimeZone

-Здесь (NSString *) параметр TimeZone - часовой пояс сервера

-(NSString *)convertTimeIntoLocal:(NSString *)defaultTime :(NSString *)TimeZone
{
    NSDateFormatter *serverFormatter = [[NSDateFormatter alloc] init];
    [serverFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:TimeZone]];
    [serverFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    NSDate *theDate = [serverFormatter dateFromString:defaultTime];
    NSDateFormatter *userFormatter = [[NSDateFormatter alloc] init];
    [userFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    [userFormatter setTimeZone:[NSTimeZone localTimeZone]];
    NSString *dateConverted = [userFormatter stringFromDate:theDate];
    return dateConverted;
}
person imjaydeep    schedule 09.01.2016

Поскольку никто, казалось, не использовал NSDateComponents, я подумал, что вставлю его ... В этой версии NSDateFormatter не используется, следовательно, не используется синтаксический анализ строк, а NSDate не используется для представления времени за пределами GMT (UTC). Исходный NSDate находится в переменной i_date.

NSCalendar *anotherCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:i_anotherCalendar];
anotherCalendar.timeZone = [NSTimeZone timeZoneWithName:i_anotherTimeZone];

NSDateComponents *anotherComponents = [anotherCalendar components:(NSCalendarUnitEra | NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond | NSCalendarUnitNanosecond) fromDate:i_date];

// The following is just for checking   
anotherComponents.calendar = anotherCalendar; // anotherComponents.date is nil without this
NSDate *anotherDate = anotherComponents.date;

i_anotherCalendar может быть NSCalendarIdentifierGregorian или любой другой календарь. NSString, разрешенный для i_anotherTimeZone, можно получить с помощью [NSTimeZone knownTimeZoneNames], но anotherCalendar.timeZone может быть [NSTimeZone defaultTimeZone], [NSTimeZone localTimeZone] или [NSTimeZone systemTimeZone] вместе.

На самом деле это anotherComponents время в новом часовом поясе. Вы заметите, что anotherDate равно i_date, потому что время указывается в GMT (UTC).

person techniao    schedule 21.12.2014

Вы можете попробовать это:

NSDate *currentDate = [[NSDate alloc] init];
NSTimeZone *timeZone = [NSTimeZone defaultTimeZone];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateStyle:NSDateFormatterLongStyle];
[dateFormatter setTimeStyle:NSDateFormatterLongStyle];
[dateFormatter setTimeZone:timeZone];
[dateFormatter setDateFormat:@"ZZZ"];
NSString *localDateString = [dateFormatter stringFromDate:currentDate];
NSMutableString *mu = [NSMutableString stringWithString:localDateString];
[mu insertString:@":" atIndex:3];
 NSString *strTimeZone = [NSString stringWithFormat:@"(GMT%@)%@",mu,timeZone.name];
 NSLog(@"%@",strTimeZone);
person kalpesh satasiya    schedule 09.01.2018

Пожалуйста, используйте этот код.

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss"]; 
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]];
NSDate *date = [dateFormatter dateFromString:@"2015-04-01T11:42:00"]; // create date from string

[dateFormatter setDateFormat:@"EEE, MMM d, yyyy - h:mm a"];
[dateFormatter setTimeZone:[NSTimeZone localTimeZone]];
NSString *timestamp = [dateFormatter stringFromDate:date];
person incredever    schedule 14.01.2021

Решение для библиотеки SwiftDate:

// Take date by seconds in UTC time zone
var viewModelDate: Date = DateInRegion(seconds: Double(backendModel.scheduledTimestamp)).date 

...

// Convert date to local timezone and convert to string by format rule.
label.text = viewModelDate.convertTo(region: .current).toFormat(" EEE MM/dd j:mm") 
person Bimawa    schedule 09.06.2021

Преобразование времени UTC в текущий часовой пояс.

функция вызова

NSLocale *locale = [NSLocale autoupdatingCurrentLocale];

NSString *myLanguageCode = [locale objectForKey: NSLocaleLanguageCode];
NSString *myCountryCode = [locale objectForKey: NSLocaleCountryCode];

NSString *rfc3339DateTimeString = @"2015-02-15 00:00:00"];
NSDate *myDateTime = (NSDate*)[_myCommonFunctions _ConvertUTCTimeToLocalTimeWithFormat:rfc3339DateTimeString LanguageCode:myLanguageCode CountryCode:myCountryCode Formated:NO];

Функция

-NSObject*)_ConvertUTCTimeToLocalTimeWithFormat:rfc3339DateTimeString     LanguageCode:(NSString *)lgc CountryCode:(NSString *)ctc Formated:(BOOL) formated
{
    NSDateFormatter *sUserVisibleDateFormatter = nil;
    NSDateFormatter *sRFC3339DateFormatter = nil;

    NSTimeZone *timeZone = [NSTimeZone defaultTimeZone];

    if (sRFC3339DateFormatter == nil)
    {
        sRFC3339DateFormatter = [[NSDateFormatter alloc] init];

        NSLocale *myPOSIXLocale = [[NSLocale alloc] initWithLocaleIdentifier:[NSString stringWithFormat:@"%@", timeZone]];

        [sRFC3339DateFormatter setLocale:myPOSIXLocale];
        [sRFC3339DateFormatter setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'"];
        [sRFC3339DateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
    }

    // Convert the RFC 3339 date time string to an NSDate.
    NSDate *date = [sRFC3339DateFormatter dateFromString:rfc3339DateTimeString];

    if (formated == YES)
    {
        NSString *userVisibleDateTimeString;

        if (date != nil)
        {
            if (sUserVisibleDateFormatter == nil)
            {
                sUserVisibleDateFormatter = [[NSDateFormatter alloc] init];
                [sUserVisibleDateFormatter setDateStyle:NSDateFormatterMediumStyle];
                [sUserVisibleDateFormatter setTimeStyle:NSDateFormatterShortStyle];
            }

            // Convert the date object to a user-visible date string.
            userVisibleDateTimeString = [sUserVisibleDateFormatter stringFromDate:date];

            return (NSObject*)userVisibleDateTimeString;
        }
    }

    return (NSObject*)date;
}
person Alan10977    schedule 15.02.2015