iOS: Chuyển đổi UTC NSDate sang múi giờ địa phương


138

Làm cách nào để chuyển đổi UTC NSDatethành NSDate múi giờ cục bộ trong Mục tiêu C hoặc / và Swift?


14
Ngày chắc chắn có múi giờ.
Glenn Maynard

1
Nếu nó giúp, hãy nghĩ về nhiệt độ. Chúng có thể được thể hiện bằng Fahrenheit, Celsius hoặc Kelvin. Nhưng thông tin được thể hiện (chuyển động trung bình của các phân tử) không có đơn vị nội tại, mặc dù nó chỉ có ý nghĩa đối với chúng tôi khi được thể hiện trong một số đơn vị.
phần mềm phát triển

7
@DaveDeLong NSDate không có múi giờ. Từ tham chiếu lớp NSDate: "Phương thức này trả về giá trị thời gian liên quan đến ngày tham chiếu tuyệt đối, tức thì ngay ngày đầu tiên của ngày 1 tháng 1 năm 2001, GMT." Lưu ý các tài liệu tham khảo rõ ràng và cụ thể để GMT.
Murray Sagal

3
Tôi không đồng ý. NSDate KHÔNG có múi giờ. Để chỉ định múi giờ cho NSDate, bạn sử dụng đối tượng NSCalWiki hoặc đối tượng NSDateFormatter. Nếu bạn tạo NSDate từ một chuỗi không có múi giờ được chỉ định, thì NSDate sẽ cho rằng chuỗi đó nằm trong giờ GMT.
Rickster

1
@M bồSagal Chỉ vì một phương thức cụ thể đó trả về giá trị thời gian liên quan đến một ngày trong múi giờ cụ thể, điều đó không có nghĩa là NSDate mô hình một ngày có liên quan đến múi giờ.
eremzeit

Câu trả lời:


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

Bảng các tham số chuỗi định dạng:

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

Nếu hiệu suất là ưu tiên, bạn có thể muốn xem xét sử dụng strftime

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


có lẽ đáng để đề cập, bạn cũng có thể sử dụng trình định dạng để đọc ngày trở lại từ các chuỗi
slf

34
@DaveDeLong tất cả đều tốt và tốt nếu bạn chỉ hiển thị ngày dưới dạng chuỗi. Nhưng có những lý do hoàn toàn hợp lệ để thực hiện chuyển đổi múi giờ vào một ngày. Ví dụ: nếu bạn muốn mặc định ngày trên UIDatePicker bằng setDate :. Ngày được trả lại bởi các dịch vụ web thường là UTC, nhưng đại diện cho một sự kiện trong múi giờ địa phương của người dùng, như danh sách TV. Vượt qua trong một ngày không chuyển đổi sẽ hiển thị thời gian không chính xác trong bộ chọn.
Christopher Pickslay

5
@GlennMaynard Tôi không đồng ý. Bản chất của câu trả lời này là không cần chuyển đổi NSDateđối tượng, điều này là chính xác. Chuyển đổi thành múi giờ xảy ra khi ngày được định dạng, không phải khi nó được tạo, vì ngày không có múi giờ.
Dave DeLong

1
@GlennMaynard ... ngoại trừ việc đó NSCalendarDatekhông được chấp nhận.
Dave DeLong

1
Cũng lưu ý điều này: oleb.net/blog/2011/11/ trên đó ghi "GMT! = UTC"
huggie

106

EDIT Khi tôi viết bài này, tôi không biết mình nên sử dụng một định dạng ngày có lẽ là một cách tiếp cận tốt hơn, vì vậy hãy kiểm tra slfcâu trả lời quá.

Tôi có một dịch vụ web trả về ngày trong UTC. Tôi sử dụng toLocalTimeđể chuyển đổi nó thành giờ địa phương và toGlobalTimeđể chuyển đổi trở lại nếu cần.

Đây là nơi tôi nhận được câu trả lời của mình từ:

https: // agilewar Warrior.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
Đừng làm điều này. NSDates luôn ở trong UTC. Điều này chỉ gây nhầm lẫn vấn đề.
JeremyP

13
Điều này có thể rất hữu ích cho trường hợp "dịch vụ web" được ghi chú ở trên. Giả sử bạn có một máy chủ lưu trữ các sự kiện trong UTC và khách hàng muốn hỏi tất cả các sự kiện đã xảy ra hôm nay. Để làm điều này, khách hàng cần lấy ngày hiện tại (UTC / GMT) và sau đó thay đổi nó theo thời gian bù của nó trước khi gửi nó đến máy chủ.
Taylor Lafrinere

@JeremyP Sẽ chính xác hơn khi nói rằng NSDates luôn ở dạng GMT. Từ tham chiếu lớp NSDate: "Phương thức này trả về giá trị thời gian liên quan đến ngày tham chiếu tuyệt đối, tức thì ngay ngày đầu tiên của ngày 1 tháng 1 năm 2001, GMT." Lưu ý các tài liệu tham khảo rõ ràng và cụ thể để GMT. Có một sự khác biệt về kỹ thuật giữa GMT và UTC nhưng điều đó chủ yếu không liên quan đến các giải pháp mà hầu hết mọi người đang tìm kiếm.
Murray Sagal

3
Sẽ rất tuyệt khi lưu ý nơi bạn đã sao chép mã từ: agilewar Warrior.wordpress.com/2012/06/27/iêu
aryaxt

2
@aryaxt bạn nói đúng, tôi xin lỗi. Tôi thực sự không nhớ tôi đã sao chép từ đâu khi tôi đăng câu trả lời.
gyozo kudor

49

Phương pháp đơn giản nhất mà tôi tìm thấy là:

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

3
Câu trả lời này cảm thấy di động hơn. Câu trả lời dưới đây giả định múi giờ được cố định trong thời gian chạy trong khi câu trả lời ở trên lấy được múi giờ từ nền tảng.
bleeckerj

9
Rất hữu ích. Một bổ sung, secondsFromGMTForDatenên được sử dụng nếu bạn muốn tính đến việc tiết kiệm ánh sáng ban ngày. Xem Tài liệu Apple
Sergey Markelov

1
Điều này không tính đến các thay đổi DST.
lkraider

36

Swift 3+ : UTC thành cục bộ và cục bộ sang 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)
    }
}

Nó sẽ chuyển đổi múi giờ nào sang UTC hay ngược lại?
Mitesh

26

Nếu bạn muốn ngày và giờ địa phương. Hãy thử mã này: -

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

Câu trả lời chính xác! Điều này sẽ lấy ngày hiện tại. Một sự thích ứng của điều này sử dụng chuỗi ngày sẽ được thay thế [NSDate date]bằng [NSDate dateWithNaturalLanguageString:sMyDateString].
Volomike

7

Chuyển đổi ngày UTC của bạn thành Ngày địa phương

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

Sử dụng như thế này

NSString *localDate = [self getLocalDateTimeFromUTC:@"yourUTCDate"];

1
Không hoạt động với tôi, giờ địa phương của tôi là +3 và mã này trả về +2
Fadi Abuzant

6

Ở đây đầu vào là một chuỗi hiện tạiUTCTime (ở định dạng 08/12/2012 11:11) chuyển đổi thời gian đầu vào theo GMT thành thời gian đặt vùng của hệ thống

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

Tôi viết Phương thức này để chuyển đổi thời gian ngày sang LocalTimeZone của chúng tôi

-Có tham số TimeZone (NSString *) là múi giờ của máy chủ

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

Vì dường như không ai đang sử dụng NSDateComponents, tôi nghĩ rằng tôi sẽ đưa một người vào ... Trong phiên bản này, không NSDateFormatterđược sử dụng, do đó không phân tích chuỗi và NSDatekhông được sử dụng để thể hiện thời gian bên ngoài GMT (UTC). Bản gốc NSDatelà trong biến 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_anotherCalendarcó thể NSCalendarIdentifierGregorianhoặc bất kỳ lịch nào khác. Các NSStringphép i_anotherTimeZonecó thể được mua với [NSTimeZone knownTimeZoneNames], nhưng anotherCalendar.timeZonecó thể là [NSTimeZone defaultTimeZone]hay [NSTimeZone localTimeZone]hay[NSTimeZone systemTimeZone] hoàn toàn.

Nó thực sự anotherComponentsđang giữ thời gian trong múi giờ mới. Bạn sẽ thông báo anotherDatebằng i_date, vì nó giữ thời gian trong GMT (UTC).


0

Bạn có thể thử cái này:

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

Chuyển đổi thời gian UTC sang múi giờ hiện tại.

chức năng gọi

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

Chức năng

-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;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.