TL / DR:我需要NSDate
专门代表1970-01-01 00:00:00 +0000
。使用[NSDate dateWithTimeIntervalSince1970:0]
返回为我的时区调整的日期。我无法弄清楚如何解决这个问题。
我正在尝试编写围绕NSDates
的Objective-C iOS测试。问题是,我尝试创建的任何NSDate
对象,无论是直接使用,还是使用NSDateFormatter
或[NSDateComponents dateFromComponents]
,似乎总是会针对我的Mac'当前时区。也就是说,测试将使用NSDate的时区调整值,并且它也将在Xcode调试器中以这种方式出现。但是,如果我在NSDateComponents
或NSDateFormatter
中明确将时区设置为GMT,当我使用po
检查控制台中的值时,它将返回GMT中的日期/时间,就像我一样集。
例如,[NSDate dateWithTimeIntervalSince1970:0]
会返回日期为1969-12-31 19:00:00 -0500
的NSDate。 [NSDate date]
返回当前日期和时间,但按我的时区:2015-03-03 05:49:32 -0500
。我无法弄清楚为什么我不能仅仅1970-01-01 00:00:00 +0000
作为NSDate。
我有什么遗失的东西吗?任何人都可以帮我解决这个问题吗?
谢谢!
编辑:我尝试使用NSDateComponents
:
NSCalendar *calendar = [[NSCalendar alloc]
initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components = [[NSDateComponents alloc] init];
[components setYear:1970];
[components setMonth:1];
[components setDay:1];
[components setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
NSDate *componentDate = [calendar dateFromComponents:components];
componentDate
在控制台中正确显示(当我键入po componentDate
时),但在调试窗口中显示为时区调整。此外,这个时区调整后的值是我在测试中使用的值,因此它对我编写可靠测试的能力有一定的影响。
答案 0 :(得分:2)
TLDR:[NSDate dateWithTimeIntervalSince1970:0]
代表您要求的日期。它是将NSDate
转换为涉及您的时区的字符串。
作为人类,我们有很多方法可以及时代表。例如,“2001年1月1日00:00:00 GMT”表示特定时刻。同一时刻的另一个名字是“2000年12月31日18:00:00美国/芝加哥”。同一时刻的第三个名字是“2001年1月1日03:00:00欧洲/莫斯科”。所有这些名称(字符串)以及更多名称代表了同一时刻。作为人类,我们认识到所有这些标签代表了同一时刻。
NSDate
以完全不同的方式表示时刻:NSDate
存储相对于一个预定参考时刻的偏移(以秒为单位)。 NSDate
不存储任何时区信息。它只存储一个双精度数。对于每个时刻,只有一个NSDate
代表它。 1
注意人类表征与NSDate
表示之间的区别:瞬间有许多人类表示,但只有一个NSDate
表示。
使用%@
中的NSLog
打印日期,或在调试程序中使用po
时,会将description
消息发送到日期。 description
方法的工作是为NSDate
表示的唯一时刻生成一些人类表示。但是有许多可能的人类表示,而description
方法只能使用一个。该方法的实现者决定使用基于您当地时区的表示。
如果您不喜欢使用当地时区,请不要使用description
(直接或间接)。创建NSDateFormatter
,设置其timeZone
,根据需要设置其他属性,并使用它来设置日期格式。您已经注意到这是有效的。这是解决问题的正确方法。
如果需要,您可以向定义NSDate
方法的gmtDescription
添加一个类别,该方法返回GMT中日期的表示形式:
@interface NSDate (Argus9)
- (NSString *)gmtDescription;
@end
@implementation NSDate (Argus9)
- (NSString *)gmtDescription {
static NSDateFormatter *df;
static dispatch_once_t once;
dispatch_once(&once, ^{
df = [[NSDateFormatter alloc] init];
df.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
df.dateFormat = @"yyyy-MM-dd HH:mm:ss";
});
return [df stringFromDate:self];
}
@end
脚注1.这不完全正确,因为double
有两个零:+0和-0。两者都代表同一时刻(参考时刻本身)。此外,由于NSDate
将其偏移量存储为double
,并且存在有限数量的双精度数,因此它不能唯一地表示每个时刻。许多时间映射到相同的double
值。