iOS: Перетворити UTC NSDate в локальний часовий пояс


139

Як перетворити UTC NSDateв локальний часовий пояс NSDate в ціль C або / і Swift?


14
Дати, безумовно, мають часові пояси.
Гленн Мейнард

1
Якщо це допомагає, подумайте про температуру. Вони можуть бути виражені у Фаренгейті, Цельсії або Кельвіні. Але інформація, що виражається (середній рух молекул), не має внутрішньої одиниці, хоча для нас вона має значення лише тоді, коли вона виражена в якійсь одиниці.
програмне забезпечення розвивалося

7
@DaveDeLong NSDate має часовий пояс. З посилання на клас NSDate: "Цей метод повертає значення часу відносно абсолютної опорної дати - першого моменту 1 січня 2001 року, GMT." Зверніть увагу на чіткі та конкретні посилання на GMT.
Мюррей Сагал

3
Я не погоджуюсь. NSDate НЕ має часовий пояс. Щоб вказати часовий пояс для NSDate, ви використовуєте об'єкт NSCalendar або об’єкт NSDateFormatter. Якщо ви створюєте NSDate з рядка, у якому не вказано часовий пояс, то NSDate буде припускати, що рядок знаходиться за часом GMT.
Рікстер

1
@MurraySagal Тільки тому, що один конкретний метод повертає значення часу відносно дати у певному часовому поясі, це не означає, що NSDate моделює дату як відносну до часового поясу.
eremzeit

Відповіді:


139
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/strWeather.3.html


напевно, варто згадати, що ви можете використовувати формат і для читання дат ще з рядків
slf

34
@DaveDeLong, це все добре і добре, якщо ви просто відображаєте дату як рядок. Але є цілком поважні причини для того, щоб робити перетворення часових поясів на побачення. Наприклад, якщо ви хочете за замовчуванням дати на UIDatePicker за допомогою setDate :. Дати, повернені веб-службами, часто є UTC, але являють собою подію в локальному часовому поясі користувача, як-от телевізор. Проходження неперетвореної дати відобразить неправильний час у виборі.
Крістофер Пікслі

5
@GlennMaynard Я не згоден. Суть цієї відповіді полягає в тому, що перетворення на NSDateоб’єкт не потрібно, що є правильним. Перетворення в часовий пояс відбувається, коли дата відформатована, а не коли вона створена, оскільки дати не мають часових поясів.
Дейв ДеЛонг

1
@GlennMaynard ... крім того, що NSCalendarDateзастаріло.
Дейв ДеЛонг

1
Також зверніть увагу на це: oleb.net/blog/2011/11/… де написано "GMT! = UTC"
huggie

106

EDIT Коли я писав це, я не знав, що мені слід використовувати формат дат, що, мабуть, є кращим підходом, тому також ознайомтеся з 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

25
Не робіть цього. NSDates завжди в UTC. Це просто заплутує проблему.
JeremyP

13
Це може бути дуже корисно для вищезазначеного випадку "веб-сервіс". Скажімо, у вас є сервер, який зберігає події в UTC, і клієнт хоче запитати про всі події, що відбулися сьогодні. Для цього клієнту необхідно отримати поточну дату (UTC / GMT), а потім змістити її на зміщення часового поясу, перш ніж надсилати її на сервер.
Тейлор Лафрінер

@JeremyP Точніше було б сказати, що NSDates завжди в GMT. З посилання на клас NSDate: "Цей метод повертає значення часу відносно абсолютної опорної дати - першого моменту 1 січня 2001 року, GMT." Зверніть увагу на чіткі та конкретні посилання на GMT. Існує технічна різниця між GMT та UTC, але це в основному не стосується рішень, які більшість людей шукає.
Мюррей Сагал

3
Було б добре відзначити, куди ви скопіювали код з: agilewarrior.wordpress.com/2012/06/27/…
aryaxt

2
@aryaxt ви праві, мені дуже шкода. Я чесно не пам’ятав, звідки я скопіював, коли розмістив відповідь.
gyozo kudor

49

Найпростіший метод, який я знайшов, це такий:

NSDate *someDateInUTC = …;
NSTimeInterval timeZoneSeconds = [[NSTimeZone localTimeZone] secondsFromGMT];
NSDate *dateInLocalTimezone = [someDateInUTC dateByAddingTimeInterval:timeZoneSeconds];

3
Ця відповідь відчуває себе більш портативною. Відповідь нижче передбачає, що часовий пояс фіксується під час виконання, тоді як відповідь вище отримує часовий пояс з платформи.
bleeckerj

9
Дуже корисний. Одне доповнення secondsFromGMTForDateслід використовувати, якщо ви хочете врахувати літній час. Дивіться Apple Docs
Сергій Маркелов

1
Це не враховує зміни DST.
lkraider

36

Перемістіть курсор 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)
    }
}

Це перетворить будь-який часовий пояс у UTC чи навпаки?
Мітеш

26

Якщо ви хочете місцеву дату та час. Спробуйте цей код: -

NSString *localDate = [NSDateFormatter localizedStringFromDate:[NSDate date] dateStyle:NSDateFormatterMediumStyle timeStyle:NSDateFormatterMediumStyle];

Чудова відповідь! Це захопить поточну дату. Адаптацію цього, що використовує рядок дати, слід було б замінити [NSDate date]на [NSDate dateWithNaturalLanguageString:sMyDateString].
Воломіке

7

Перетворіть вашу дату 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"];

1
Не працює для мене, мій місцевий час +3 та повернення цього коду +2
Fadi Abuzant

6

Тут вхід - це рядок 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;

4
//This is basic way to get time of any GMT time.

NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"hh:mm a"];  // 09:30 AM
[formatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:1]]; // For GMT+1
NSString *time = [formatter stringFromDate:[NSDate date]];  // Current time


2

Я пишу цей метод для перетворення часу дати в нашу 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;
}

1

Оскільки, здавалося, ніхто не використовує 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).


0

Ви можете спробувати це:

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);

-1

Перетворити час 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;
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.