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

145

如何在 Objective-C 或 Swift 中将 UTC 时间 NSDate 转换为本地时间的 NSDate


14
日期确实有时区。 - Glenn Maynard
1
如果有帮助的话,可以想象温度。它们可以用华氏度、摄氏度或开尔文表示。但所表达的信息(分子的平均运动)没有固有的单位,尽管只有在以某种单位表达时才对我们有意义。 - software evolved
7
NSDate类确实具有时区。从NSDate类参考文档中可以得知:“此方法返回相对于绝对参考日期的时间值——2001年1月1日GMT时间的第一个瞬间。”请注意,明确而具体地提到了GMT时区。 - Murray Sagal
3
我不同意。NSDate本身没有时区的概念。如果要为NSDate指定时区,可以使用NSCalendar对象或者NSDateFormatter对象进行设置。如果从一个没有指定时区的字符串创建NSDate对象,则NSDate会默认将其视为格林威治标准时间。 - Rickster
3
@Murray,我认为你误解了。仅因为NSDates相对于引用日期而言是以GMT格式提供给我们的,并不意味着NSDates本质上具有时区,除非在未指定时区时或许有一种默认的时间解释方式。文档也可以很容易地说明绝对参考日期是布达佩斯时间的2001年1月1日02:00。它们与GMT一样锚定到任何时区。请参见此答案:https://dev59.com/H2ox5IYBdhLWcg3w9o6h#8866731。 - Bradley Thomas
显示剩余2条评论
15个回答

142
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


34
@DaveDeLong 如果你只是把日期显示为字符串,那么这一切都很好。但是进行时区转换有很多合理的原因。例如,如果你想使用setDate:在UIDatePicker上默认日期。web服务返回的日期通常是UTC时间,但代表用户本地时区的事件,比如电视节目。传入未经转换的日期将在选择器中显示错误的时间。 - Christopher Pickslay
5
我不同意。这个答案的要点是不需要将日期转换为NSDate对象,这是正确的。时区转换发生在格式化日期时,而不是创建日期时,因为日期本身不包含时区信息。 - Dave DeLong
1
@GlennMaynard ... 除了 NSCalendarDate 已经被弃用。 - Dave DeLong
1
还要注意这一点:http://oleb.net/blog/2011/11/working-with-date-and-time-in-cocoa-part-2/,其中提到“GMT != UTC”。 - huggie
@NiKKi 我认为你正在寻找小写字母 z,请参考我在帖子中添加的链接。 - slf
显示剩余10条评论

107

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

我有一个 Web 服务,它返回 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

28
不要这样做。NSDate始终处于UTC时区,这只会让事情更加混乱。 - JeremyP
13
对于上述“webservice”情况,这非常有用。假设您有一个服务器,在其中以UTC存储事件,并且客户端想要查询今天发生的所有事件。为此,客户端需要获取当前日期(UTC / GMT),然后将其按其时区偏移量进行偏移,然后再将其发送到服务器。 - Taylor Lafrinere
我问题的最佳和最可重用的解决方案 :). 非常感谢 :) - Pawan Sharma
3
最好注明你从哪里复制了这段代码:https://agilewarrior.wordpress.com/2012/06/27/how-to-convert-nsdate-to-different-time-zones/ - aryaxt
2
@aryaxt,你是对的,我很抱歉。说实话,当我发布答案时,我真的不记得我从哪里复制的了。 - gyozo kudor
显示剩余3条评论

49

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

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

3
这个答案更具通用性。下面的答案假设时区在运行时是固定的,而上面的答案则从平台中获取时区。 - bleeckerj
10
非常有帮助。另外,如果您想考虑夏令时,请使用secondsFromGMTForDate函数。请参见苹果文档 - Sergey M
1
这未考虑到夏令时的变化。 - lkraider

39

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或反之亦然吗? - Mitesh

26

如果你想获取本地日期和时间,请尝试使用以下代码:

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

很好的回答!这将获取当前日期。使用日期字符串的版本将会用[NSDate dateWithNaturalLanguageString:sMyDateString]替换[NSDate date] - Volomike

7

将您的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"];

1
对我没用,我的本地时间是+3,而这段代码返回的是+2。 - Fadi Abuzant

6

这里的输入是一个字符串,格式为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;

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

3

2
我编写了这个方法,将日期时间转换为我们的本地时区。
- 这里的(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;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接