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 转换为本地时区的主要内容,如果未能解决你的问题,请参考以下文章