Bir NSDate'in bugün olup olmadığını nasıl belirleyebilirim?


156

NSDateBugünün ait olup olmadığını nasıl kontrol edebilirim ?

İlk 10 karakterini kullanarak kontrol ederdim [aDate description]. [[aDate description] substringToIndex:10]dize "YYYY-MM-DD"tarafından döndürülen dize ile karşılaştırıldığında ben dize döndürür [[[NSDate date] description] substringToIndex:10].

Kontrol etmenin daha hızlı ve / veya temiz bir yolu var mı?

Teşekkürler.


Benim yöntemimin, Apple'ın belgelerine atıfta bulunan ve iki gün aynı olup olmadığını belirlemek için önerdiklerini yapan tek yöntem olduğuna inanıyorum. Diğer yöntemler işe yarayabilse de, yöntemimin gelecekteki kanıt olduğuna inanıyorum. stackoverflow.com/a/17641925/901641
ArtOfWarfare

@ArtOfWarfare: Kabul etmiyorum. Kodunuzun hala zaman aralıklarıyla uğraşması gerekiyor, ancak elma bunu zaten faktör olarak etkileyen yöntemler sunuyor - bkz: stackoverflow.com/a/17642033/106435
vikingosegundo

1
NSDate "description" yöntemi tarihi UTC biçiminde, yani Greenwich Ortalama Saat biçiminde görüntüler, gün ışığından yararlanma saati için düzeltme yapmaz. ABD'de akşam geç veya Hindistan'da sabah erken saatlerde, takviminize göre "bugün" ne olduğunu göstermez. NSDate'i bir güne çevirmek ve geçerli tarihi bir güne dönüştürmek, sonra bunları karşılaştırmak için bir NSCalendar nesnesine ihtiyacınız vardır.
gnasher729

Yanıtlar:


308

MacOS 10.9+ ve iOS 8+ sürümlerinde NSCalendar / Calendar'da tam olarak bunu yapan bir yöntem vardır!

- (BOOL)isDateInToday:(NSDate *)date 

Yani basitçe yapardın

Objective-C:

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

Hızlı 3:

let today = Calendar.current.isDateInToday(date)

1
İOS

1
Yukarıdaki yorum ile kafam karıştı, bu kesinlikle iOS 8: - (BOOL) isDateInToday: (NSDate *) tarih NS_AVAILABLE (10_9, 8_0);
powerj1984

Evet, ben de öyle dedim. Önceki yorumcu, muhtemelen iOS 7 SDK'sına bakarak karışıktı. Farklı bir beyanı vardı.
Catfish_Man

'bugün' için bu mükemmel bir cevap :)
Daij-Djan

Mükemmel cevap!
Supertecnoboff

192

Tarih bileşenlerini karşılaştırabilirsiniz:

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
}

Düzenle:

Stefan'ın yöntemini daha çok seviyorum, daha temiz ve daha anlaşılır bir if ifadesi yapar:

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, önerinizi ekledim. Dönemin ne olduğunu araştırmak zorunda kaldım, bu yüzden bilmeyen herkes için BC ve AD arasında ayrım yapar. Bu muhtemelen çoğu insan için gereksizdir, ancak kontrol edilmesi kolaydır ve biraz kesinlik ekler, bu yüzden dahil ettim. Hız için gidiyorsanız, bu muhtemelen iyi bir yöntem değildir.


NOT SO'daki birçok cevapta olduğu gibi, 7 yıl sonra bu tamamen güncel değil. Swift'te şimdi sadece.isDateInToday


1
Teşekkürler. Sorumun daha temiz ve geleceğe yönelik bir çözüm olduğunu düşünüyorum.
Seunghoon

1
Bence dönem bileşenini de eklemeniz gerekiyor. İki yaklaşım arasında bir bozuk para olduğunu düşünüyorum; isEqualToDate daha hoş görünüyor, ancak biraz savurgan görünüyor ve bileşenlerden bir tarih oluşturmak için yaklaşık aynı sayıda satır alıyor.
Chris Page

1
Hem "otherDay" hem de "bugün" yalnızca bu dört alanı zaten doldurduğundan (talep ettiğiniz tek şey budur), ikincisine çember atlamaksızın [bugün eşittir: otherDay] kullanabilirsiniz.
Glenn Maynard

@Glenn İlki NSDateComponents karşılaştırmak öneririz? Bunu gerçekten düşünmemiştim, ama aynı zamanda iyi bir fikir gibi görünüyor.
David Kanarek

1
@DavidKanarek Eski yazıları kazmak ... Tarih bileşenlerini doğrudan karşılaştırmanızı önermem, bileşenlerden birini dengelemeniz gereken bir duruma girerseniz, month == 3, day == 34 gibi bir şey alabilirsiniz. Tarihlere dönüştürmek bunu 3 Nisan olarak doğru bir şekilde yorumlayacak, tarih bileşenlerini karşılaştırmak bunu ay == 4, gün == 3 ile aynı şekilde
görmeyecek

27

Bu, sorunuzun bir bölümüdür, ancak "Bugün" veya "Dün" ile bir NSDate yazdırmak istiyorsanız, işlevi kullanın

- (void)setDoesRelativeDateFormatting:(BOOL)b

NSDateFormatter için


3
Zekice fikir. Ancak, "Bugün" dizesini aramanın yerelleştirdiğinizde kırılacağını varsayıyorum.
Basil Bourque

16

Bugünün tarihini gece yarısına ve ikinci tarihe normalleştirmeye, gece yarısına normalleşmeye ve aynı NSDate olup olmadığını karşılaştırmaya çalışacağım.

Gönderen bir Apple Örneğin burada ikinci tarih ve karşılaştırmak için nasıl normal hale gece yarısı bugünün tarihine yapmak aynı şey:

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

Bence dönemi de dahil etmeniz gerekiyor.
Chris Page

Bir tarih, saatin gece yarısı değil, 12 olarak ayarlanmasıyla normalleştirilmemelidir? Tarih GMT'de olduğundan, gün ortası olarak ayarlanması, saat dilimi değişikliklerinin her iki yönde de (ve yalnızca her iki yönde de 12 saate kadar çıkmasını) önceki güne veya güne 'sıçramamasını' sağlar.
artooras

13

Catfish_Man tarafından yapılan önerinin çalışma Swift 3 ve 4 uzantısı :

extension Date {

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

}

12

Bileşenler, dönemler ve diğer şeylerle dengelemeye gerek yok.

NSCalendar, mevcut bir tarih için belirli bir zaman biriminin başlangıcını almak için bir yöntem sağlar.

Bu kod bugünün başlangıcını ve başka bir tarihi alır ve karşılaştırır. Değerlendirilirse NSOrderedSame, her iki tarih de aynı gündür - bugün.

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'da benim için çalıştı


6

En iyi cevabın hızlı versiyonu:

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'ın "Takvim Hesaplamaları Gerçekleştirme" [link] başlıklı belge girişine bakın .

Bu sayfadaki 13 numaralı liste, günler arasındaki gece yarısı sayısını belirlemenizi önerir:

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

Daha sonra, bu yöntemi kullanarak ve 0 döndürüp döndürmediğini görerek iki günün aynı olup olmadığını belirleyebilirsiniz.


2
Bir dönemin 00: 00'da başlayacağını unutmayın! Tarihlerden biri (veya her ikisi) GMT saat diliminde değilse bu yöntem düzgün çalışmayabilir.
Andreas Ley

5

Ayrıca, sahip olduğunuz tarih ile geçerli tarih arasındaki zaman aralığını da kontrol edebilirsiniz:

[myDate timeIntervalSinceNow]

Bu, myDate ile geçerli tarih / saat arasındaki zaman aralığını saniye cinsinden verecektir.

bağlantı .

Düzenleme: Not herkese: Ben de [myDate timeIntervalSinceNow] açıkça myDate bugün olup olmadığını belirlemek olmadığını biliyorum.

Birisi benzer bir şey arıyorsa ve [myDate timeIntervalSinceNow] faydalıysa, bu yanıtı bırakıyorum.


1
Söyledikleriniz doğru, ancak aralık, tarihin bugün olup olmadığını kontrol etmeye gerçekten yardımcı olmuyor.
Jaanus

3
Bunun şu andan itibaren 24 saat içinde olup olmadığınızı söyleyeceğini, ancak tarihlerin aynı olup olmadığını unutmayın. Bir saniyelik fark farklı tarihler olabilir ve 86399 saniyelik fark aynı tarih olabilir.
David Kanarek

@David: Doğru. Soruyu cevaplarken 3 şey daha yaptığım gibi düşünmedim ve sayfayı yüklediğimde cevabınız gönderilmedi.
alesplin

1
Bu soruya hiç cevap vermiyor. Silmelisiniz.
vikingosegundo

1
Bu cevap gürültüden başka bir şey değildir. Soruyu cevaplamaya çalışmaz ve timeIntervalSinceNowdiğer birçok yayında ele alındığı için başvurmak gerekli değildir . Ayrıca saniye kontrolü ile gün karşılaştırması,
86400'e kadar

4

En iyi yanıtlara dayalı Swift Uzantısı:

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

Bu tarih karşılaştırmalarının çoğuna sahipseniz, çağrılar calendar:components:fromDateçok zaman almaya başlar. Yaptığım bazı profillemelere göre oldukça pahalı görünüyorlar.

Diyelim ki, belirli bir tarih dizisinden hangilerinin NSArray *datesToComparebelirli bir günle aynı gün olduğunu belirlemeye çalışıyorsunuz , diyelim ki NSDate *baseDate, aşağıdaki gibi bir şey kullanabilirsiniz (yukarıdaki cevaba kısmen uyarlanmış):

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

Çıktı:

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

Bunun için teşekkürler. Kabul edilen yol, uygulamamız için çok fazla CPU yoğundu, bu yüzden bunu optimize etmemiz gerekiyordu.
Accatyyc

1
Bu kod yaz saati uygulamasında başarısız olur. Tanınmayan 86,400 numaralı kodu kullanan herkes, neden olabileceği baş ağrısını hak ediyor.
vikingosegundo

2

Yukarıdaki cevapların çoğundan daha kolay bir yolu var!

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

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

1
Catfish_Man'ın cevabı ile aynı!
Thanh Pham

0

Bu muhtemelen bir NSDate kategorisi olarak elden geçirilmiş olabilir, ancak kullandım:

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

(Bununla birlikte, orijinal tarihte olduğu gibi iki tarih dizesini karşılaştırmak neredeyse 'daha temiz' hisseder ..)


compsHemen sıfıra ayarlarken neden oluştururken saat, dakika ve saniye eklemelisiniz? Ayrıca, dönemi eklemeniz gerektiğini düşünüyorum.
Chris Page

Bu hemen hemen her durumda işe yarayacaktır, ancak artık saniye gibi şeyler olduğunu lütfen unutmayın. Apple'ın NSDate sınıfının bunları idare edip etmediğini veya nasıl ele aldığını bilmiyorum, ancak bunun işe yarama ihtimali var. Bu, son derece nadir oldukları için (tarihte 24) yönteminize yönelik bir eleştiriden ziyade "biliyor muydunuz".
David Kanarek

24 saat uzun olmayan, ancak 23 ya da 25 gün ışığından yararlanma saatleri ne olacak?
vikingosegundo

0

iOS7 ve öncesi için:

//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

Zorla açmadan, Swift 2.2 ve iOS 8'den önce çalışan doğru ve güvenli çözüm:

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

İşte benim kabul edilen yanıta dayalı, ancak daha yeni API'yı destekleyen 2 sentlik yanıtım. Not: Çoğu zaman damgası GMT olduğu için Gregoryen takvimini kullanıyorum, ancak uygun gördüğünüzde kendinizinkini değiştiriyorum

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

Benim çözümüm 1970'den bu yana kaç gün geçtiğini hesaplamak ve tamsayı kısmını karşılaştırmak.

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

Aslında kötü bir çözüm değil. Neden bu kadar indirgendiğinden emin değilim. Tamsayı bölmesinin kullanılması, geri kalan kısmı kesecek ve GMT için düzeltmeden sonra unix'in sadece "günler" değerini uzun süre karşılaştıracaktır. Bence bu oldukça açık ve net bir çözüm.
devios1

1
@chaiguy: Bu, her günün 24 saat uzunluğunda olduğu varsayıldığı gibi kötü bir çözümdür - durum böyle değildir. Yaz Saati nedeniyle günler 23, 24 veya 25 saat uzunluğunda olabilir.
vikingosegundo

Hmm bu doğru. Bununla birlikte, yıllık ortalama tam 24 saattir, bu yüzden gördüğüm gibi, potansiyel olarak sadece bir saat en kötü durumda kapalı olacaktır. Belki de bu açıkça kontrol edilebilir.
devios1

2
@chaiguy: hayır. sadece 60 * 60 * 24 içeren bir kod kullanmayın. veya baş ağrınızla yaşayın.
vikingosegundo

"secondsFromGMT" dünyanın birçok yerinde yılda iki kez aniden değişir. NSCalendar yöntemlerini kullanmak için çok daha güvenli.
gnasher729

-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
Bu, her iki NSDate'in aynı tarih olup olmadığını, aynı gün olsalar bile, hangisinin daha erken olduğunu söylemez.
David Kanarek
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.