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

Posted

技术标签:

【中文标题】NSDate 创建没有时间元素的日期的最佳实践【英文标题】:NSDate best practice in creating a date with no time element 【发布时间】:2010-12-01 15:49:46 【问题描述】:

我正在编写一个使用核心数据来存储我的数据的应用程序。其中包括一个日期字段,我只对日期而不是时间感兴趣。 我需要根据日期(而不是时间)选择记录,因此我在 NSDate 上创建了一个类别以返回日期,标准化为设定时间,如下所示:

+ (NSDate *)dateWithNoTime:(NSDate *)dateTime 
if( dateTime == nil ) 
    dateTime = [NSDate date];

NSDateComponents* comps = [[NSCalendar currentCalendar] components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit fromDate:dateTime];
NSDate *dateOnly = [[NSCalendar currentCalendar] dateFromComponents:comps];
[dateOnly dateByAddingTimeInterval:(60.0 * 60.0 * 12.0)];           // Push to Middle of day.
return dateOnly;

然后我在向核心数据存储添加数据时使用它(我有一个使用此方法设置原始日期值的设置器),然后我使用此方法创建一个用于比较日期的日期执行获取请求时。所以理论上这应该总是有效的 - 即选择我正在寻找的日期。

我有点紧张,因为我不完全确定更改时区或语言环境会产生什么影响。还能用吗?

仅当您对时间不感兴趣时​​,才在日期上存储和搜索时被认为是最佳做法。

干杯。

编辑

阅读推荐的讨论后,我认为我应该修改我的代码如下。想法是,如果我确保将其推送到特定的日历系统和特定的时区 (UTC),那么无论您在哪里设置日期和阅读日期,日期都应该始终相同。对此新代码的任何 cmet 表示赞赏。

+ (NSDate *)dateWithNoTime:(NSDate *)dateTime 
if( dateTime == nil ) 
    dateTime = [NSDate date];


NSCalendar       *calendar   = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
[calendar setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]];
NSDateComponents *components = [[[NSDateComponents alloc] init] autorelease];
components = [calendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit
                         fromDate:dateTime];

NSDate *dateOnly = [calendar dateFromComponents:components];

[dateOnly dateByAddingTimeInterval:(60.0 * 60.0 * 12.0)];           // Push to Middle of day.
return dateOnly;

【问题讨论】:

感谢您的解决方案!! :D 稍微更正一下:行:[dateOnly dateByAddingTimeInterval:(60.0 * 60.0 * 12.0)]; 应该是:dateOnly = [dateOnly dateByAddingTimeInterval:(60.0 * 60.0 * 12.0)]; 【参考方案1】:

这里有几个问题需要处理。首先,正如您所指出的,时区。您还需要担心夏令时,它会改变“中午”的概念。

查看 CocoaDev 上的 this discussion,其中 Apple 工程师会给出一些答案并讨论一些最佳实践。

【讨论】:

谢谢。在阅读了该讨论之后,我似乎应该确保我始终使用相同的日历系统和时区进行存储和比较。基于这种新想法,我在我的问题中添加了新代码。【参考方案2】:

一个更简单的解决方案是使用一个谓词来查找特定范围内的日期。

使用 NSCalendarComponent 为您的“日”创建开始日期和结束日期,然后将它们包含在谓词中。

NSPredicate *p=[NSPredicate predicateWithFormat:@"$@ <= date <= $@",startDate,endDate];

这将提供最大的灵活性,而不会太复杂。日期和时间编程看似复杂。准备做一些工作。

【讨论】:

【参考方案3】:

我还遇到了一个需要NSDate 来比较日期而不考虑时间的情况。

我有一个过滤机制,并且作为 UI 的一部分,如果用户选择今天作为开始日期和结束日期的最小日期,我将显示“所有时间段”而不是格式中的字符串:

2006 年 1 月 5 日 - 2009 年 12 月 24 日

所以我需要使用+dateNSDate 获取今天的日期,并将其与结束日期进行比较。该结束日期来自设置为无时间的UIDatePicker,但+date 返回了现在的日期和时间。

所以我写了这个简短的方便的方法,它接收一个日期对象,使用NSDateComponentsNSCalendar 类来提取日、月和年。

然后使用这三个参数创建一个新的NSDate 使用NSDateFormatter's -dateFromString: 方法,结果是一个NSDate 对应于与参数相同的“日期”(在传统的人类概念中) date 但没时间。

- (NSDate *)strictDateFromDate:(NSDate *)date
    NSUInteger flags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit;
    NSDateComponents *components = [[NSCalendar currentCalendar] components:flags
                                                                   fromDate:[NSDate date]];
    NSString *stringDate = [NSString stringWithFormat:@"%d/%d/%d", components.day, components.month, components.year];

    NSDateFormatter *formatter = [[[NSDateFormatter alloc] init] autorelease];
    formatter.dateFormat = @"dd/MM/yyyy";

    return [formatter dateFromString:stringDate];

希望您以后可以使用和享受此功能。

【讨论】:

以上是关于NSDate 创建没有时间元素的日期的最佳实践的主要内容,如果未能解决你的问题,请参考以下文章

通过视图模型接收 DateTime 输入的最佳实践是啥?

将时间分区添加到表的最佳实践

初始化日期时间值同时避免代码重复的最佳实践

bson.json_util 日期时间编码和解码最佳实践

查询日期:“dateval LIKE '2014-01-01%'”是最佳实践吗? [复制]

BigQuery 表设计最佳实践:日期分区和分片的组合?