NSDate是否独立于时区?

8

我有一个应用程序,显示特定渡轮行程的时间表。

如果我前往不同的时区 - 比如4个小时之前,那么10点的渡轮行程现在会显示为早上6点?

我知道这与日期如何根据它们的时区处理有关,但我无法弄清楚如何更改这种行为。

目前,我正在获取日期并将其显示在UILabel上的方式如下:

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"HH:mm"];
[self.departureTime setText:[dateFormatter stringFromDate:[self.route objectForKey:@"departureTime"]]];
[self.arrivalTime setText:[dateFormatter stringFromDate:[self.route objectForKey:@"arrivalTime"]]];
[dateFormatter release];

感谢您提前的帮助。

4
请注意,NSDate本身与时区无关,它代表的是协调世界时(格林威治标准时间)。您必须设置NSDateFormatter的时区,以便生成您想要的时区的结果。 - Hot Licks
3
@DanielRHicks 日期没有时区。它不代表协调世界时,因为协调世界时是一个时区,而日期没有时区。 - Dave DeLong
2
@DanielRHicks 不完全正确;参考日期是以UTC时区测量的,但它仍然是一个绝对时间点。这个绝对时间点存在于任何时区之外。换句话说,参考日期可以用任何时区表示。 - Dave DeLong
@BradThomas - NSDate对象中存储的数字值是自2001年1月1日GMT以来的毫秒数。是的,这也可以是其他时区中某个时间以来的毫秒数,但如果你开始这样思考,你很快就会混淆自己——我保证。 - Hot Licks
但通常情况下,没有必要这样考虑。我们通常只需要知道NSDate存储相对于某个绝对参考日期的日期时间即可。我们不需要真正了解苹果文档中引用的参考日期是以GMT为基准的,时区规范并不真正相关于了解存储在NSDate中的信息类型。 - Bradley Thomas
显示剩余3条评论
5个回答

7

您需要存储渡轮行驶所在的时区,并按该时区格式化它。

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"HH:mm"]; 

NSDate *now = [NSDate date];   
NSLog(@"now:%@", [dateFormatter stringFromDate:now]);

NSTimeZone *timeZone = [NSTimeZone timeZoneForSecondsFromGMT:(-8 * 3600)];     
[dateFormatter setTimeZone:timeZone];
NSLog(@"adjusted for timezone: %@", [dateFormatter stringFromDate:now]);

输出:

2011-10-10 20:42:23.781 Craplet[2926:707] now:20:42
2011-10-10 20:42:23.782 Craplet[2926:707] adjusted for timezone: 16:42

我们可能还需要处理夏令时。 - Tuyen Nguyen

2

1

您还可以使用苹果参考文档中描述的NSDateComponents类:

如果您需要创建一个与时区无关的日期,可以将日期存储为NSDateComponents对象,只要存储一些对应日历的参考即可。

在iOS中,NSDateComponents对象可以包含一个日历、一个时区和一个日期对象。因此,您可以将日历与组件一起存储。如果您使用NSDateComponents类的date方法访问日期,请确保相关时区是最新的。

https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/DatesAndTimes/Articles/dtTimeZones.html#//apple_ref/doc/uid/20000185-SW1


0
不要将NSDate值与NSLog等格式化输出混淆。NSDate是GMT,苹果的文档如下:

NSDate的唯一原始方法timeIntervalSinceReferenceDate为NSDate接口中的所有其他方法提供了基础。此方法返回相对于绝对参考日期(即2001年1月1日GMT的第一个瞬间)的时间值。

NSTimeInterval referenceInterval = [[dateFormatter dateFromString:@"1 January 2001 GMT"] timeIntervalSinceReferenceDate];
NSLog(@"referenceInterval: %f", referenceInterval);

NSTimeInterval estInterval = [[dateFormatter dateFromString:@"1 January 2001 EST"] timeIntervalSinceReferenceDate];
NSLog(@"estInterval:       %f", estInterval);

输出:

referenceInterval: 0.000000  
estInterval:   18000.000000

那个文档引用并不意味着“NSDate是GMT”,因为格林威治标准时间的2001年1月1日可以在任何时区中同样地表示。 - Bradley Thomas
我只是想理解你所说的“NSDate是GMT”的意思,因为我看不出任何一种方式使NSDate值内部具有优先于任何其他时区(包括GMT)的时区概念。除了文档任意引用GMT作为参考日期的事实,以及如果未显式提供时区,则NSDate在接受字符串时默认将其识别为GMT。 - Bradley Thomas
你说在其他时区它不是0.0,我向你展示了相对于布达佩斯时区它确实是0.0。我不清楚你最新的评论如何解决这个问题(或者如何表明“NSDate是GMT”)。 - Bradley Thomas
我想说的是,事实并不意味着在某种意义上NSDate存储GMT值。它也是相对于堪察加半岛中午的0.0。为什么NSDate不是堪察加时间呢?或者说午夜比中午更特殊吗? - Bradley Thomas
如果你说“NSDate是GMT”,我很难理解它的意思,因为实际上它只能有效地表示“NSDate通过维护相对于绝对参考日期时间的值来存储绝对日期时间,而这个绝对参考日期时间恰好是苹果文档中引用的GMT时间”! - Bradley Thomas
显示剩余6条评论

-1
        NSDate *currentDateTime =  datePicker.date;
        NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
        [dateFormatter setDateFormat:@"EEE,MM-dd-yyyy HH:mm:ss"];
        NSString *dateInStringFormated = [dateFormatter stringFromDate:currentDateTime];
        NSLog(@"%@", dateInStringFormated);

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