如何确定今天是否有NSDate?


156

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

我曾经使用中的前10个字符来检查它[aDate description][[aDate description] substringToIndex:10]返回类似"YYYY-MM-DD"的字符串,所以我将字符串与所返回的字符串进行了比较[[[NSDate date] description] substringToIndex:10]

有没有更快速和/或更整洁的检查方法?

谢谢。


我相信我的方法(实际上是我撰写本文时所用的唯一方法)实际上是指Apple的文档,并根据他们的建议进行操作,以确定两天是否相同。尽管其他方法可能有效,但我相信我的方法可以为将来提供更多证明。stackoverflow.com/a/17641925/901641
ArtOfWarfare 2013年

@ArtOfWarfare:我不同意。您的代码仍然需要处理时间间隔,但是Apple提供的方法已经解决了这一问题—请参阅:stackoverflow.com/a/17642033/106435
vikingosegundo

1
NSDate的“描述”方法以UTC格式显示日期,即格林威治标准时间,不校正夏令时。如果您在美国的傍晚或印度的清晨,则不会根据您的日历显示“今天”。您需要一个NSCalendar对象才能将NSDate转换为一天,并将当前日期转换为一天,然后进行比较。
gnasher729 2014年

Answers:


308

在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)

1
使用iOS 8 SDK进行检查
Catfish_Man 2014年

1
我对以上评论感到困惑,这绝对是iOS 8:-(BOOL)isDateInToday:(NSDate *)date NS_AVAILABLE(10_9,8_0);
powerj1984 2014年

是的,那是我说的。大概是以前的评论者通过查看iOS 7 SDK感到困惑。它有一个不同的声明。
Catfish_Man 2014年

对于“今天”,这是一个完美的答案:)
Daij-Djan

很好的答案!
Supertecnoboff

192

您可以比较日期成分:

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的方法,我认为它可以使if语句更简洁,更易理解:

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
}

克里斯,我已经采纳了你的建议。我必须查询一下什么时代,因此对于任何其他不知道的人,它可以区分BC和AD。对于大多数人来说,这可能是不必要的,但是它很容易检查并增加了确定性,因此我将其包括在内。如果您追求速度,那么这可能不是一个好方法。


注意,与SO上的许多答案一样,在7年后,这已经完全过时了。在Swift中,只需使用.isDateInToday


1
谢谢。我认为这是对我的问题更为简洁和未来安全的解决方案。
胜勋

1
我认为您也需要包括时代部分。我认为这是两种方法之间的一次折腾。isEqualToDate似乎更好,但似乎有点浪费,并且从组件重构日期的花费大约相同。
克里斯·佩奇

1
由于“ otherDay”和“ today”无论如何都只填充了这四个字段(这就是您所要求的全部),因此您可以使用[today equalTo:otherDay],而不必在第二个字段中跳过。
Glenn Maynard

@Glenn您是否建议我在第一个中比较NSDateComponents?我没有真正考虑过,但这似乎是一个好主意。
David Kanarek

1
@DavidKanarek挖掘旧帖子...我不建议直接比较日期组成部分,如果遇到需要抵消其中一个组成部分的情况,则可能会得到类似month == 3,day == 34的情况。转换为日期将正确地解释这是4月3日,在比较日期组件将不会认为这是同月== 4,一天== 3
肖恩Kladek

27

这是您问题的分支,但是如果您要使用“今天”或“昨天”来打印NSDate,请使用该功能

- (void)setDoesRelativeDateFormatting:(BOOL)b

对于NSDateFormatter


3
聪明的主意。但是我假设如果本地化,寻找字符串“ Today”会中断。
罗勒·布尔克

16

我将尝试将今天的日期归一化为午夜,将第二个日期归一化,归一化为午夜,然后比较是否是相同的NSDate。

Apple的示例中,这是如何规范化到今天的午夜日期,对第二个日期执行相同的操作并进行比较:

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

我认为您也需要包括时代。
克里斯·佩奇

难道不应该通过将时间设置为12来规范日期,即中午,而不是午夜吗?由于日期是格林尼治标准时间(GMT),因此将其设置为中午可确保两种时区的时差(并且仅两种时差都达到12h)不会“跳入”前一天或后一天。
artooras 2014年

13

由Catfish_Man建议的工作Swift 3和4扩展

extension Date {

    func isToday() -> Bool {
        return Calendar.current.isDateInToday(self)
    }

}

12

无需费心处理组件,时代和事物。

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
}

9
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)
}

在Swift 2.0上为我工作


6

Swift版本的最佳答案:

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
}

5

请参阅Apple文档标题为“执行日历计算”的文档条目[link]

该页面上的清单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。


2
请记住,时代确实从格林尼治标准时间00:00开始!如果其中一个日期(或两个日期)不在GMT时区中,则此方法可能无法正常工作。
Andreas Ley

5

您还可以检查您拥有的日期与当前日期之间的时间间隔:

[myDate timeIntervalSinceNow]

这将为您提供myDate和当前日期/时间之间的时间间隔(以秒为单位)。

链接

编辑:所有人注意:我很清楚[myDate timeIntervalSinceNow]不会明确确定myDate是否是今天。

我将原样保留此答案,以便如果某人正在寻找相似的东西并且[myDate timeIntervalSinceNow]有用,他们可能会在这里找到。


1
您说的是正确的,但间隔实际上并没有帮助检查日期是否为今天。
Jaanus 2010年

3
请记住,这是告诉您距现在是否在24小时之内,但不会告诉您日期是否相同。一秒的差异可以是不同的日期,而86399秒的差异可以是相同的日期。
大卫·卡纳雷克

@大卫:是的。在回答问题时我没有做其他事情,也没有想过,加载页面时也没有发布您的答案。
alesplin

1
这根本无法回答问题。您应该删除它。
vikingosegundo

1
这个答案不过是噪音。它既没有试图回答这个问题,也没有必要提及timeIntervalSinceNow它,因为它在许多其他职位中都涉及到。还可以通过比较秒数来处理日期比较,从而鼓励将错误易除以86400。– vikingosegundo 2014
6

4

Swift扩展基于最佳答案:

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)
    }
}

2

如果您有很多这样的日期比较,则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

谢谢你 对于我们的应用程序,可接受的方法过于占用CPU资源,因此我们需要对其进行优化。
Accatyyc

1
该代码将在夏令时失败。每个使用臭名昭著的数字86,400的代码的人都应该为此感到头痛。
vikingosegundo

2

有比上述答案更简单的方法!

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

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

1
与Catfish_Man的答案相同!
Thanh Pham

0

这可能可以作为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 );
}

(但是,像原始问题中那样比较两个日期字符串几乎感觉“更干净”。)


comps当立即将它们设置为零时,为什么要在创建时包括小时,分钟和秒?另外,我认为您需要包括时代。
克里斯·佩奇

请注意,虽然这几乎在每种情况下都可以使用,但还是有leap秒之类的事情。我不知道Apple的NSDate类是否或如何处理它们,但是有一定的可能性不起作用。这更像是“您知道吗”,而不是批评您的方法,因为它们极为罕见(历史上为24)。
David Kanarek

日期不是24小时,而是由于夏令时而变成23或25?
vikingosegundo

0

对于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 :-)");


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
}

-1

这是我的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
}

-3

我的解决方案是按除法计算自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);
}

这实际上不是一个不好的解决方案。不知道为什么这么低估。在校正了GMT之后,使用整数除法将截断其余部分,并仅长时间比较unix的“天”值。坦率地说,我认为这是最干净的解决方案。
devios1 2013年

1
@chaiguy:这是一个糟糕的解决方案,因为它假设每天有24小时之久-情况并非如此。由于夏令时,时间可能长达23、24或25小时。
vikingosegundo

嗯,是的。但是,每年的平均时间恰好是24小时,因此,我认为,最坏的情况只会使其减少一小时。也许可以明确检查。
devios1 2013年

2
@chaiguy:不。永远不要使用包含60 * 60 * 24的代码。或生活在头痛之中。
vikingosegundo

在世界上大多数地方,“ secondsFromGMT”每年都会突然更改两次。使用NSCalendar方法要安全得多。
gnasher729 2014年

-4
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;  
}  

4
这不会告诉您两个NSD日期是否是同一日期,哪一个是较早的日期,即使它们是同一天。
David Kanarek
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.