(iOS,Objective-C)在计算日期/时间时处理不同的时区

时间:2012-12-03 22:34:28

标签: objective-c timezone nsdate

2013年8月7日编辑:Apple拥有一套优秀的WWDC视频,真正帮助我了解Objective-C中的各种日期和时间类,以及如何正确地执行时间计算/操作。< /强>

“常见日期和时间挑战的解决方案”(HD videoSD videoslides (PDF))(WWDC 2013)
“执行日历计算”(SD videoslides (PDF))(WWDC 2011)

注意:链接需要免费的Apple Developer会员资格。

this SO question中,我问我如何计算某个日期和时间(“下周日下午5点”)。感谢我得到的答案,我想出了以下代码:

 - (NSDate *) toPacificTime
 {
     NSTimeZone *tz = [NSTimeZone timeZoneWithName:@"America/Los_Angeles"];
     NSInteger seconds = [tz secondsFromGMTForDate: self];
     return [NSDate dateWithTimeInterval: seconds sinceDate: self];
 }

 - (void)handleLiveShowReminders
 {
    NSDate *gmtNow = [NSDate date];
    NSDate *now = [gmtNow toPacificTime];

    NSCalendar *calendar = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
    [calendar setTimeZone:[NSTimeZone timeZoneWithName:@"America/Los_Angeles"]];
    NSDateComponents *dateComponents = [calendar components:NSWeekdayCalendarUnit fromDate:now];
    NSInteger weekday = [dateComponents weekday];

    NSInteger daysTillNextSunday = 8 - weekday;

    int secondsInDay = 86400; // 24 * 60 * 60
    NSDate *nextSunday = [now dateByAddingTimeInterval:secondsInDay * daysTillNextSunday];

    NSDateComponents *components = [calendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit fromDate:nextSunday];
    [components setHour:17];
    [components setMinute:00];
    [components setTimeZone:[NSTimeZone timeZoneWithName:@"America/Los_Angeles"]];
    NSDate *nextSunday5PM = [calendar dateFromComponents:components];

    warningInterval = -300;    // we want the notification to fire 5 minutes beforehand

    NSDate *alertDate = [nextSunday5PM dateByAddingTimeInterval:(NSTimeInterval)warningInterval];

    UILocalNotification* notifyAlarm = [[[UILocalNotification alloc] init] autorelease];
    if (notifyAlarm)
    {
        notifyAlarm.fireDate = alertDate;
        notifyAlarm.timeZone = [NSTimeZone timeZoneWithName:@"America/Los_Angeles"];    
        notifyAlarm.repeatInterval = NSWeekCalendarUnit;
        notifyAlarm.soundName = @"alert.aif";
        notifyAlarm.alertBody = @"LIVE SHOW REMINDER: The live show is about to start!";

        [[UIApplication sharedApplication] scheduleLocalNotification:notifyAlarm];
    }
 }

问题在于,虽然这段代码对我有用,但对于那些不在PST时区的人来说,它不起作用,我从EST的用户那里得到的这个调试输出可以看出:

number of notifications = 1

Notification #1
===================
Body: LIVE SHOW REMINDER: The live show is about to start!
Details: <UIConcreteLocalNotification: 0x1d5f2200>
{fire date = Sunday, December 9, 2012, 4:30:00 PM Pacific Standard Time,
time zone = America/Los_Angeles (PST) offset -28800,
repeat interval = NSWeekCalendarUnit
repeat count = UILocalNotificationInfiniteRepeatCount,
next fire date = Sunday, December 9, 2012, 4:30:00 PM Eastern Standard Time,
user info = (null)}

我在这里做错了什么?

2 个答案:

答案 0 :(得分:2)

您的逻辑存在一个问题,只是在您的时间间隔内添加86,400可能不是您想要的。例如,如果用户经历了夏令时,那么您将在一个小时之后离开,如果在午夜附近发生,则会关闭一天。更好的方法是向NSCalendar询问结果,该结果考虑了用户的本地时区。

NSDate *start = yourDate;
NSDateComponents *oneDay = [NSDateComponents new];
[oneDay setDay:1];

NSCalendar *cal = [NSCalendar currentCalendar];
NSDate *end = [cal dateByAddingComponents:oneDay toDate:start options:0];

答案 1 :(得分:0)

NSDate与UTC / GMT相关。当你在太平洋时间“调整”时,你会产生完全混乱。