如何确定一个 NSDate 是今天?

如何检查 NSDate是否属于今天?

我过去常常使用 [aDate description]中的前10个字符来检查它。[[aDate description] substringToIndex:10]返回类似于 "YYYY-MM-DD"的字符串,因此我将该字符串与 [[[NSDate date] description] substringToIndex:10]返回的字符串进行了比较。

是否有更快捷和/或更简洁的检查方法?

谢谢。

73092 次浏览

您可以比较日期组件:

NSDateComponents *otherDay = [[NSCalendar currentCalendar] components:NSCalendarUnitEra | NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay fromDate:aDate];
NSDateComponents *today = [[NSCalendar currentCalendar] components:NSCalendarUnitEra | NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay fromDate:[NSDate date]];
if([today day] == [otherDay day] &&
[today month] == [otherDay month] &&
[today year] == [otherDay year] &&
[today era] == [otherDay era]) {
//do stuff
}

编辑:

我更喜欢 Stefan 的方法,我觉得这样更干净,也更容易理解:

NSCalendar *cal = [NSCalendar currentCalendar];
NSDateComponents *components = [cal components:(NSCalendarUnitEra | NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay) fromDate:[NSDate date]];
NSDate *today = [cal dateFromComponents:components];
components = [cal components:(NSCalendarUnitEra | NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay) fromDate:aDate];
NSDate *otherDate = [cal dateFromComponents:components];


if([today isEqualToDate:otherDate]) {
//do stuff
}

克里斯,我采纳了你的建议。我必须查一下那个时代是什么,所以对于其他不知道的人来说,它区分了公元前和公元前。对于大多数人来说,这可能是不必要的,但是它很容易检查并增加一些确定性,所以我把它包括进来了。如果你追求速度,这可能不是一个好的方法。


和很多关于 SO 的回答一样,7年过去了,这个问题已经完全过时了。在 Swift 中,现在只需使用 .isDateInToday

我会尝试将今天的日期标准化为午夜和第二个日期,标准化为午夜然后比较,如果它是相同的 NSDate。

一个苹果的例子开始,下面是如何将今天的日期正常化到午夜,对第二次约会做同样的事情,然后进行比较:

NSCalendar * gregorian = [[NSCalendar alloc]
initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents * components =
[gregorian components:
(NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit)
fromDate:[NSDate date]];
NSDate * today = [gregorian dateFromComponents:components];

这可能会被重新编写为 NSDate 类别,但我使用了:

// Seconds per day (24h * 60m * 60s)
#define kSecondsPerDay 86400.0f


+ (BOOL) dateIsToday:(NSDate*)dateToCheck
{
// Split today into components
NSCalendar* gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents* comps = [gregorian components:(NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit|NSHourCalendarUnit|NSMinuteCalendarUnit|NSSecondCalendarUnit)
fromDate:[NSDate date]];


// Set to this morning 00:00:00
[comps setHour:0];
[comps setMinute:0];
[comps setSecond:0];
NSDate* theMidnightHour = [gregorian dateFromComponents:comps];
[gregorian release];


// Get time difference (in seconds) between date and then
NSTimeInterval diff = [dateToCheck timeIntervalSinceDate:theMidnightHour];
return ( diff>=0.0f && diff<kSecondsPerDay );
}

(然而,比较原问题中的两个日期字符串感觉更“干净”... ...)

NSDate *dateOne = yourDate;
NSDate *dateTwo = [NSDate date];


switch ([dateOne compare:dateTwo])
{
case NSOrderedAscending:
NSLog(@”NSOrderedAscending”);
break;


case NSOrderedSame:
NSLog(@”NSOrderedSame”);
break;


case NSOrderedDescending:
NSLog(@”NSOrderedDescending”);
break;
}

这是您问题的一个分支,但是如果您想打印带有“今天”或“昨天”的 NSDate,请使用该函数

- (void)setDoesRelativeDateFormatting:(BOOL)b

用于 NSDateFormatter

如果你有很多这样的日期比较,那么调用 calendar:components:fromDate开始占用很多时间。根据我做的一些侧写,它们似乎相当昂贵。

假设你试图从一些日期数组(比如 NSArray *datesToCompare)中确定哪一天与某一天(比如 NSDate *baseDate)是同一天,那么你可以使用下面这样的方法(部分改编自上面的答案) :

NSDate *baseDate = [NSDate date];


NSArray *datesToCompare = [NSArray arrayWithObjects:[NSDate date],
[NSDate dateWithTimeIntervalSinceNow:100],
[NSDate dateWithTimeIntervalSinceNow:1000],
[NSDate dateWithTimeIntervalSinceNow:-10000],
[NSDate dateWithTimeIntervalSinceNow:100000],
[NSDate dateWithTimeIntervalSinceNow:1000000],
[NSDate dateWithTimeIntervalSinceNow:50],
nil];


// determine the NSDate for midnight of the base date:
NSCalendar* calendar = [NSCalendar currentCalendar];
NSDateComponents* comps = [calendar components:(NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit)
fromDate:baseDate];
NSDate* theMidnightHour = [calendar dateFromComponents:comps];


// set up a localized date formatter so we can see the answers are right!
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
[dateFormatter setTimeStyle:NSDateFormatterMediumStyle];


// determine which dates in an array are on the same day as the base date:
for (NSDate *date in datesToCompare) {
NSTimeInterval interval = [date timeIntervalSinceDate:theMidnightHour];
if (interval >= 0 && interval < 60*60*24) {
NSLog(@"%@ is on the same day as %@", [dateFormatter stringFromDate:date], [dateFormatter stringFromDate:baseDate]);
}
else {
NSLog(@"%@ is NOT on the same day as %@", [dateFormatter stringFromDate:date], [dateFormatter stringFromDate:baseDate]);
}
}

产出:

Nov 23, 2011 1:32:00 PM is on the same day as Nov 23, 2011 1:32:00 PM
Nov 23, 2011 1:33:40 PM is on the same day as Nov 23, 2011 1:32:00 PM
Nov 23, 2011 1:48:40 PM is on the same day as Nov 23, 2011 1:32:00 PM
Nov 23, 2011 10:45:20 AM is on the same day as Nov 23, 2011 1:32:00 PM
Nov 24, 2011 5:18:40 PM is NOT on the same day as Nov 23, 2011 1:32:00 PM
Dec 5, 2011 3:18:40 AM is NOT on the same day as Nov 23, 2011 1:32:00 PM
Nov 23, 2011 1:32:50 PM is on the same day as Nov 23, 2011 1:32:00 PM

我的解决方案是通过除法计算自1970年以来过了多少天,然后比较整数部分

#define kOneDay (60*60*24)
- (BOOL)isToday {
NSInteger offset = [[NSTimeZone defaultTimeZone] secondsFromGMT];


NSInteger days =[self timeIntervalSince1970] + offset;
NSInteger currentDays = [[NSDate date] timeIntervalSince1970] + offset;
return (days / kOneDay == currentDays / kOneDay);
}

参考苹果的文档条目“执行日历计算”[链接]

该页面上的清单13表明,要确定白天之间的午夜数,可以使用:

- (NSInteger)midnightsFromDate:(NSDate *)startDate toDate:(NSDate *)endDate
{
NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar];
NSInteger startDay = [calendar ordinalityOfUnit:NSDayCalendarUnit
inUnit:NSEraCalendarUnit
forDate:startDate];
NSInteger endDay = [calendar ordinalityOfUnit:NSDayCalendarUnit
inUnit:NSEraCalendarUnit
forDate:endDate];
return endDay - startDay;
}

然后,您可以通过使用该方法并查看它是否返回0来确定两天是否相同。

没必要在零件,纪元和其他东西上做文章。

NSCalendar 提供了一种方法来获取现有日期的某个时间单元的开头。

这段代码将获得今天的开始和另一个日期,并进行比较。如果计算结果为 NSOrderedSame,那么两个日期都在同一天,所以今天。

NSDate *today = nil;
NSDate *beginningOfOtherDate = nil;


NSDate *now = [NSDate date];
[[NSCalendar currentCalendar] rangeOfUnit:NSDayCalendarUnit startDate:&today interval:NULL forDate:now];
[[NSCalendar currentCalendar] rangeOfUnit:NSDayCalendarUnit startDate:&beginningOfOtherDate interval:NULL forDate:beginningOfOtherDate];


if([today compare:beginningOfOtherDate] == NSOrderedSame) {
//otherDate is a date in the current day
}

在 macOS 10.9 + & iOS 8 + 中,NSCalendar/Calendar 上有一个方法可以做到这一点!

- (BOOL)isDateInToday:(NSDate *)date

所以你只需要

目标 C:

BOOL today = [[NSCalendar currentCalendar] isDateInToday:date];

斯威夫特3:

let today = Calendar.current.isDateInToday(date)

IOS7及更早版本:

//this is now => need that for the current date
NSDate * now = [NSDate date];


NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
[calendar setTimeZone:[NSTimeZone systemTimeZone]];


NSDateComponents * components = [calendar components:( NSYearCalendarUnit|    NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit) fromDate: now];


[components setMinute:0];
[components setHour:0];
[components setSecond:0];


//this is Today's Midnight
NSDate *todaysMidnight = [calendar dateFromComponents: components];






//now timeIntervals since Midnight => in seconds
NSTimeInterval todayTimeInterval = [now timeIntervalSinceDate: todaysMidnight];


//now timeIntervals since OtherDate => in seconds
NSTimeInterval otherDateTimeInterval = [now timeIntervalSinceDate: otherDate];


if(otherDateTimeInterval > todayTimeInterval) //otherDate is not in today
{
if((otherDateTimeInterval - todayTimeInterval) <= 86400) //86400 == a day total seconds
{
@"yesterday";
}
else
{
@"earlier";
}
}
else
{
@"today";
}




now = nil;
calendar = nil;
components = nil;
todaysMidnight = nil;


NSLog("Thank you :-)");

检查我们的 Erica Sadun 的大 NSDate extension。非常简单的使用。罚款在这里:

Http://github.com/erica/nsdate-extensions

它已经在这篇文章中出现了: https://stackoverflow.com/a/4052798/362310

最佳答案的快速版本:

let cal = NSCalendar.currentCalendar()
var components = cal.components([.Era, .Year, .Month, .Day], fromDate:NSDate())
let today = cal.dateFromComponents(components)!


components = cal.components([.Era, .Year, .Month, .Day], fromDate:aDate);
let otherDate = cal.dateFromComponents(components)!


if(today.isEqualToDate(otherDate)) {
//do stuff
}

下面是我的2美分答案,它建立在公认的答案之上,同时也支持更新的 API。注意: 我使用公历,因为大多数时间戳是格林尼治标准时间,但改变你的,因为你认为合适

func isDateToday(date: NSDate) -> Bool {
let calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!
if calendar.respondsToSelector("isDateInToday:") {
return calendar.isDateInToday(date)
}
let dateComponents = NSCalendarUnit.CalendarUnitYear | NSCalendarUnit.CalendarUnitMonth | NSCalendarUnit.CalendarUnitDay
let today = calendar.dateFromComponents(calendar.components(dateComponents, fromDate: NSDate()))!
let dateToCompare = calendar.dateFromComponents(calendar.components(dateComponents, fromDate: date))!


return dateToCompare == today
}

基于最佳答案的快速扩展:

extension NSDate {
func isToday() -> Bool {
let cal = NSCalendar.currentCalendar()
if cal.respondsToSelector("isDateInToday:") {
return cal.isDateInToday(self)
}
var components = cal.components((.CalendarUnitEra | .CalendarUnitYear | .CalendarUnitMonth | .CalendarUnitDay), fromDate:NSDate())
let today = cal.dateFromComponents(components)!


components = cal.components((.CalendarUnitEra | .CalendarUnitYear | .CalendarUnitMonth | .CalendarUnitDay), fromDate:self);
let otherDate = cal.dateFromComponents(components)!
return today.isEqualToDate(otherDate)
}
}
extension NSDate {
func isToday() -> Bool {
let cal = NSCalendar.currentCalendar()
var components = cal.components([.Era, .Year, .Month, .Day], fromDate:NSDate())
let today = cal.dateFromComponents(components)!


components = cal.components([.Era, .Year, .Month, .Day], fromDate:self)
let otherDate = cal.dateFromComponents(components)!


return today.isEqualToDate(otherDate)
}

我在斯威夫特2.0版就是这么做的

正确和安全的解决方案,不需要强制拆封,可以在 Swift 2.2和 iOS 8之前使用:

func isToday() -> Bool {
let calendar = NSCalendar.currentCalendar()
if #available(iOS 8.0, *) {
return calendar.isDateInToday(self)
}


let todayComponents = calendar.components([.Era, .Year, .Month, .Day], fromDate:NSDate())
let dayComponents = calendar.components([.Era, .Year, .Month, .Day], fromDate:self)


guard let today = calendar.dateFromComponents(todayComponents),
day = calendar.dateFromComponents(dayComponents) else {
return false
}


return today.compare(day) == .OrderedSame
}

有一个比上述许多答案更简单的方法!

NSDate *date = ... // The date you wish to test
NSCalendar *calendar = [NSCalendar currentCalendar];


if([calendar isDateInToday:date]) {
//do stuff
}

Catfish _ Man 建议的工作 迅速扩展:

extension Date {


var isToday: Bool {
Calendar.current.isDateInToday(self)
}
    

}