ottieni NSDate oggi, ieri, questa settimana, la settimana scorsa, questo mese, lo scorso mese ... variabili


86

Sto cercando di fare è ottenere NSDate oggi, ieri, questa settimana, la scorsa settimana, questo mese, le variabili del mese scorso pronte per il confronto per le intestazioni da aggiungere su titleForHeaderInSection di UITableView

Quello che voglio è fatto manualmente nel codice qui sotto per la data 2009-12-11

 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"];

Risposte:


93

Adattato dalla Guida alla programmazione di data e ora :

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

Se vuoi il numero esatto corretto di giorni a seconda del mese, dovresti usare un file NSCalendar.


77
Le costanti fisse per il tempo sono BAD BAD BAD. Che dire dei giorni bisestili o dei secondi intercalari? Usa NSDateComponents o soffrirai di problemi molto sgradevoli e difficili da eseguire il debug quando i timbri della data iniziano a non corrispondere.
Kendall Helmstetter Gelner,

11
Non è poi così male se vuoi solo circa i post dell'ultima settimana o altro. Ho specificato che l'OP dovrebbe usare NSCalendarse l'esattezza era richiesta.
Ben S,

2
Le costanti fisse dovrebbero andare bene per il conteggio dei giorni: ogni giorno è 86400 secondi. I secondi intercalari richiedono semplicemente il doppio del tempo: un giorno con un secondo intercalare ha ancora 86400 "secondi". Per quanto riguarda i mesi ... sì, stai alla larga :)
Chris

3
@Chris tranne quando i giorni non sono 86400 secondi. E l'ora legale? Sembra insignificante, ma questo può effettivamente portarti a bug super nodosi che non escono dal nulla quando arriva l'ora legale e non ti sei ricordato di tenerne conto.
jpswain

1
Se vuoi solo tornare indietro diciamo 7 giorni circa, puoi semplicemente sottrarre il tempo, se vuoi tornare al "lunedì" di questa settimana, usa NSCalendar. Esistono casi d'uso per entrambi gli scenari.
Johnny Rockex

83

Potrebbe essere un modo migliore per scrivere questo, ma ecco cosa mi è venuto in mente sul suggerimento di NSCalendar di Ben e lavorando da lì a NSDateComponents

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

13
Stai perdendo memoria dappertutto con quei fromDate:[[NSDate alloc] init]bit.
Shaggy Frog

21
@Shaggy Frog: Immagino che stia assumendo che ARC sia abilitato ...;)
orj

3
Questo codice non funziona correttamente. Non tiene conto delle frazioni di secondo che fanno parte della data di input. Cioè, la data potrebbe avere 30,1234 secondi e NSDateComponents ha solo 30 come valore dei secondi, quindi sottraendo 30 secondi da NSDate si ottiene 0,1234 secondi dopo la mezzanotte. Inoltre, alcuni giorni hanno più (o meno) di 24 ore (ora legale), quindi per ottenere la data di ieri dovresti utilizzare [components setDay: -1] invece di [components setHour: -24].
orj

5
@orj Cordiali saluti, ARC è uscito molto tempo dopo che la risposta è stata pubblicata
Shaggy Frog

3
@ oj Inoltre, quando cambia l'ora legale, la sottrazione delle ore non ti dà mezzanotte. -1. Questo codice non vale 35 voti positivi.
Nikolai Ruhe

40

NSDateComponents è bello da ottenere oggi:

NSCalendar *cal = [NSCalendar currentCalendar];

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

Questo crea un NSDate con solo anno, mese e data:

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

Per ottenere ieri, ecc. Puoi calcolarlo utilizzando NSDateComponents:

NSDateComponents *components = [[NSDateComponents alloc] init];
[components setDay:-1];
NSDate *yesterday = [cal dateByAddingComponents:components toDate:today options:0];

Non è necessario includere la componente era?
Chris Page

Bello. Usato per calcolare una data di 8 anni nel passato e funziona bene. Ho solo bisogno di correggere una perdita qui: [[NSDateComponents alloc] init];
Craig B

@ CraigB grazie. Non vuole essere un esempio completo. Tralasciata l'evidente gestione della memoria come sfida per il lettore;)
Christian Beer

@ChrisPage il componente dell'era? Per che cosa?
Christian Beer

1
@ChristianBeer Sono abbastanza sicuro che tutti i componenti più grandi della risoluzione desiderata devono essere considerati. Credo che (NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit)dovrebbe essere (NSEraCalendarUnit | NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit).
Chris Page

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

Non è necessario includere la componente era?
Chris Page

Ho dovuto rimuovere NSDayCalendarUnit e aggiungere NSWeekdayCalendarUnit durante il calcolo di DateLastWeek.
jessecurry

Apple ha cambiato la definizione di NSWeekdayCalendarUnit e NSDayCalendarUnit attorno a iOS 5.0. Il nuovo modo è utilizzare NSWeekdayCalendarUnit. Ma nelle versioni precedenti è necessario utilizzare NSDayCalendarUnit. È un casino ...
Dustin

@Dustin Sembra che non funzioni, anche durante l'aggiornamento a nuove unità ... Ad esempio DateThisWeek, l'impostazione della settimana non ha alcun impatto su 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)

Si noti che i componenti della data sono facoltativi.


1
@fengd bene, oggi 27 giugno 2016, all'1 di notte sarà il 28 giugno 2016, e se sottraggo 24 ore, la data sarà il 27 giugno dell'1. Qual è il punto che mi sono perso?
gokhanakkurt,

1
scusa, @gokhanakkurt. Penso che ci siano stati dei singhiozzi nella mia mente. la tua risposta è corretta
fengd

4

Le altre risposte semplicemente non hanno funzionato per me (forse a causa del mio fuso orario). Ecco come lo faccio:

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

4

Se utilizzi iOS 10+ o MacOS 10.12+, puoi utilizzare questi due Calendarmetodi per farlo correttamente.

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

Ecco un esempio di come utilizzare questi metodi in Swift 3, insieme all'output dei playground nel mio fuso orario.

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: puoi utilizzare la DateIntervals per verificare se una data rientra in tale intervallo. Continuando dall'alto:

thisWeekInterval!.contains(now)
// => true
lastMonthInterval!.contains(now)
// => false

Perché è yesterdayscritto il 29 aprile e il now28 aprile?
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];

0

Mi piace molto l'oggetto THCalendarInfo contenuto in questo progetto:

http://github.com/jaredholdcroft/kcalendar

Non riesco a trovare l'originale. Utilizzando questo oggetto è possibile passare a un giorno precedente, all'inizio di una settimana, all'inizio di un mese, ottenere il giorno della settimana, il giorno del mese ... ecc ecc.


0
NSDate *today = [[NSDate alloc] initWithTimeIntervalSinceNow:0];

14
Perché no [NSDate date]?
joshpaul

Poiché entrambi sono validi per ottenere la data corrente, entrambi includono l'ora. Quindi non è la soluzione corretta per la domanda!
Christian Beer

0

Questo è per controllare che la data sia questo mese o no

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
}

E il secondo cambia solo il tipo di calendarUnit per debole come questo

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
}

Spero che questo sia utile a qualcuno Grazie.


0

Ho risposto una domanda simile già ed ecco il motivo per cui la mia risposta è meglio:

  • Swift 3 !
  • Utilizza "Ieri" e "Oggi" di DateFormatter. Questo è già tradotto da Apple, il che ti fa risparmiare il lavoro!
  • Utilizza la stringa "1 settimana" già tradotta di DateComponentsFormatter. (Ancora meno lavoro per te, per gentile concessione di Apple.) Tutto quello che devi fare è tradurre la stringa "% @ ago". 🙂
  • Le altre risposte calcolano in modo errato l'ora in cui il giorno passa da "oggi" a "ieri" ecc. Le costanti fisse sono un grande NO-NO per ragioni . Inoltre, le altre risposte utilizzano la data / ora corrente quando dovrebbero utilizzare la fine della data / ora del giorno corrente .
  • Utilizza autoupdatingCurrent per Calendar e Locale che garantisce che la tua app sia immediatamente aggiornata con il calendario dell'utente e le preferenze di lingua in Settings.app
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.