iOS: convertir UTC NSDate en fuseau horaire local

139

Comment puis-je convertir un UTC NSDateen NSDate de fuseau horaire local en Objective C ou / et Swift?

Krunal
la source
14
Les dates ont certainement des fuseaux horaires.
Glenn Maynard
1
Si cela aide, pensez aux températures. Ils peuvent être exprimés en Fahrenheit, Celsius ou Kelvin. Mais l'information exprimée (le mouvement moyen des molécules) n'a pas d'unité intrinsèque, bien qu'elle ne soit significative pour nous que lorsqu'elle est exprimée dans une unité.
logiciel a évolué le
7
@DaveDeLong NSDate a un fuseau horaire. À partir de la référence de classe NSDate: "Cette méthode renvoie une valeur d'heure relative à une date de référence absolue - le premier instant du 1er janvier 2001, GMT." Notez la référence claire et spécifique à GMT.
Murray Sagal
3
Je ne suis pas d'accord. NSDate n'a PAS de fuseau horaire. Pour spécifier le fuseau horaire du NSDate, vous utilisez un objet NSCalendar ou un objet NSDateFormatter. Si vous créez un NSDate à partir d'une chaîne pour laquelle aucun fuseau horaire n'est spécifié, le NSDate supposera que la chaîne est à l'heure GMT.
Rickster
1
@MurraySagal Ce n'est pas parce que cette méthode particulière renvoie une valeur d'heure relative à une date dans un fuseau horaire spécifique que NSDate modélise une date comme étant relative à un fuseau horaire.
eremzeit

Réponses:

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

Tableau des paramètres de chaîne de formatage:

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

Si les performances sont une priorité, vous pouvez envisager d'utiliser strftime

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

slf
la source
il vaut probablement la peine de mentionner que vous pouvez également utiliser le formateur pour lire les dates à partir de chaînes
slf
34
@DaveDeLong c'est très bien si vous affichez simplement la date sous forme de chaîne. Mais il existe des raisons parfaitement valables pour effectuer des conversions de fuseau horaire sur une date. Par exemple, si vous souhaitez définir la date par défaut sur un UIDatePicker à l'aide de setDate :. Les dates renvoyées par les services Web sont souvent UTC, mais représentent un événement dans le fuseau horaire local de l'utilisateur, comme une liste télévisée. Passer une date non convertie affichera l'heure incorrecte dans le sélecteur.
Christopher Pickslay
5
@GlennMaynard Je ne suis pas d'accord. L'essence de cette réponse est qu'aucune conversion en NSDateobjet n'est nécessaire, ce qui est correct. La conversion en fuseau horaire se produit lorsque la date est formatée, pas lors de sa création, car les dates n'ont pas de fuseau horaire.
Dave DeLong
1
@GlennMaynard ... sauf que NSCalendarDatec'est obsolète.
Dave DeLong
1
Notez également ceci: oleb.net/blog/2011/11/… où il est dit "GMT! = UTC"
huggie
106

EDIT Quand j'ai écrit ceci, je ne savais pas que je devrais utiliser un datformatter qui est probablement une meilleure approche, alors vérifiez aussi slfla réponse de.

J'ai un webservice qui renvoie les dates en UTC. J'utilise toLocalTimepour le convertir en heure locale et toGlobalTimepour le reconvertir si nécessaire.

C'est de là que j'ai obtenu ma réponse:

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
la source
25
Ne fais pas ça. Les NSDates sont toujours en UTC. Cela ne fait que confondre le problème.
JeremyP
13
Cela peut être très utile pour le cas du "webservice" mentionné ci-dessus. Disons que vous avez un serveur qui stocke les événements en UTC et que le client souhaite demander tous les événements qui se sont produits aujourd'hui. Pour ce faire, le client doit obtenir la date actuelle (UTC / GMT), puis la décaler de son décalage de fuseau horaire avant de l'envoyer au serveur.
Taylor Lafrinere
@JeremyP Il serait plus exact de dire que les NSDates sont toujours en GMT. À partir de la référence de classe NSDate: "Cette méthode renvoie une valeur d'heure relative à une date de référence absolue - le premier instant du 1er janvier 2001, GMT." Notez la référence claire et spécifique à GMT. Il existe une différence technique entre GMT et UTC, mais cela n'a généralement pas de rapport avec les solutions que la plupart des gens recherchent.
Murray Sagal
3
Ce serait bien de noter où vous avez copié le code de: agilewarrior.wordpress.com/2012/06/27/…
aryaxt
2
@aryaxt vous avez raison, je suis désolé. Honnêtement, je ne me souvenais pas d'où j'avais copié lorsque j'ai publié la réponse.
gyozo kudor
49

La méthode la plus simple que j'ai trouvée est la suivante:

NSDate *someDateInUTC = …;
NSTimeInterval timeZoneSeconds = [[NSTimeZone localTimeZone] secondsFromGMT];
NSDate *dateInLocalTimezone = [someDateInUTC dateByAddingTimeInterval:timeZoneSeconds];
Sendoa
la source
3
Cette réponse semble plus portable. La réponse ci-dessous suppose que le fuseau horaire est fixé au moment de l'exécution, tandis que la réponse ci-dessus dérive le fuseau horaire de la plate-forme.
bleeckerj
9
Très utile. Un ajout secondsFromGMTForDatedoit être utilisé si vous souhaitez tenir compte de l'heure d'été. Voir Apple Docs
Sergey Markelov
1
Cela ne prend pas en compte les modifications DST.
lkraider
36

Swift 3+ : UTC vers Local et Local vers 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
la source
Il convertira n'importe quel fuseau horaire en UTC ou vice versa?
Mitesh le
26

Si vous voulez une date et une heure locales. Essayez ce code: -

NSString *localDate = [NSDateFormatter localizedStringFromDate:[NSDate date] dateStyle:NSDateFormatterMediumStyle timeStyle:NSDateFormatterMediumStyle];
Mohd Iftekhar Qurashi
la source
Très bonne réponse! Cela saisira la date actuelle. Une adaptation de ce qui utilise une chaîne de date serait de remplacer [NSDate date]par [NSDate dateWithNaturalLanguageString:sMyDateString].
Volomike
7

Convertissez votre date UTC en date locale

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

Utilisez comme ça

NSString *localDate = [self getLocalDateTimeFromUTC:@"yourUTCDate"];
Vvk
la source
1
Ne fonctionne pas pour moi, mon heure locale est +3 et ce code retourne +2
Fadi Abuzant
6

Ici, l'entrée est une chaîne currentUTCTime (au format 30/08/2012 11:11) convertit l'heure d'entrée en GMT en heure de zone définie par le système

//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
la source
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
la source
2

J'écris cette méthode pour convertir la date et l'heure dans notre LocalTimeZone

-Here (NSString *) paramètre TimeZone est un fuseau horaire du serveur

-(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
la source
1

Comme personne ne semblait utiliser NSDateComponents, j'ai pensé que j'en lancerais un ... Dans cette version, no NSDateFormatterest utilisé, donc pas d'analyse de chaîne, et NSDaten'est pas utilisé pour représenter le temps en dehors de GMT (UTC). L'original NSDateest dans la variable 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_anotherCalendarpourrait être NSCalendarIdentifierGregorianou tout autre calendrier. Le NSStringpermis i_anotherTimeZonepeut être acquis avec [NSTimeZone knownTimeZoneNames], mais anotherCalendar.timeZonepourrait être [NSTimeZone defaultTimeZone]ou [NSTimeZone localTimeZone]ou[NSTimeZone systemTimeZone] tout à fait.

Il tient en fait anotherComponentsl'heure dans le nouveau fuseau horaire. Vous remarquerez qu'il anotherDateest égal à i_date, car il contient l'heure GMT (UTC).

techniao
la source
0

Vous pouvez essayer celui-ci:

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
la source
-1

Convertissez l'heure UTC en fuseau horaire actuel.

fonction d'appel

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

Fonction

-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
la source