iOS: Converter UTC NSDate em fuso horário local

138

Como converter um UTC NSDatepara o fuso horário local NSDate no Objetivo C ou / e Swift?

Krunal
fonte
14
As datas certamente têm fusos horários.
perfil completo de Glenn Maynard
1
Se ajudar, pense nas temperaturas. Eles podem ser expressos em Fahrenheit, Celsius ou Kelvin. Mas a informação que está sendo expressa (o movimento médio das moléculas) não tem unidade intrínseca, embora só seja significativa para nós quando expressa em alguma unidade.
software evoluiu
7
O @DaveDeLong NSDate possui um fuso horário. Na referência da classe NSDate: "Este método retorna um valor de tempo relativo a uma data de referência absoluta - o primeiro instante de 1 de janeiro de 2001, GMT". Observe a referência clara e específica ao GMT.
Murray Sagal
3
Discordo. O NSDate NÃO possui um fuso horário. Para especificar o fuso horário para o NSDate, use um objeto NSCalendar ou um objeto NSDateFormatter. Se você criar um NSDate a partir de uma sequência que não possui fuso horário especificado, o NSDate assumirá que a sequência está no horário GMT.
Rickster
1
@MurraySagal Só porque esse método específico retorna um valor de tempo relativo a uma data em um fuso horário específico, não significa que o NSDate modela uma data como sendo relativa a um fuso horário.
eremzeit

Respostas:

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 de formatação dos parâmetros da string:

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

Se o desempenho for uma prioridade, considere usar strftime

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

slf
fonte
provavelmente vale a pena mencionar que você pode usar o formatador para ler datas também de strings
slf
34
@DaveDeLong está tudo bem se você estiver apenas exibindo a data como uma string. Mas há razões perfeitamente válidas para fazer conversões de fuso horário em uma data. Por exemplo, se você desejar padronizar a data em um UIDatePicker usando setDate :. As datas retornadas pelos serviços da web geralmente são UTC, mas representam um evento no fuso horário local do usuário, como uma listagem de TV. Passar em uma data não convertida exibirá a hora incorreta no selecionador.
Christopher Pickslay
5
@GlennMaynard Eu discordo. A essência dessa resposta é que nenhuma conversão para o NSDateobjeto é necessária, o que é correto. A conversão para um fuso horário ocorre quando a data é formatada, não quando é criada, porque as datas não possuem fuso horário.
Dave DeLong
1
@GlennMaynard ... exceto que NSCalendarDateestá obsoleto.
Dave DeLong
1
Observe também o seguinte: oleb.net/blog/2011/11/… onde diz "GMT! = UTC"
huggie
106

EDITAR Quando escrevi isso, não sabia que deveria usar um formatador de data que provavelmente é uma abordagem melhor, então confiraslf também a resposta.

Eu tenho um serviço da web que retorna datas no UTC. Eu uso toLocalTimepara convertê-lo para a hora local etoGlobalTime para converter novamente, se necessário.

Foi aqui que recebi minha resposta:

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
fonte
25
Não faça isso. Os NSDates estão sempre em UTC. Isso apenas confunde o problema.
precisa saber é o seguinte
13
Isso pode ser muito útil para o caso "webservice" mencionado acima. Digamos que você tenha um servidor que armazene eventos no UTC e o cliente queira solicitar todos os eventos que ocorreram hoje. Para fazer isso, o cliente precisa obter a data atual (UTC / GMT) e depois alterá-la pelo deslocamento do fuso horário antes de enviá-la ao servidor.
Taylor Lafrinere
@ JeremyP Seria mais preciso dizer que os NSDates estão sempre no GMT. Na referência da classe NSDate: "Este método retorna um valor de tempo relativo a uma data de referência absoluta - o primeiro instante de 1 de janeiro de 2001, GMT". Observe a referência clara e específica ao GMT. Existe uma diferença técnica entre GMT e UTC, mas isso é irrelevante para as soluções que a maioria das pessoas procura.
Murray Sagal
3
Seria bom observar de onde você copiou o código: agilewarrior.wordpress.com/2012/06/27/…
aryaxt
2
@aryaxt você está certo, me desculpe. Sinceramente, não me lembro de onde copiei quando publiquei a resposta.
Gyozo kudor
49

O método mais fácil que encontrei é o seguinte:

NSDate *someDateInUTC = …;
NSTimeInterval timeZoneSeconds = [[NSTimeZone localTimeZone] secondsFromGMT];
NSDate *dateInLocalTimezone = [someDateInUTC dateByAddingTimeInterval:timeZoneSeconds];
Sendoa
fonte
3
Essa resposta parece mais portátil. A resposta abaixo assume que o fuso horário é fixado no tempo de execução, enquanto a resposta acima deriva o fuso horário da plataforma.
bleeckerj
9
Muito útil. Uma adição secondsFromGMTForDatedeve ser usada se você quiser considerar o horário de verão. Veja Apple Docs
Sergey Markelov
1
Isso não leva em consideração as alterações de horário de verão.
Lkraider 17/11
36

Swift 3+ : UTC para Local e Local para 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
fonte
Ele converterá qualquer fuso horário para UTC ou vice-versa?
Mitesh 11/06
26

Se você deseja local Data e hora. Experimente este código: -

NSString *localDate = [NSDateFormatter localizedStringFromDate:[NSDate date] dateStyle:NSDateFormatterMediumStyle timeStyle:NSDateFormatterMediumStyle];
Mohd Iftekhar Qurashi
fonte
Ótima resposta! Isso pegará a data atual. Uma adaptação disso que usa uma string de data seria substituída [NSDate date]por [NSDate dateWithNaturalLanguageString:sMyDateString].
Volomike
7

Converta sua data UTC em Data Local

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

Use como este

NSString *localDate = [self getLocalDateTimeFromUTC:@"yourUTCDate"];
Vvk
fonte
1
Não funciona para mim, meu horário local é +3 ​​e esse código retorna +2
Fadi Abuzant 25/10
6

Aqui, a entrada é uma string currentUTCTime (no formato 30/08/2012 11:11) converte o tempo de entrada no GMT para o fuso horário definido pelo sistema

//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
fonte
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
fonte
2

Escrevo este método para converter data e hora em nosso LocalTimeZone

-Here (NSString *) O parâmetro TimeZone é um fuso horário do servidor

-(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
fonte
1

Como ninguém parecia estar usando NSDateComponents, pensei em incluir um ... Nesta versão, no NSDateFormatteré usado, portanto, nenhuma análise de string e NSDatenão é usado para representar o tempo fora do GMT (UTC). O original NSDateestá na variável 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_anotherCalendarpoderia ser NSCalendarIdentifierGregorianou qualquer outro calendário. O NSStringpermitido i_anotherTimeZonepode ser adquirido com [NSTimeZone knownTimeZoneNames], mas anotherCalendar.timeZonepode ser [NSTimeZone defaultTimeZone]ou [NSTimeZone localTimeZone]ou[NSTimeZone systemTimeZone] completamente.

Na verdade, ele está anotherComponentsmantendo o horário no novo fuso horário. Você notará que anotherDateé igual a i_date, porque mantém o tempo em GMT (UTC).

techniao
fonte
0

Você pode tentar este:

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
fonte
-1

Converta a hora UTC no fuso horário atual.

função de chamada

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

Função

-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
fonte