How to determine if an NSDate is today?

72,553

Solution 1

In macOS 10.9+ & iOS 8+, there's a method on NSCalendar/Calendar that does exactly this!

- (BOOL)isDateInToday:(NSDate *)date 

So you'd simply do

Objective-C:

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

Swift 3:

let today = Calendar.current.isDateInToday(date)

Solution 2

You can compare date components:

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
}

Edit:

I like stefan's method more, I think it makes for a cleaner and more understandable if statement:

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
}

Chris, I've incorporated your suggestion. I had to look up what era was, so for anyone else who doesn't know, it distinguishes between BC and AD. This is probably unnecessary for most people, but it's easy to check and adds some certainty, so I've included it. If you're going for speed, this probably isn't a good method anyway.


NOTE as with many answers on SO, after 7 years this is totally out of date. In Swift now just use .isDateInToday

Solution 3

This is an offshoot to your question, but if you want to print an NSDate with "Today" or "Yesterday", use the function

- (void)setDoesRelativeDateFormatting:(BOOL)b

for NSDateFormatter

Solution 4

I would try to get today's date normalized to midnight and the second date, normalize to midnight then compare if it is the same NSDate.

From an Apple example here's how you normalize to midnight today's date, do the same for the second date and compare:

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

Solution 5

Working Swift 3 & 4 extension of the suggestion by Catfish_Man:

extension Date {

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

}
Share:
72,553

Related videos on Youtube

Seunghoon
Author by

Seunghoon

http://twitter.com/yeonsh Work experiences on Go, Python, C++, Objective-C, Java, Swift and Dart(Flutter) Learning: Haskell, Rust, Swift

Updated on July 25, 2020

Comments

  • Seunghoon
    Seunghoon almost 4 years

    How to check if an NSDate belongs to today?

    I used to check it using first 10 characters from [aDate description]. [[aDate description] substringToIndex:10] returns string like "YYYY-MM-DD" so I compared the string with the string returned by [[[NSDate date] description] substringToIndex:10].

    Is there more fast and/or neat way to check?

    Thanks.

    • ArtOfWarfare
      ArtOfWarfare almost 11 years
      I believe my method is the only one (as of my writing this) that actually refers to Apple's documentation and does what they suggest within it to determine if two days are the same. Although other methods may work, I believe my method is most future proof. stackoverflow.com/a/17641925/901641
    • vikingosegundo
      vikingosegundo almost 11 years
      @ArtOfWarfare: I disagree. Your code still needs to deal with time intervals, but apple provides methods that already factor this away — see: stackoverflow.com/a/17642033/106435
    • gnasher729
      gnasher729 about 10 years
      The NSDate "description" method displays the date in UTC format, that is Greenwich Mean Time, with no correction for daylight savings time. If you're late in the evening in the USA, or early in the morning in India, it will not display what is "today" according to your calendar. You need an NSCalendar object to translate the NSDate into a day, and to convert the current date into a day, then compare them.
  • Jaanus
    Jaanus about 14 years
    What you say is correct, but the interval doesn't really help to check if date is today.
  • Kirill
    Kirill about 14 years
    Just keep in mind that this is it tells you if you are within 24 hours since now, but not if the dates are the same. A one second difference can be different dates and a 86399 second difference can be the same date.
  • alesplin
    alesplin about 14 years
    @David: True. Didn't think about that as I was doing 3 other things while answering the question, and your answer wasn't posted when I loaded the page.
  • Seunghoon
    Seunghoon about 14 years
    Thanks. I think it is more neat and future-safe solution to my question.
  • Kirill
    Kirill about 13 years
    This doesn't tell you if both NSDates are the same date, just which one is earlier, even if they're the same day.
  • Chris Page
    Chris Page over 12 years
    Why include hours, minutes and seconds when creating comps when you're immediately setting them to zero? Also, I think you need to include the era.
  • Chris Page
    Chris Page over 12 years
    I think you need to include the era component, too. I think it's a coin toss between the two approaches; isEqualToDate seems nicer, but it seems a little wasteful and takes about the same number of lines to reconstruct a date from the components.
  • Chris Page
    Chris Page over 12 years
    I think you need to include the era, too.
  • Kirill
    Kirill over 12 years
    Please note that while this will work in almost every case, there are such things as leap seconds. I don't know if or how Apple's NSDate class handles them, but there is some chance this won't work. This is more a "did you know" rather than a criticism of your method as they're exceedingly rare (24 in history).
  • Accatyyc
    Accatyyc almost 12 years
    Thanks for this. The accepted way was way too CPU intensive for our app so we needed to optimize this.
  • Glenn Maynard
    Glenn Maynard over 11 years
    Since both "otherDay" and "today" only have those four fields filled anyway (that's all you requested), you can just use [today equalTo:otherDay], without jumping the hoops in the second one.
  • Kirill
    Kirill over 11 years
    @Glenn Are you suggesting I compare NSDateComponents in the first one? I hadn't really thought about that, but it also seems like a good idea.
  • Basil Bourque
    Basil Bourque over 11 years
    Clever idea. But I assume that looking for the string "Today" would break if you localize.
  • Sean Kladek
    Sean Kladek about 11 years
    @DavidKanarek Digging up old posts...I wouldn't recommend comparing date components directly, if you get into a situation where you need to offset one of the components, you may get something like month == 3, day == 34. Converting to dates will correctly interpret this as April 3, comparing date components will not see this as the same as month == 4, day == 3.
  • devios1
    devios1 almost 11 years
    That's actually not a bad solution. Not sure why it was so downvoted. Using integer division will cut off the remainder and compare just the "days" value of the unix long time, after correcting for GMT. I think this is the cleanest solution of them all to be quite frank.
  • Andreas Ley
    Andreas Ley almost 11 years
    Bear in mind that an Era does start at 00:00 GMT! This method might not work correctly if one of the dates (or both) are not in the GMT timezone.
  • vikingosegundo
    vikingosegundo over 10 years
    what about dates that are not 24 hours long, but 23 or 25 due to Daylight Saving Times?
  • vikingosegundo
    vikingosegundo over 10 years
    @chaiguy: this is a bad solution as it assumes, that each day is 24 hours long — what is not the case. Due to Daylight Saving Times days can be 23, 24 or 25 hours long.
  • devios1
    devios1 over 10 years
    Hmm that's true. However the average per year is exactly 24 hours, so it will only potentially be off by one hour worst case, as I see it. Perhaps that could be checked for explicitly.
  • vikingosegundo
    vikingosegundo over 10 years
    @chaiguy: no. just never use a code that contains 60*60*24. or live with your headache.
  • vikingosegundo
    vikingosegundo over 10 years
    This does not answer the question at all. You should delete it.
  • vikingosegundo
    vikingosegundo over 10 years
    This code will fail for daylight saving times. Everybody using code with the infamous number 86,400 deserve the headache it may cause.
  • alesplin
    alesplin over 10 years
    I'm not inclined to do so, given that at the very least it doesn't contain anything that is going to cause harm (unlike some of the other 'magic number' answers below). It's obviously not correct or complete, but it could be an approach that may prove useful to someone doing something similar that happens across it.
  • gnasher729
    gnasher729 about 10 years
    Actually, two NSDates that are 86399 + 3600 seconds apart can be on the same day, but only once a year.
  • gnasher729
    gnasher729 about 10 years
    "secondsFromGMT" changes abruptly twice a year in most places in the world. Much safer to use the NSCalendar methods.
  • artooras
    artooras almost 10 years
    Shouldn't a date be normalised by setting time to 12, i.e. midday, not midnight? Since date is in GMT, setting it to midday ensures that time zone variations both ways (and they go up to 12h only both ways) does not 'jump' into the day before or after.
  • vikingosegundo
    vikingosegundo almost 10 years
    This answer is nothing but noise. It does neither attempt to answer the question nor is it necessary to refer to timeIntervalSinceNow as it is covered in many other posts. Also handling day comparison with checking for seconds encourage error-prone division by 86400.
  • Catfish_Man
    Catfish_Man almost 10 years
    Check using the iOS 8 SDK
  • Nurbol
    Nurbol over 9 years
    I'm confused by the above comment, this is definitely iOS 8: - (BOOL)isDateInToday:(NSDate *)date NS_AVAILABLE(10_9, 8_0);
  • Catfish_Man
    Catfish_Man over 9 years
    Yes, that's what I said. The previous commenter was confused by looking at the iOS 7 SDK, presumably. It had a different declaration.
  • Daij-Djan
    Daij-Djan almost 8 years
    for 'today' this is the perfect answer :)
  • Thanh Pham
    Thanh Pham over 7 years
    Same as Catfish_Man's answer!
  • Supertecnoboff
    Supertecnoboff over 5 years
    Excellent answer!