Holen Sie sich NSDate heute, gestern, diese Woche, letzte Woche, diesen Monat, letzten Monat ... Variablen

86

Ich versuche, NSDate heute, gestern, diese Woche, letzte Woche, diesen Monat, letzten Monat Variablen zum Vergleich bereit zu machen, damit Header in UITableViews titleForHeaderInSection hinzugefügt werden können

Was ich möchte, wird manuell im folgenden Code für das Datum 2009-12-11 ausgeführt

 NSDate *today = [NSDate dateWithString:@"2009-12-11 00:00:00 +0000"];
 NSDate *yesterday = [NSDate dateWithString:@"2009-12-10 00:00:00 +0000"];
 NSDate *thisWeek = [NSDate dateWithString:@"2009-12-06 00:00:00 +0000"];
 NSDate *lastWeek = [NSDate dateWithString:@"2009-11-30 00:00:00 +0000"];
 NSDate *thisMonth = [NSDate dateWithString:@"2009-12-01 00:00:00 +0000"];
 NSDate *lastMonth = [NSDate dateWithString:@"2009-11-01 00:00:00 +0000"];
hasnat
quelle

Antworten:

93

Angepasst aus dem Programmierhandbuch für Datum und Uhrzeit :

// Right now, you can remove the seconds into the day if you want
NSDate *today = [NSDate date];

// All intervals taken from Google
NSDate *yesterday = [today dateByAddingTimeInterval: -86400.0];
NSDate *thisWeek  = [today dateByAddingTimeInterval: -604800.0];
NSDate *lastWeek  = [today dateByAddingTimeInterval: -1209600.0];

// To get the correct number of seconds in each month use NSCalendar
NSDate *thisMonth = [today dateByAddingTimeInterval: -2629743.83];
NSDate *lastMonth = [today dateByAddingTimeInterval: -5259487.66];

Wenn Sie die richtige genaue Anzahl von Tagen je nach Monat wünschen, sollten Sie eine verwenden NSCalendar.

Ben S.
quelle
77
Feste Konstanten für die Zeit sind BAD BAD BAD. Was ist mit Schalttagen oder Schaltsekunden? Verwenden Sie NSDateComponents, da sonst einige sehr unangenehme und schwer zu debuggende Probleme auftreten, wenn Ihre Datumsstempel nicht mehr übereinstimmen.
Kendall Helmstetter Gelner
11
Es ist wirklich nicht so schlimm, wenn Sie nur ungefähr die Posts der letzten Woche oder was auch immer wollen. Ich habe angegeben, dass das OP verwendet werden soll, NSCalendarwenn Genauigkeit erforderlich ist.
Ben S
2
Feste Konstanten sollten für das Zählen von Tagen eigentlich in Ordnung sein: Jeder Tag ist 86400 Sekunden. Schaltsekunden dauern einfach doppelt so lange - ein Tag mit einer Schaltsekunde hat immer noch 86400 Sekunden. Wie für Monate ... ja lenken klar :)
Chris
3
@ Chris, außer wenn die Tage nicht 86400 Sekunden sind. Was ist mit der Sommerzeit? Es klingt unbedeutend, aber dies kann tatsächlich zu extrem knorrigen Fehlern führen, die nirgendwo auftauchen, wenn die Sommerzeit eintritt, und Sie haben nicht daran gedacht, dies zu berücksichtigen.
Jpswain
1
Wenn Sie nur ungefähr 7 Tage zurückgehen möchten, können Sie einfach die Zeit subtrahieren. Wenn Sie zu 'Montag' dieser Woche zurückkehren möchten, verwenden Sie NSCalendar. Für beide Szenarien gibt es Anwendungsfälle.
Johnny Rockex
83

Könnte ein besserer Weg sein, dies zu schreiben, aber hier, was ich auf Bens NSCalendar-Vorschlag und die Arbeit von dort an NSDateComponents kam

NSCalendar *cal = [NSCalendar currentCalendar];
NSDateComponents *components = [cal components:( NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond ) fromDate:[[NSDate alloc] init]];

[components setHour:-[components hour]];
[components setMinute:-[components minute]];
[components setSecond:-[components second]];
NSDate *today = [cal dateByAddingComponents:components toDate:[[NSDate alloc] init] options:0]; //This variable should now be pointing at a date object that is the start of today (midnight);

[components setHour:-24];
[components setMinute:0];
[components setSecond:0];
NSDate *yesterday = [cal dateByAddingComponents:components toDate: today options:0];

components = [cal components:NSWeekdayCalendarUnit | NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit fromDate:[[NSDate alloc] init]];

[components setDay:([components day] - ([components weekday] - 1))]; 
NSDate *thisWeek  = [cal dateFromComponents:components];

[components setDay:([components day] - 7)];
NSDate *lastWeek  = [cal dateFromComponents:components];

[components setDay:([components day] - ([components day] -1))]; 
NSDate *thisMonth = [cal dateFromComponents:components];

[components setMonth:([components month] - 1)]; 
NSDate *lastMonth = [cal dateFromComponents:components];

NSLog(@"today=%@",today);
NSLog(@"yesterday=%@",yesterday);
NSLog(@"thisWeek=%@",thisWeek);
NSLog(@"lastWeek=%@",lastWeek);
NSLog(@"thisMonth=%@",thisMonth);
NSLog(@"lastMonth=%@",lastMonth);
hasnat
quelle
13
Mit diesen fromDate:[[NSDate alloc] init]Bits verlieren Sie überall Speicher .
Shaggy Frog
21
@ Shaggy Frog: Ich denke, er geht davon aus, dass ARC aktiviert ist ...;)
orj
3
Dieser Code funktioniert nicht richtig. Die Sekundenbruchteile, die Teil des Eingabedatums sind, werden nicht berücksichtigt. Das heißt, das Datum könnte 30,1234 Sekunden haben, und die NSDateComponents haben nur 30 als Sekundenwert. Wenn Sie also 30 Sekunden vom NSDate abziehen, haben Sie 0,1234 Sekunden nach Mitternacht. Außerdem haben einige Tage mehr (oder weniger) als 24 Stunden (Sommerzeit), sodass für das Abrufen des gestrigen Datums wirklich [Komponenten setDay: -1] anstelle von [Komponenten setHour: -24] verwendet werden sollte.
Orj
5
@orj FYI, ARC kam Alter heraus, nachdem diese Antwort veröffentlicht wurde
Shaggy Frog
3
@orj Auch bei Änderungen der Sommerzeit gibt Ihnen das Subtrahieren der Stunden keine Mitternacht. -1. Dieser Code ist keine 35 Upvotes wert.
Nikolai Ruhe
40

NSDateComponents ist heute schön zu bekommen:

NSCalendar *cal = [NSCalendar currentCalendar];

NSDate *date = [NSDate date];
NSDateComponents *comps = [cal components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) 
                                                          fromDate:date];
NSDate *today = [cal dateFromComponents:comps];

Dadurch wird ein NSDate mit nur Jahr, Monat und Datum erstellt:

(gdb) po today
2010-06-22 00:00:00 +0200

Um gestern usw. zu bekommen, können Sie es mit NSDateComponents berechnen:

NSDateComponents *components = [[NSDateComponents alloc] init];
[components setDay:-1];
NSDate *yesterday = [cal dateByAddingComponents:components toDate:today options:0];
Christian Beer
quelle
Müssen Sie die Ära-Komponente nicht einbeziehen?
Chris Seite
Nett. Verwendet dies, um ein Datum in 8 Jahren in der Vergangenheit zu berechnen und es funktioniert gut. Hier muss nur ein Leck behoben werden: [[NSDateComponents alloc] init];
Craig B
@CraigB danke. Es soll kein vollständiges Beispiel sein. Das offensichtliche Speichermanagement als Herausforderung für den Leser ausgelassen;)
Christian Beer
@ChrisPage die Ära-Komponente? Wozu?
Christian Beer
1
@ChristianBeer Ich bin mir ziemlich sicher, dass alle Komponenten berücksichtigt werden müssen, die größer als die gewünschte Auflösung sind. Ich glaube (NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit)sollte sein (NSEraCalendarUnit | NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit).
Chris Seite
19
+ (NSDate*)dateFor:(enum DateType)dateType {

    NSCalendar *calendar = [NSCalendar currentCalendar];

    NSDateComponents *comps =
    [calendar components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit
                fromDate:[NSDate date]];

    if(dateType == DateYesterday) {

        comps.day--;
    }
    else if(dateType == DateThisWeek) {

        comps.weekday = 1;
    }
    else if(dateType == DateLastWeek) {

        comps.weekday = 1;
        comps.week--;
    }
    else if(dateType == DateThisMonth) {

        comps.day = 1;
    }
    else if(dateType == DateLastMonth) {

        comps.day = 1;
        comps.month--;
    }
    else if(dateType != DateToday)
        return nil;

    return [calendar dateFromComponents:comps];
}
Dustin
quelle
Müssen Sie die Ära-Komponente nicht einbeziehen?
Chris Seite
Ich musste NSDayCalendarUnit entfernen und NSWeekdayCalendarUnit hinzufügen, wenn ich DateLastWeek berechnete.
Jessecurry
Apple hat die Definition von NSWeekdayCalendarUnit und NSDayCalendarUnit um iOS 5.0 geändert. Der neue Weg ist die Verwendung von NSWeekdayCalendarUnit. Bei älteren Versionen müssen Sie jedoch NSDayCalendarUnit verwenden. Es ist ein Durcheinander ...
Dustin
@Dustin Es scheint nicht zu funktionieren, selbst wenn auf neue Einheiten aktualisiert wird ... Zum Beispiel DateThisWeekhat das Festlegen des Wochentags keine Auswirkungen auf das NSDate ...
AnthoPak
11

Swift 4.2

let today = Date()
let yesterday = today.addingTimeInterval(-86400.0)
let thisWeek = today.addingTimeInterval(-604800.0)
let lastWeek = today.addingTimeInterval(-1209600.0)

let thisMonth = today.addingTimeInterval(-2629743.83)
let lastMonth = today.addingTimeInterval(-5259487.66)

// components of the date
let calendar = Calendar(identifier: Calendar.Identifier.gregorian)
let components = calendar.dateComponents([.year, .month, .day], from: today)
let (year, month, day) = (components.year, components.month, components.day)

Bitte beachten Sie, dass Datumskomponenten optional sind.

Gokhanakkurt
quelle
1
@fengd gut, Heute, 27. Juni 2016, um 1 Uhr morgens, ist der 28. Juni 2016, und wenn ich 24 Stunden abziehe, ist das Datum der 27. Juni, 1 Uhr morgens. Was ist der Punkt, den ich verpasst habe?
Gokhanakkurt
1
Entschuldigung, @gokhanakkurt. Ich glaube, ich hatte Schluckauf. Ihre Antwort ist richtig
fengd
4

Die anderen Antworten haben bei mir einfach nicht funktioniert (möglicherweise aufgrund meiner Zeitzone). So mache ich es:

- (BOOL)isOnThisWeek:(NSDate *)dateToCompare
{
    NSCalendar * calendar = [NSCalendar currentCalendar];
    NSDate     * today    = [NSDate date];

    int todaysWeek        = [[calendar components: NSWeekCalendarUnit fromDate:today] week];
    int dateToCompareWeek = [[calendar components: NSWeekCalendarUnit fromDate:dateToCompare] week];

    int todaysYear         = [[calendar components:NSYearCalendarUnit fromDate:today] year];
    int dateToCompareYear  = [[calendar components:NSYearCalendarUnit fromDate:dateToCompare] year];

    if (todaysWeek == dateToCompareWeek && todaysYear == dateToCompareYear) {
        return YES;
    }

    return NO;
}
Lucas
quelle
4

Wenn Sie iOS 10+ oder MacOS 10.12+ verwenden, können Sie diese beiden CalendarMethoden verwenden, um dies ordnungsgemäß durchzuführen .

  • func date(byAdding component: Calendar.Component, value: Int, to date: Date, wrappingComponents: Bool = default) -> Date?( docs )
  • func dateInterval(of component: Calendar.Component, for date: Date) -> DateInterval?( docs )

Hier ist ein Beispiel für die Verwendung dieser Methoden in Swift 3 sowie die Ausgabe der Spielplätze in meiner Zeitzone.

let calendar = Calendar.current
let now = Date()
// => "Apr 28, 2017, 3:33 PM"

let yesterday = calendar.date(byAdding: .day, value: -1, to: now)
// => "Apr 29, 2017, 3:33 PM"
let yesterdayStartOfDay = calendar.startOfDay(for: yesterday!)
// => ""Apr 29, 2017, 12:00 AM"

let thisWeekInterval = calendar.dateInterval(of: .weekOfYear, for: now)
// => 2017-04-23 04:00:00 +0000 to 2017-04-30 04:00:00 +0000

let thisMonthInterval = calendar.dateInterval(of: .month, for: now)
// => 2017-04-01 04:00:00 +0000 to 2017-05-01 04:00:00 +0000

let aDateInLastWeek = calendar.date(byAdding: .weekOfYear, value: -1, to: now)
let lastWeekInterval = calendar.dateInterval(of: .weekOfYear, for: aDateInLastWeek!)
// => 2017-04-16 04:00:00 +0000 to 2017-04-23 04:00:00 +0000

let aDateInLastMonth = calendar.date(byAdding: .month, value: -1, to: now)
let lastMonthInterval = calendar.dateInterval(of: .weekOfYear, for: aDateInLastMonth!)
// => 2017-03-26 04:00:00 +0000 to 2017-04-02 04:00:00 +0000

Bonus: Mit dem DateIntervals können Sie testen, ob ein Datum in diesen Bereich fällt. Fortsetzung von oben:

thisWeekInterval!.contains(now)
// => true
lastMonthInterval!.contains(now)
// => false
yood
quelle
Warum steht dort der yesterday29. April und der now28. April?
Juan Boero
1
NSDate *today = [NSDate date]; // Today's date
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *weekdayComponents =[gregorian componentsNSDayCalendarUnit | NSWeekdayCalendarUnit) fromDate:today];
NSInteger day = [weekdayComponents day];
Hayden
quelle
0

Das in diesem Projekt enthaltene THCalendarInfo-Objekt gefällt mir sehr gut:

http://github.com/jaredholdcroft/kcalendar

Ich kann das Original nicht ganz finden. Mit diesem Objekt können Sie zu einem vorherigen Tag, dem Beginn einer Woche, dem Beginn eines Monats, dem Wochentag, dem Monatstag usw. usw. wechseln.

Kendall Helmstetter Gelner
quelle
0
NSDate *today = [[NSDate alloc] initWithTimeIntervalSinceNow:0];
Tischel
quelle
14
Warum nicht [NSDate date]?
Joshpaul
Da beide gültig sind, um das aktuelle Datum abzurufen, enthalten beide die Uhrzeit. Es ist also nicht die richtige Lösung für die Frage!
Christian Beer
0

Dies dient zur Überprüfung des Datums in diesem Monat oder nicht

func isOnThisMonth(dateToCompare: NSDate) -> Bool {
    let calendar: NSCalendar = NSCalendar.currentCalendar()
    let today: NSDate = NSDate()
    let todaysWeek: Int = calendar.components(NSCalendarUnit.Month, fromDate: today).month
    let dateToCompareWeek: Int = calendar.components(.Month, fromDate: dateToCompare).month
    let todaysYear: Int = calendar.components(NSCalendarUnit.Year, fromDate: today).year
    let dateToCompareYear: Int = calendar.components(NSCalendarUnit.Year, fromDate: dateToCompare).year
    if todaysWeek == dateToCompareWeek && todaysYear == dateToCompareYear {
        return true
    }
    return false
}

Und zweitens ändern Sie nur den Typ der Kalendereinheit für schwache wie diese

func isOnThisWeek(dateToCompare: NSDate) -> Bool {
    let calendar: NSCalendar = NSCalendar.currentCalendar()
    let today: NSDate = NSDate()
    let todaysWeek: Int = calendar.components(NSCalendarUnit.Weekday, fromDate: today).weekday
    let dateToCompareWeek: Int = calendar.components(.Weekday, fromDate: dateToCompare).weekday
    let todaysYear: Int = calendar.components(NSCalendarUnit.Year, fromDate: today).year
    let dateToCompareYear: Int = calendar.components(NSCalendarUnit.Year, fromDate: dateToCompare).year
    if todaysWeek == dateToCompareWeek && todaysYear == dateToCompareYear {
        return true
    }
    return false
}

Ich hoffe das ist hilfreich für jemanden Danke.

Ilesh P.
quelle
0

Ich antwortete eine ähnliche Frage bereits und ist hier, warum meine Antwort ist besser:

  • Swift 3 !
  • Verwendet DateFormatters "Yesterday" und "Today". Dies wurde bereits von Apple übersetzt, was Ihnen Arbeit erspart!
  • Verwendet die bereits übersetzte Zeichenfolge "1 Woche" von DateComponentsFormatter. (Wieder weniger Arbeit für Sie, mit freundlicher Genehmigung von Apple.) Sie müssen lediglich die Zeichenfolge "% @ before" übersetzen. 🙂
  • Die anderen Antworten berechnen fälschlicherweise die Zeit, zu der der Tag von "heute" zu "gestern" zu usw. wechselt. Feste Konstanten sind aus Gründen ein großes NEIN-NEIN . Außerdem verwenden die anderen Antworten das aktuelle Datum / die aktuelle Uhrzeit, wenn das Ende des Datums / der Uhrzeit des aktuellen Tages verwendet werden soll.
  • Verwendet autoupdatingCurrent für Kalender und Gebietsschema, um sicherzustellen, dass Ihre App sofort mit den Kalender- und Spracheinstellungen des Benutzers in Settings.app auf dem neuesten Stand ist
ChrisJF
quelle