iPhone - 获取给定地点/时区的当前日期和时间并将其与同一地点的另一个日期/时间进行比较的正确方法
Posted
技术标签:
【中文标题】iPhone - 获取给定地点/时区的当前日期和时间并将其与同一地点的另一个日期/时间进行比较的正确方法【英文标题】:iPhone - Correct way for getting current date and time for a given place / timezone and compare it with another date/time in the same place 【发布时间】:2011-11-13 19:13:43 【问题描述】:我正在寻找正确的方法来获取给定地点/时区的实际日期和时间,并能够将其与同一地点的给定日期/时间进行比较。 p>
假设,例如,巴黎,即 GMT +1。就像我们现在一样,由于夏令时,巴黎也可以是 GMT+2,但据我所知,它是例外的一部分,因此必须将其考虑到答案中,但不能作为一般参数。这里重要的词是“给定的地方”。
所以,如果我想知道在澳大利亚悉尼或法国巴黎的日期和时间,并将该日期放入 NSDate,以便能够将其与另一个代表同一日期/时间的 NSDate 进行比较地方,我该怎么办?
我用 cmets 阅读了一页又一页的问题和答案,即使是接受的答案,也有经验的用户说:不是一个好的答案 -1,错误,不是正确的做法,绝对错误,.. .
那么,你知道正确的方法吗?
在一个完美的世界中,该日期/时间将是绝对的,即使用户的手机不在正确的时间和/或日期和/或时区,或者任何可以接近完美而无需连接的东西日期/时间服务器。
【问题讨论】:
【参考方案1】:我正在寻找正确的方法来获取给定地点/时区的实际日期和时间。
[NSDate date]
返回一个代表当前日期和时间的日期对象,无论您在哪里。 NSDate
s 不受地点或时区的限制。只有一个 NSDate 代表 now 或任何其他时刻,而不是每个时区的不同日期对象。因此,您不应尝试在时区之间转换日期。
NSDate
对象代表一个绝对瞬间。考虑以下示例,说明不同时区的两个日期表示(巴黎的9/9/11 3:54 PM
和悉尼的9/9/11 11:54 PM
)实际上是相同的日期。
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateStyle:NSDateFormatterShortStyle];
[formatter setTimeStyle:NSDateFormatterShortStyle];
[formatter setTimeZone:[NSTimeZone timeZoneWithName:@"Europe/Paris"]];
NSDate *aDate = [formatter dateFromString:@"9/9/11 3:54 PM"];
[formatter setTimeZone:[NSTimeZone timeZoneWithName:@"Australia/Sydney"]];
NSDate *anotherDate = [formatter dateFromString:@"9/9/11 11:54 PM"];
NSLog(@"%@",anotherDate);
if ([aDate isEqualToDate:anotherDate])
NSLog(@"How about that?");
它会记录最后一条消息,因为巴黎的9/9/11 3:54 PM
和悉尼的9/9/11 11:54 PM
实际上是同一时刻。在巴黎是9/9/11 3:54 PM
时,在悉尼是9/9/11 11:54 PM
。
调试器和 NSLog 都给出了 2011-09-09 14:26:02,但现在是 16:26,所以我猜它应该返回 16:26:02 +0200
在输出日期时,请记住NSDate
的description
方法返回格林威治标准时间,您需要使用NSDateFormatter
创建一个日期字符串来表示巴黎、悉尼的当地时间等,从某个日期开始:
NSDate *now = [NSDate date];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateStyle:NSDateFormatterShortStyle];
[formatter setTimeStyle:NSDateFormatterShortStyle];
[formatter setTimeZone:[NSTimeZone timeZoneWithName:@"Australia/Sydney"]];
NSLog(@"%@",[formatter stringFromDate:now]); //--> 9/9/11 11:54 PM
[formatter setTimeZone:[NSTimeZone timeZoneWithName:@"Europe/Paris"]];
NSLog(@"%@",[formatter stringFromDate:now]); //--> 9/9/11 3:54 PM
好的,但是如果我想知道那个时间是否在 15:00 之后,我该如何测试呢?
创建一个表示今天 15:00(当地时间)的 NSDate 对象并将其与“现在”进行比较:
NSDate *now = [NSDate date];
NSCalendar* myCalendar = [NSCalendar currentCalendar];
NSDateComponents* components = [myCalendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit
fromDate:[NSDate date]];
[components setHour: 15];
[components setMinute: 0];
[components setSecond: 0];
NSDate *todayAt15 = [myCalendar dateFromComponents:components];
if ([now compare:todayAt15] == NSOrderedDescending)
NSLog(@"After 15:00 local time");
事实证明,@Oliver 需要检查它是否在巴黎 15:00 之后,因此他需要创建一个日期,表示今天是巴黎时间 15:00(不是当地时间)。有关如何执行此操作的示例,请参阅@Oliver 的答案。为了清楚起见,我的第三个代码 sn-p 显示了如何检查它是否在当地时间 15:00 之后。
【讨论】:
这不能回答问题。为什么你认为它是“9/9/11 3:54 PM”或者我有一个日期字符串?它从何而来?这就是你所说的“绝对时间”吗?当然不是。据我所知,NSDate 不是我们可以称之为真正的绝对瞬间,而是一个主观的瞬间,因为它似乎是用户在 iPhone 上设置的日期时间。你能编辑一下吗? @Oliver 我试图提供一个示例,说明不同时区的两个日期表示(巴黎的9/9/11 3:54 PM
和悉尼的9/9/11 11:54 PM
)实际上是相同的日期,因为日期对象代表时间的瞬间,不受时区的影响。
写 NSDate *now = [NSDate date]; NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; [formatter setDateStyle:NSDateFormatterShortStyle]; [formatter setTimeStyle:NSDateFormatterShortStyle]; [formatter setTimeZone:[NSTimeZone timeZoneWithName:@"Europe/Paris"]]; NSDate *anotherDate = [formatter dateFromString:[formatter stringFromDate:now]];
,调试器和 NSLog 都在 2011-09-09 14:26:02,但现在是 16:26,所以我猜它应该返回 16:26:02 +0200 ?
这样做是为了比较时间,你确定它会比较一个巴黎时间和另一个巴黎时间吗?
@Oliver 它会正确比较日期。 NSDate
s 不受时区限制。没有巴黎 NSDate 或 GMT NSDate 这样的东西。只有 NSDates。【参考方案2】:
在头疼并开始了解 NSDate 是什么之后,我想到了那种解决方案。您如何看待这种做法?
// Now, an absolute date and time that represent now all around the world, that is made to play with
NSDate *now = [NSDate date];
// A specific calendar for a specific place in the world
NSCalendar* parisCalendar = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
[parisCalendar setTimeZone:[NSTimeZone timeZoneWithName:@"Europe/Paris"]];
// Now components seen from Paris
NSDateComponents* componentsNowInParis = [parisCalendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit|NSHourCalendarUnit|NSMinuteCalendarUnit|NSSecondCalendarUnit|NSTimeZoneCalendarUnit fromDate:now];
// Tricking a copy of "Now components seen from Paris" to force 15:00:00, in Paris
NSDateComponents* componentsInParisAt15 = [[componentsNowInParis copy] autorelease];
[componentsInParisAt15 setHour:15];
[componentsInParisAt15 setMinute:0];
[componentsInParisAt15 setSecond:0];
// Getting an universal date reference that represent what could be 15:00:00 seen from paris, Or 19:00:00 from GMT+4
NSDate* dateAt15 = [parisCalendar dateFromComponents:componentsInParisAt15];
// We now have two universal dates that can be compared each other
// If "now" is 16:00:00, those date will show a 60 minutes difference all around the world
NSLog(@"%@", now);
NSLog(@"%@", dateAt15);
一些参考:http://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/DatesAndTimes/Articles/dtTimeZones.html#//apple_ref/doc/uid/20000185-SW4
但是,据我所知和测试,那一天/时间不可能是绝对的。它基于 iPhone 日期/时间/时区,这可能是错误的。
【讨论】:
+1 完全正确。您应该编辑问题以反映具体问题并接受您自己的答案。【参考方案3】:使用 NSCalendar 和 setTimeZone
方法。
NSDate *newDate;
NSDateComponents *dateComponents = [[NSCalendar currentCalendar] components:~ NSTimeZoneCalendarUnit fromDate:[NSDate date]];
newDate = [[NSCalendar currentCalendar] dateFromComponents:dateComponents];
NSLog(@"newDate: %@", newDate);
NSLog(@"newDate: %.0f", [newDate timeIntervalSinceReferenceDate]);
新日期:2011-09-09 15:02:09 +0000 新日期:337273330
[dateComponents setTimeZone:[NSTimeZone timeZoneWithName:@"Australia/Sydney"]];
newDate = [[NSCalendar currentCalendar] dateFromComponents:dateComponents];
NSLog(@"newDate: %@", newDate);
NSLog(@"newDate: %.0f", [newDate timeIntervalSinceReferenceDate]);
新日期:2011-09-09 00:52:03 +0000 newTimeInterval:337222930
[dateComponents setTimeZone:[NSTimeZone timeZoneWithName:@"Europe/Paris"]];
newDate = [[NSCalendar currentCalendar] dateFromComponents:dateComponents];
NSLog(@"newDate: %@", newDate);
NSLog(@"newDate: %.0f", [newDate timeIntervalSinceReferenceDate]);
新日期:2011-09-09 08:52:03 +0000 新时间间隔:337251730
【讨论】:
这实际上是在创建一个与原始日期不同的新日期。 问题是:“将该日期放入 NSDate(或任何可以计算的内容,即不是字符串)” @CocoaFu :我在巴黎,将时区设置为 Europe/Paris 显示 2011-09-09 14:14:26 +0000。但现在是 16 点 18 分。我想我应该有类似 2011-09-09 16:14:26 +0200 的东西?如果它返回格林威治标准时间日期,那么设置太平洋/斐济等时区有什么需要? @Oliver NSDatedescription
方法返回 GMT 时间。请注意,2011-09-09 14:14:26 +0000
与 2011-09-09 16:14:26 +0200
的日期相同。要输出日期,您可以使用NSDateFormatter
。
@CocoaFu :看了又看又看,我终于开始觉得你的回答有一定的逻辑性但是是错误的。如果您所在的位置是“2011-09-09 15:02:09 +0000”,最后在巴黎得到的是“2011-09-09 08:52:03 +0000”,那么您似乎只是欺骗了日期。因为无论 NSlog 得到什么输出,它都不能在某个地方的 +0000 "15:02" 和其他地方的 "08:52"。以上是关于iPhone - 获取给定地点/时区的当前日期和时间并将其与同一地点的另一个日期/时间进行比较的正确方法的主要内容,如果未能解决你的问题,请参考以下文章