iOS: Konversi UTC NSDate ke Timezone lokal

138

Bagaimana cara mengubah UTC NSDateke NSDate zona waktu lokal di Objective C atau / dan Swift?

Krunal
sumber
14
Tanggal tentu memiliki zona waktu.
Glenn Maynard
1
Jika itu membantu, pikirkan suhu. Mereka dapat diekspresikan dalam Fahrenheit, Celsius, atau Kelvin. Tetapi informasi yang diungkapkan (pergerakan rata-rata molekul) tidak memiliki unit intrinsik, meskipun hanya bermakna bagi kita ketika diekspresikan dalam beberapa unit.
perangkat lunak berkembang
7
@DaveDeLong NSDate memang memiliki zona waktu. Dari referensi kelas NSDate: "Metode ini mengembalikan nilai waktu relatif ke tanggal referensi absolut — instan pertama 1 Januari 2001, GMT." Perhatikan referensi yang jelas dan spesifik untuk GMT.
Murray Sagal
3
Saya tidak setuju. NSDate TIDAK memiliki zona waktu. Untuk menentukan zona waktu untuk NSDate, Anda menggunakan objek NSCalendar atau objek NSDateFormatter. Jika Anda membuat NSDate dari string yang tidak memiliki zona waktu yang ditentukan, maka NSDate akan menganggap bahwa string tersebut dalam waktu GMT.
Rickster
1
@MurraySagal Hanya karena satu metode tertentu mengembalikan nilai waktu relatif terhadap tanggal dalam zona waktu tertentu, itu tidak berarti bahwa NSDate memodelkan tanggal sebagai relatif terhadap zona waktu.
eremzeit

Jawaban:

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

Tabel parameter string pemformatan:

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

Jika kinerja adalah prioritas, Anda mungkin ingin mempertimbangkan untuk menggunakan strftime

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

slf
sumber
mungkin layak disebutkan Anda dapat menggunakan formatter untuk membaca tanggal kembali dari string juga
slf
34
@DaveDeLong itu semua baik dan bagus jika Anda hanya menampilkan tanggal sebagai string. Tetapi ada alasan yang sah untuk melakukan konversi zona waktu pada suatu tanggal. Misalnya, jika Anda ingin menetapkan tanggal pada UIDatePicker menggunakan setDate :. Tanggal yang dikembalikan oleh layanan web sering kali adalah UTC, tetapi mewakili suatu peristiwa di zona waktu lokal pengguna, seperti daftar TV. Melewati tanggal yang belum dikonversi akan menampilkan waktu yang salah di pemilih.
Christopher Pickslay
5
@ GlennMaynard saya tidak setuju. Inti dari jawaban ini adalah bahwa tidak perlu ada konversi ke NSDateobjek, yang benar. Konversi ke zona waktu terjadi ketika tanggal diformat, bukan ketika itu dibuat, karena tanggal tidak memiliki zona waktu.
Dave DeLong
1
@ GlennMaynard ... kecuali yang NSCalendarDatesudah usang.
Dave DeLong
1
Perhatikan juga ini: oleb.net/blog/2011/11/... di mana dikatakan "GMT! = UTC"
huggie
106

EDIT Ketika saya menulis ini, saya tidak tahu saya harus menggunakan dateformatter yang mungkin merupakan pendekatan yang lebih baik, jadi lihatlahslf juga jawabannya.

Saya memiliki layanan web yang mengembalikan tanggal dalam UTC. Saya gunakan toLocalTimeuntuk mengubahnya ke waktu lokal dantoGlobalTime untuk mengkonversi kembali jika diperlukan.

Di sinilah saya mendapat jawaban dari:

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
sumber
25
Jangan lakukan ini. NSDates selalu dalam UTC. Ini hanya membingungkan masalah.
JeremyP
13
Ini bisa sangat berguna untuk kasus "layanan web" yang disebutkan di atas. Katakanlah Anda memiliki server yang menyimpan acara di UTC dan klien ingin meminta semua acara yang terjadi hari ini. Untuk melakukan ini, klien perlu mendapatkan tanggal saat ini (UTC / GMT) dan kemudian menggesernya dengan offset zona waktu sebelum mengirimnya ke server.
Taylor Lafrinere
@ JeremyP Akan lebih akurat untuk mengatakan bahwa NSDates selalu dalam GMT. Dari referensi kelas NSDate: "Metode ini mengembalikan nilai waktu relatif ke tanggal referensi absolut — instan pertama 1 Januari 2001, GMT." Perhatikan referensi yang jelas dan spesifik untuk GMT. Ada perbedaan teknis antara GMT dan UTC tetapi itu sebagian besar tidak relevan dengan solusi yang kebanyakan orang cari.
Murray Sagal
3
Akan menyenangkan untuk mencatat di mana Anda menyalin kode dari: agilewarrior.wordpress.com/2012/06/27/…
aryaxt
2
@aryaxt Anda benar, saya minta maaf. Sejujurnya saya tidak ingat dari mana saya menyalin ketika saya memposting jawabannya.
gyozo kudor
49

Metode termudah yang saya temukan adalah ini:

NSDate *someDateInUTC = …;
NSTimeInterval timeZoneSeconds = [[NSTimeZone localTimeZone] secondsFromGMT];
NSDate *dateInLocalTimezone = [someDateInUTC dateByAddingTimeInterval:timeZoneSeconds];
Sendoa
sumber
3
Jawaban ini terasa lebih portabel. Jawaban di bawah ini mengasumsikan zona waktu tetap pada saat runtime sedangkan jawaban di atas berasal zona waktu dari platform.
bleeckerj
9
Sangat membantu. Satu tambahan, secondsFromGMTForDateharus digunakan jika Anda ingin memperhitungkan penghematan siang hari. Lihat Apple Docs
Sergey Markelov
1
Ini gagal memperhitungkan perubahan DST akun.
lkraider
36

Swift 3+ : UTC ke Lokal dan Lokal ke 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
sumber
Ini akan mengubah zona waktu ke UTC atau sebaliknya?
Mitesh
26

Jika Anda ingin tanggal dan waktu setempat. Coba kode ini: -

NSString *localDate = [NSDateFormatter localizedStringFromDate:[NSDate date] dateStyle:NSDateFormatterMediumStyle timeStyle:NSDateFormatterMediumStyle];
Mohd Iftekhar Qurashi
sumber
Jawaban bagus! Ini akan mengambil tanggal saat ini. Adaptasi ini yang menggunakan string tanggal akan diganti [NSDate date]dengan [NSDate dateWithNaturalLanguageString:sMyDateString].
Volomike
7

Ubah tanggal UTC Anda menjadi Tanggal Lokal

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

Gunakan Seperti Ini

NSString *localDate = [self getLocalDateTimeFromUTC:@"yourUTCDate"];
Vvk
sumber
1
Tidak berfungsi untuk saya, waktu lokal saya adalah +3 dan kode ini kembali +2
Fadi Abuzant
6

Di sini input adalah string currentUTCTime (dalam format 08/30/2012 11:11) mengonversi waktu input dalam GMT ke sistem mengatur waktu zona

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

Saya menulis Metode ini untuk mengonversi waktu tanggal ke LocalTimeZone kami

-Sini (NSString *) Parameter TimeZone adalah zona waktu server

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

Karena tidak ada yang tampaknya menggunakan NSDateComponents, saya pikir saya akan memasukkan satu ... Dalam versi ini, tidak ada NSDateFormatteryang digunakan, maka tidak ada string parsing, dan NSDatetidak digunakan untuk mewakili waktu di luar GMT (UTC). Dokumen asli NSDateada dalam variabel 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_anotherCalendarbisa jadi NSCalendarIdentifierGregorianatau kalender lainnya. Yang NSStringdiizinkan untuk i_anotherTimeZonedapat diperoleh dengan [NSTimeZone knownTimeZoneNames], tetapi anotherCalendar.timeZonebisa [NSTimeZone defaultTimeZone]atau [NSTimeZone localTimeZone]atau [NSTimeZone systemTimeZone]sama sekali.

Ini sebenarnya anotherComponentsmenahan waktu di zona waktu baru. Anda akan melihat anotherDatesama dengan i_date, karena waktu berlaku dalam GMT (UTC).

techniao
sumber
0

Anda dapat mencoba yang ini:

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

Konversi waktu UTC ke zona waktu saat ini.

fungsi panggilan

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

Fungsi

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