如何创建代表下一个指定日期时间的完整 NSDate 对象?

Posted

技术标签:

【中文标题】如何创建代表下一个指定日期时间的完整 NSDate 对象?【英文标题】:How can I create a complete NSDate object that represents the next specified day time? 【发布时间】:2010-08-11 04:22:25 【问题描述】:

我可能没有把这个标题说得足够清楚,但是如果用户指定了下午 2:30 的时间,而现在是下午 2:00,那么我需要一个 NSDate 对象来表示当天的时间为下午 2:30 .如果用户指定了下午 2:30 的时间并且当前是下午 3:00,那么我需要一个 NSDate 对象来表示明天的时间为下午 2:30。类似于闹钟的工作原理。

我已经写了这段代码,但它太长了,感觉很笨拙,我觉得它应该更简单,但我是 ios 开发和这个特定 API 的新手。

非常感谢您的帮助!

【问题讨论】:

【参考方案1】:

您是否已经有一个 NSDate 代表用户选择的日期/时间?如果是这样,将其与现在进行比较(通过earlierDate:laterDate:)并在一天后创建一个新的(通过dateWithTimeInterval:sinceDate:initWithTimeInterval:sinceDate:)是一件非常简单的事情。

类似这样的:

// Assume dateTarget is an NSDate representing the date/time the user picked.
// Is it earlier than now?
if( [dateTarget earlierDate:[NSDate date]] == dateTarget ) 
    // dateTarget is earlier than now.
    // Add 1 day to it.
    NSDate* newDate = [[NSDate alloc]initWithTimeInterval:60*60*24 sinceDate:dateTarget];
    [dateTarget release];
    dateTarget = newDate;


// dateTarget is now either the original time, or if that time passed, the same time tomorrow.
NSLog( @"dateTarget = %@", dateTarget );

【讨论】:

【参考方案2】:

我相信,如果您添加的时间间隔会在夏令时日期前后出现混乱。增加一天的秒数将在一天后结束,但会提前或推迟一个小时。我很确定我以前遇到过这种情况,但我猜你可以轻松测试。

另一种方法是使用 NSDateComponents:

// using while will be inefficient when the targetDate is more than a few days in the past
while ([targetDate compare:[NSDate date]] == NSOrderedAscending) 
    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSInteger units = NSYearCalendarUnit |
                      NSMonthCalendarUnit |
                      NSDayCalendarUnit |
                      NSHourCalendarUnit |
                      NSMinuteCalendarUnit |
                      NSSecondCalendarUnit;
    NSDateComponents *comps = [calendar components:units fromDate:targetDate];
    [comps setDay:[comps day] + 1]; // if day is 32 for instance, it'll automatically roll over to the next month
    NSDate *targetDate = [calendar dateFromComponents:comps];

以上绝不是一个理想的解决方案(例如,如果您保留它,它会泄漏 targetDate),但主要是为了向您展示如何使用 NSDateComponents 为 NSDate 添加 1 天。

【讨论】:

【参考方案3】:

假设用户使用UIDatePicker 选择日期,我会这样做:

NSDate * selectedDate = ...; //2:30pm
NSDate * selectedComponents = [[NSCalendar currentCalendar] components:(NSHourCalendarUnit | NSMinuteCalendarUnit) fromDate:selectedDate];

NSDate * now = [NSDate date];
NSDate * nowComponents = [[NSCalendar currentCalendar] components:NSUIntegerMax fromDate:now];

[nowComponents setHour:[selectedComponents hour]];
[nowComponents setMinute:[selectedComponents minute]];

NSDate * targetDate = [[NSCalendar currentCalendar] dateFromComponents:nowComponents];
if ([[now laterDate:targetDate] isEqual:now]) 
  //in a comparison between now and the target date, the target date has already passed
  [nowComponents setDay:[nowComponents day]+1];
  targetDate = [[NSCalendar currentCalendar] dateFromComponents:nowComponents];


//target date is now at the appropriate 2:30pm

旁注:由于NSCalendarUnitNSUInteger 的位域类型定义,我传入NSUIntegerMax 以检索所有可能的日历单位。这样我就不必有大量的按位 OR 语句。

【讨论】:

给你的问题:如果你现在做Components setDay: day + 1,那一天是否重要,比如32?例如,如果 day 是一个月的最后一天?还是一切都会自己解决? @SeanDanzeiser -dateFromComponents: 将处理单元翻转。【参考方案4】:

如果你从用户那里得到 userDate 和 nowDate = [NSDate date] ,那么

NSComparisonResult diff = [userDate compare: nowDate];

如果 diff 是NSOrderedDescending,那么 userDate 比 nowDate 晚,你设置了今天的闹钟。如果是NSOrderedAscending,那么你设置明天的闹钟。你可以测试NSOrderedSame,但它永远不会。

您不想确定今天是哪一天,所以在我看来,添加 NSTimeInterval 的差异加上 24 * 60 * 60(如果闹钟是明天)或只是差异(如果闹钟是今天)就足够了。

我不知道为什么每个人都在尝试制作闹钟。据我所知,这是不可能的。

【讨论】:

有了iOS 4和本地通知,闹钟就可以搞定了。 你不应该使用 24 * 60 * 60 来表示一天,使用 NSDateComponents 和 NSCalendar 来添加 1 天。如果你使用硬编码的时间间隔,你最终会遇到一堆边缘情况,例如如果夏令时结束,您的“明天”时间将减少一个小时。

以上是关于如何创建代表下一个指定日期时间的完整 NSDate 对象?的主要内容,如果未能解决你的问题,请参考以下文章

如何计算不同时区的两个 NSDate 对象之间的天数差异?

如何创建过去的新 NSDate 对象,例如比另一个日期早 1 秒?

如何为 NSDate 添加 1 天?

如何在 NSArray 中检查 NSDate yyyy/mm/dd 并进行比较?

NSDate 创建没有时间元素的日期的最佳实践

NSDate/NSCalendar 问题