NSDateが今日であるかどうかを判断する方法は?


156

NSDateが今日のものであるかどうかを確認するにはどうすればよいですか?

以前はからの最初の10文字を使用して確認していました[aDate description][[aDate description] substringToIndex:10]のように文字列を返す"YYYY-MM-DD"ので、文字列をによって返された文字列と比較しました[[[NSDate date] description] substringToIndex:10]

チェックするためのより高速かつ/またはきちんとした方法はありますか?

ありがとう。


私の方法は、(これを書いている時点で)実際にAppleのドキュメントを参照し、2日間が同じかどうかを判断するためにその中で提案している唯一の方法だと思います。他の方法も機能する可能性はありますが、私の方法は最も将来の証明になると思います。stackoverflow.com/a/17641925/901641
ArtOfWarfare 2013

@ArtOfWarfare:同意しません。コードは引き続き時間間隔を処理する必要がありますが、アップルはすでにこれを考慮しないメソッドを提供しています—参照:stackoverflow.com/a/17642033/106435
vikingosegundo

1
NSDateの「説明」メソッドは、夏時間の補正なしで、グリニッジ標準時であるUTC形式で日付を表示します。アメリカの夕方、またはインドの早朝の場合、カレンダーによると「今日」の内容は表示されません。NSDateを日に変換し、現在の日付を日に変換して比較するNSCalendarオブジェクトが必要です。
gnasher729 2014年

回答:


308

macOS 10.9以降とiOS 8以降では、NSCalendar / Calendarにこれを正確に行うメソッドがあります!

- (BOOL)isDateInToday:(NSDate *)date 

だからあなたは単にやります

Objective-C:

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

スウィフト3:

let today = Calendar.current.isDateInToday(date)

1
iOS 8 SDKを使用して確認する
Catfish_Man '8/07/17

1
上記のコメントに混乱しています。これは間違いなくiOS 8です。-(BOOL)isDateInToday:(NSDate *)date NS_AVAILABLE(10_9、8_0);
powerj1984 14

はい、それは私が言ったことです。以前のコメント投稿者は、おそらくiOS 7 SDKを見て混乱していました。別の宣言がありました。
Catfish_Man 2014

「今日」のためこれは完全な答えです:)
Daij-Djan '19

正解です。
Supertecnoboff 2018年

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
}

編集:

私はステファンの方法がもっと好きです、それはよりクリーンで理解しやすい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
}

クリス、あなたの提案を取り入れました。私は時代を調べなければならなかったので、知らない人のために、紀元前と西暦を区別しています。これはおそらくほとんどの人にとって不必要ですが、簡単に確認でき、確実性が高まるので、ここに含めました。あなたがスピードを求めているなら、おそらくこれはとにかく良い方法ではありません。


NOTE SO上で多くの答えとしては、7年後にこれは完全に時代遅れです。Swiftでは今ちょうど使う.isDateInToday


1
ありがとう。私の質問に対するそれは、よりきちんとした将来の安全な解決策だと思います。
Seunghoon、

1
eraコンポーネントも含める必要があると思います。これは、2つのアプローチの間のコイントスだと思います。isEqualToDateの方が見栄えは良いですが、少し無駄があり、コンポーネントから日付を再構築するのにほぼ同じ行数を要します。
クリスページ

1
「otherDay」と「today」のどちらも、とにかくこれらの4つのフィールドのみが入力されているため(要求したのはそれだけです)、2番目のフープにジャンプすることなく、[today equalTo:otherDay]を使用できます。
Glenn Maynard

@Glenn最初のNSDateComponentsを比較することを提案していますか?それについてはあまり考えていませんでしたが、良い考えのようにも思えます。
David Kanarek

1
@DavidKanarek古い投稿を掘り下げる...日付コンポーネントを直接比較することはお勧めしません。コンポーネントの1つをオフセットする必要がある場合、月== 3、日== 34の​​ような結果になる可能性があります。日付に変換することは正しく、月と同じ== 4日== 3としてこれを見ることはありません日付コンポーネントを比較し、4月3日としてこれを解釈します
ショーンKladek

27

これはあなたの質問の派生ですが、「今日」または「昨日」を含むNSDateを印刷する場合は、関数を使用します

- (void)setDoesRelativeDateFormatting:(BOOL)b

NSDateFormatter


3
賢いアイデア。しかし、ローカライズすると、文字列 "Today"を探すと壊れてしまうと思います。
Basil Bourque

16

今日の日付を真夜中に正規化して2番目の日付を取得し、真夜中に正規化してから、同じNSDateであるかどうかを比較しようとします。

Appleの例から今日の日付を真夜中に正規化し、2番目の日付についても同じようにして比較すると、次のようになります。

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 14

13

ワーキング・スウィフト3&4拡張 Catfish_Manの提案の:

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のドキュメントエントリ[リンク]を参照してください

そのページのリスト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;
}

次に、そのメソッドを使用して2日が同じかどうかを判断し、それが0を返すかどうかを確認します。


2
時代はGMTの00:00に始まることに注意してください。日付のいずれか(または両方)がGMTタイムゾーンにない場合、この方法は正しく機能しない可能性があります。
Andreas Ley 2013

5

あなたが持っている日付と現在の日付の間の時間間隔をチェックすることもできます:

[myDate timeIntervalSinceNow]

これにより、myDateと現在の日付/時刻の間の秒単位の時間間隔がわかります。

リンク

編集:全員への注意:[myDate timeIntervalSinceNow]はmyDateが今日であるかどうかを明確に決定しないことをよく知っています。

私はこの答えをそのまま残しているので、誰かが同様の何かを探していて、[myDate timeIntervalSinceNow]が役に立つ場合、ここで見つけることができます。


1
あなたが言うことは正しいですが、間隔は日付が今日であるかどうかを確認するのに本当に役立ちません。
Jaanus 2010

3
これは、現在から24時間以内であるかどうかを通知しますが、日付が同じである場合は通知しないことを覚えておいてください。1秒の差は異なる日付である可能性があり、86399秒の差は同じ日付である可能性があります。
デビッドカナレク2010

@David:True。質問に答えている間に私が他に3つのことをしていて、ページをロードしたときにあなたの答えが投稿されなかったので、それについては考えませんでした。
alesplin 2010

1
これは質問にまったく答えません。削除してください。
vikingosegundo 2013年

1
この答えはノイズに他なりません。timeIntervalSinceNow他の多くの投稿で取り上げられているため、質問への回答を試みたり、言及する必要はありません。また秒間チェックして一日の比較を扱うには、86400でエラーが発生しやすい部門を奨励
vikingosegundo

4

最良の回答に基づくSwift Extension:

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 2012

1
このコードは夏時間では失敗します。悪名高い86,400のコードを使用している人は誰でも、それが引き起こす可能性のある頭痛に値します。
vikingosegundo 2013年

2

上記の答えの多くよりも簡単な方法があります!

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

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

1
Catfish_Manの回答と同じです。
Thanh Pham 2016

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

(ただし、元の質問のように2つの日付文字列を比較すると、ほとんど「クリーン」に感じられます。)


compsすぐにゼロに設定するときに、作成時に時間、分、秒を含めるのはなぜですか?また、時代を含める必要があると思います。
クリスペイジ

これはほとんどすべての場合に機能しますが、うるう秒などがあることに注意してください。AppleのNSDateクラスがそれらをどのように処理するかはわかりませんが、これが機能しない可能性があります。これは非常にまれであるため(過去24か所)、メソッドに対する批判というよりは、「知っていましたか」という意味です。
David Kanarek

24時間ではなく、夏時間のために23または25の日付はどうでしょうか。
vikingosegundo 2013年

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もサポートしています。注:ほとんどのタイムスタンプはGMTなのでグレゴリオ暦を使用しますが、必要に応じて変更してください

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:これは、1日が24時間であると想定しているので、悪い解決策です。夏時間のため、日数は23、24、または25時間になることがあります。
vikingosegundo 2013年

そうですね。ただし、1年あたりの平均は正確に24時間であるため、私が見る限り、最悪の場合でも1時間だけずれている可能性があります。おそらくそれを明示的にチェックすることができます。
devios1 2013年

2
@chaiguy:いいえ。60 * 60 * 24を含むコードを使用しないでください。またはあなたの頭痛と一緒に住んでいます。
vikingosegundo 2013年

「secondsFromGMT」は、世界のほとんどの場所で年に2回突然変化します。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
これは、両方のNSDateが同じ日付であるかどうかを知らせません。たとえ同じ日であっても、どちらが早いかだけです。
デビッド・カナレク
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.