iOS: Konwertuj UTC NSDate na lokalną strefę czasową

139

Jak przekonwertować UTC NSDatena lokalną strefę czasową NSDate w Objective C i / lub Swift?

Krunal
źródło
14
Daty z pewnością mają strefy czasowe.
Glenn Maynard
1
Jeśli to pomoże, pomyśl o temperaturach. Można je wyrazić w stopniach Fahrenheita, Celsjusza lub Kelvina. Ale wyrażana informacja (średni ruch cząsteczek) nie ma wewnętrznej jednostki, chociaż ma dla nas znaczenie tylko wtedy, gdy jest wyrażona w jakiejś jednostce.
oprogramowanie ewoluowało
7
@DaveDeLong NSDate ma strefę czasową. Z odwołania do klasy NSDate: „Ta metoda zwraca wartość czasu w stosunku do bezwzględnej daty odniesienia - pierwsza chwila 1 stycznia 2001 r. GMT”. Zwróć uwagę na jasne i konkretne odniesienie do GMT.
Murray Sagal
3
Nie zgadzam się. NSDate NIE ma strefy czasowej. Aby określić strefę czasową dla NSDate, użyj obiektu NSCalendar lub obiektu NSDateFormatter. Jeśli utworzysz NSDate z ciągu, który nie ma określonej strefy czasowej, wówczas NSDate przyjmie, że ciąg jest w czasie GMT.
Rickster
1
@MurraySagal Tylko dlatego, że ta konkretna metoda zwraca wartość czasu w odniesieniu do daty w określonej strefie czasowej, nie oznacza to, że NSDate modeluje datę jako relatywną do strefy czasowej.
eremzeit

Odpowiedzi:

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

Tabela formatowania parametrów ciągu:

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

Jeśli priorytetem jest wydajność, możesz rozważyć użycie strftime

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

slf
źródło
prawdopodobnie warto wspomnieć, że możesz użyć programu formatującego do odczytania dat również z łańcuchów
slf
34
@DaveDeLong to wszystko dobrze i dobrze, jeśli wyświetlasz tylko datę jako ciąg. Istnieją jednak całkowicie uzasadnione powody, dla których warto przeprowadzić konwersję strefy czasowej na randkę. Na przykład, jeśli chcesz ustawić domyślną datę w UIDatePicker za pomocą setDate :. Daty zwracane przez usługi internetowe są często podawane w czasie UTC, ale reprezentują wydarzenie w lokalnej strefie czasowej użytkownika, takie jak program telewizyjny. Przekazanie nieprzekształconej daty spowoduje wyświetlenie nieprawidłowego czasu w selektorze.
Christopher Pickslay
5
@GlennMaynard Nie zgadzam się. Istota tej odpowiedzi polega na tym, że żadna konwersja do NSDateprzedmiotu nie jest konieczna, co jest poprawne. Konwersja do strefy czasowej następuje po sformatowaniu daty, a nie po jej utworzeniu, ponieważ daty nie mają stref czasowych.
Dave DeLong,
1
@GlennMaynard ... z wyjątkiem tego, że NSCalendarDatejest przestarzały.
Dave DeLong,
1
Zwróć też uwagę na to: oleb.net/blog/2011/11/… gdzie jest napisane „GMT! = UTC”
przytul się,
106

EDYTUJ Kiedy to pisałem, nie wiedziałem, że powinienem użyć formatu daty, który jest prawdopodobnie lepszym podejściem, więc sprawdź slfteż odpowiedź.

Mam usługę sieciową, która zwraca daty w UTC. Używam, toLocalTimeaby przekonwertować go na czas lokalny i toGlobalTimew razie potrzeby przekonwertować z powrotem.

Stąd otrzymałem odpowiedź:

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
gyozo kudor
źródło
25
Nie rób tego. NSDates są zawsze w UTC. To tylko myli sprawę.
JeremyP
13
Może to być bardzo przydatne w przypadku „usługi sieciowej” opisanej powyżej. Powiedzmy, że masz serwer, który przechowuje wydarzenia w UTC, a klient chce zapytać o wszystkie wydarzenia, które miały miejsce dzisiaj. Aby to zrobić, klient musi uzyskać aktualną datę (UTC / GMT), a następnie przesunąć ją zgodnie z przesunięciem strefy czasowej przed wysłaniem jej na serwer.
Taylor Lafrinere
@JeremyP Dokładniej byłoby powiedzieć, że NSDates są zawsze w GMT. Z odwołania do klasy NSDate: „Ta metoda zwraca wartość czasu w stosunku do bezwzględnej daty odniesienia - pierwsza chwila 1 stycznia 2001 r. GMT”. Zwróć uwagę na jasne i konkretne odniesienie do GMT. Istnieje różnica techniczna między GMT i UTC, ale w większości przypadków nie ma to znaczenia dla rozwiązań, których szuka większość ludzi.
Murray Sagal
3
Byłoby miło odnotować, gdzie skopiowałeś kod z: agilewarrior.wordpress.com/2012/06/27/ ...
aryaxt
2
@aryaxt masz rację, przepraszam. Szczerze mówiąc, nie pamiętałem, skąd kopiowałem, kiedy publikowałem odpowiedź.
gyozo kudor
49

Najłatwiejsza metoda, jaką znalazłem, to:

NSDate *someDateInUTC = …;
NSTimeInterval timeZoneSeconds = [[NSTimeZone localTimeZone] secondsFromGMT];
NSDate *dateInLocalTimezone = [someDateInUTC dateByAddingTimeInterval:timeZoneSeconds];
Sendoa
źródło
3
Ta odpowiedź wydaje się bardziej przenośna. Poniższa odpowiedź zakłada, że ​​strefa czasowa jest ustalona w czasie wykonywania, podczas gdy powyższa odpowiedź pochodzi ze strefy czasowej z platformy.
bleeckerj
9
Bardzo pomocne. secondsFromGMTForDateNależy użyć jednego dodatku, jeśli chcesz uwzględnić czas letni. Zobacz Apple Docs
Sergey Markelov,
1
Nie uwzględnia to zmian czasu letniego.
lkraider
36

Swift 3+ : od UTC do lokalnego i od lokalnego do 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)
    }
}
Krunal
źródło
Konwertuje dowolną strefę czasową na UTC lub odwrotnie?
Mitesh
26

Jeśli chcesz lokalną datę i godzinę. Wypróbuj ten kod: -

NSString *localDate = [NSDateFormatter localizedStringFromDate:[NSDate date] dateStyle:NSDateFormatterMediumStyle timeStyle:NSDateFormatterMediumStyle];
Mohd Iftekhar Qurashi
źródło
Świetna odpowiedź! Spowoduje to pobranie aktualnej daty. Adaptacja ta, która wykorzystuje datę ciąg byłoby wymienić [NSDate date]z [NSDate dateWithNaturalLanguageString:sMyDateString].
Volomike
7

Konwertuj swoją datę UTC na datę lokalną

-(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];
}

Użyj w ten sposób

NSString *localDate = [self getLocalDateTimeFromUTC:@"yourUTCDate"];
Vvk
źródło
1
Nie działa dla mnie, mój czas lokalny to +3, a ten kod zwraca +2
Fadi Abuzant
6

Tutaj dane wejściowe to ciąg currentUTCTime (w formacie 08/30/2012 11:11) konwertuje czas wejściowy w GMT na ustawiony przez system czas strefy

//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;
Ashwin Kumar
źródło
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
Linh Nguyen
źródło
2

Piszę tę metodę, aby przekonwertować datę i godzinę na naszą LocalTimeZone

-Here (NSString *) Parametr TimeZone to strefa czasowa serwera

-(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;
}
imjaydeep
źródło
1

Ponieważ wydawało się NSDateComponents, że nikt nie używa , pomyślałem, że będę go używać ... W tej wersji nie NSDateFormatterjest używane, stąd nie ma analizowania ciągów i NSDatenie jest używane do reprezentowania czasu poza GMT (UTC). Oryginał NSDateznajduje się w zmiennej 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_anotherCalendarmógłby być NSCalendarIdentifierGregorianlub jakikolwiek inny kalendarz. NSStringPozwoliło i_anotherTimeZonemogą być nabywane z [NSTimeZone knownTimeZoneNames], ale anotherCalendar.timeZonemoże być [NSTimeZone defaultTimeZone]albo [NSTimeZone localTimeZone]czy [NSTimeZone systemTimeZone]w ogóle.

W rzeczywistości anotherComponentsutrzymuje czas w nowej strefie czasowej. Zauważysz, że anotherDatejest równe i_date, ponieważ zawiera czas w GMT (UTC).

techniao
źródło
0

Możesz spróbować tego:

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);
kalpesh satasiya
źródło
-1

Konwertuj czas UTC na aktualną strefę czasową.

funkcja wywołania

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

Funkcjonować

-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;
}
Alan10977
źródło