iOS:将 UTC NSDate 转换为本地时区

Posted

技术标签:

【中文标题】iOS:将 UTC NSDate 转换为本地时区【英文标题】:iOS: Convert UTC NSDate to local Timezone 【发布时间】:2010-11-19 02:30:04 【问题描述】:

如何在 Objective C 或/和 Swift 中将 UTC NSDate 转换为本地时区 NSDate?

【问题讨论】:

日期当然有时区。 如果有帮助,请考虑温度。它们可以用华氏、摄氏或开尔文表示。但是被表达的信息(分子的平均运动)没有内在的单位,尽管它只有在以某种单位表达时才对我们有意义。 @DaveDeLong NSDate 确实有一个时区。来自 NSDate 类参考:“此方法返回相对于绝对参考日期的时间值——格林威治标准时间 2001 年 1 月 1 日的第一时刻。”请注意对 GMT 的明确和具体引用。 我不同意。 NSDate 没有时区。要为 NSDate 指定时区,请使用 NSCalendar 对象或 NSDateFormatter 对象。如果您从未指定时区的字符串创建 NSDate,则 NSDate 将假定该字符串为 GMT 时间。 @Murray 我相信你错了。仅仅因为 NSDates 相对于我们在 GMT 中的 Apple 文档格式的参考日期,并不意味着 NSDates 本质上具有时区,除了可能是在未指定时区时解释时间的默认方式。文档可以很容易地说绝对参考日期是布达佩斯时间 2001 年 1 月 1 日 02:00。因此,它们与格林威治标准时间一样锚定到任何时区。看到这个答案***.com/a/8866731/558352 【参考方案1】:
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

格式化字符串参数表:

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

如果性能是优先考虑的因素,您可能需要考虑使用strftime

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

【讨论】:

可能值得一提的是,您也可以使用格式化程序从字符串中读取日期 @DaveDeLong 如果您只是将日期显示为字符串,那就太好了。但是在某个日期进行时区转换有完全正当的理由。例如,如果您想使用 setDate: 在 UIDatePicker 上默认日期。 Web 服务返回的日期通常是 UTC,但代表用户本地时区中的事件,例如电视节目表。传入未转换的日期将在选择器中显示不正确的时间。 @GlennMaynard 我不同意。这个答案的本质是不需要转换为NSDate 对象,这是正确的。转换为时区是在格式化日期时发生的,而不是在创建日期时发生的,因为日期没有时区。 @GlennMaynard ... 除了 NSCalendarDate 已弃用。 另请注意:oleb.net/blog/2011/11/… 上面写着“GMT != UTC”【参考方案2】:

编辑当我写这篇文章时,我不知道我应该使用可能是更好的方法的日期格式化程序,所以也请查看slf 的答案。

我有一个以 UTC 格式返回日期的网络服务。我使用toLocalTime 将其转换为当地时间,并在需要时使用toGlobalTime 转换回来。

这是我得到答案的地方:

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

【讨论】:

不要这样做。 NSDates 始终采用 UTC。这只是混淆了问题。 这对于上面提到的“webservice”案例非常有用。假设您有一个以 UTC 格式存储事件的服务器,并且客户端想要询问今天发生的所有事件。为此,客户端需要获取当前日期(UTC/GMT),然后将其移动时区偏移量,然后再将其发送到服务器。 @JeremyP 更准确地说,NSDates 总是在格林威治标准时间。来自 NSDate 类参考:“此方法返回相对于绝对参考日期的时间值 - 格林威治标准时间 2001 年 1 月 1 日的第一时刻。”请注意对 GMT 的明确和具体参考。 GMT 和 UTC 之间存在技术差异,但这与大多数人正在寻找的解决方案大多无关。 请注意您从哪里复制代码:agilewarrior.wordpress.com/2012/06/27/… @aryaxt 你是对的,我很抱歉。老实说,我不记得我发布答案时从哪里复制的。【参考方案3】:

我发现的最简单的方法是这样的:

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

【讨论】:

这个答案感觉更便携。下面的答案假设时区在运行时是固定的,而上面的答案是从平台派生的时区。 非常有帮助。另外,如果您想考虑夏令时,应该使用secondsFromGMTForDate。见Apple Docs 这没有考虑到夏令时的变化。【参考方案4】:

Swift 3+UTC 到本地和本地到 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)
    

【讨论】:

它将任何时区转换为UTC,反之亦然?【参考方案5】:

如果您想要本地日期和时间。试试这个代码:-

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

【讨论】:

很好的答案!这将获取当前日期。一个使用日期字符串的修改方法是将[NSDate date] 替换为[NSDate dateWithNaturalLanguageString:sMyDateString]【参考方案6】:

将您的 UTC 日期转换为本地日期

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

这样使用

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

【讨论】:

不适合我,我的当地时间是 +3,这段代码返回 +2【参考方案7】:

这里的输入是一个字符串 currentUTCTime(格式为 08/30/2012 11:11)将 GMT 的输入时间转换为系统设置的区域时间

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

【讨论】:

【参考方案8】:
//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

【讨论】:

【参考方案9】:

Convert the date 从 UTC 日历与相应的本地 NSTimeZone 为一。

【讨论】:

【参考方案10】:

我写这个方法来将日期时间转换为我们的 LocalTimeZone

-这里(NSString *)TimeZone参数是一个服务器时区

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

【讨论】:

【参考方案11】:

由于似乎没有人使用NSDateComponents,所以我想我会在... 在这个版本中,没有使用NSDateFormatter,因此没有字符串解析,并且NSDate 不用于表示GMT (UTC) 之外的时间。原来的NSDate在变量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_anotherCalendar 可以是 NSCalendarIdentifierGregorian 或任何其他日历。 可以使用[NSTimeZone knownTimeZoneNames] 获取i_anotherTimeZone 允许的NSString,但anotherCalendar.timeZone 可以是[NSTimeZone defaultTimeZone][NSTimeZone localTimeZone][NSTimeZone systemTimeZone]

实际上是anotherComponents在新时区保持时间。您会注意到 anotherDate 等于 i_date,因为它的时间是 GMT (UTC)。

【讨论】:

【参考方案12】:

你可以试试这个:

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

【讨论】:

【参考方案13】:

请使用此代码。

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss"]; 
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]];
NSDate *date = [dateFormatter dateFromString:@"2015-04-01T11:42:00"]; // create date from string

[dateFormatter setDateFormat:@"EEE, MMM d, yyyy - h:mm a"];
[dateFormatter setTimeZone:[NSTimeZone localTimeZone]];
NSString *timestamp = [dateFormatter stringFromDate:date];

【讨论】:

【参考方案14】:

SwiftDate 库的解决方案:

// Take date by seconds in UTC time zone
var viewModelDate: Date = DateInRegion(seconds: Double(backendModel.scheduledTimestamp)).date 

...

// Convert date to local timezone and convert to string by format rule.
label.text = viewModelDate.convertTo(region: .current).toFormat(" EEE MM/dd j:mm") 

【讨论】:

【参考方案15】:

将 UTC 时间转换为当前时区。

调用函数

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

功能

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

【讨论】:

以上是关于iOS:将 UTC NSDate 转换为本地时区的主要内容,如果未能解决你的问题,请参考以下文章

将 UTC 日期格式转换为本地 nsdate

将UTC日期格式转换为本地nsdate

Flask + Jinja:将 UTC 转换为本地时区

NSDate: 我只输入utc时间成分,并正确设置日历,但NSDate不知为何会被重新计算到我的时区。

将UTC时间戳转换为熊猫中的本地时区问题

将 postgresql 中的 UTC 时区转换为 EST(本地时间)