NSDate ottiene anno / mese / giorno


291

Come posso ottenere l'anno / mese / giorno di un NSDateoggetto, senza altre informazioni? Mi rendo conto che probabilmente potrei farlo con qualcosa di simile a questo:

NSCalendar *cal = [[NSCalendar alloc] init];
NSDateComponents *components = [cal components:0 fromDate:date];
int year = [components year];
int month = [components month];
int day = [components day];

Ma sembra essere una seccatura per qualcosa di semplice come ottenere un NSDateanno / mese / giorno. c'è un'altra soluzione?


4
Ho avuto un po 'di problemi nell'usare questo codice fino a quando ho cambiato la prima riga in "NSCalendar * cal = [[NSCalendar alloc] initWithCalendarIdentifier: NSGregorianCalendar];" Deve esserci stata una modifica all'API da quando è stata posta questa domanda.
Russell Thackston,

@ futureelite7 è tornato alla revisione 1. Il codice esiste per scopi storici ed era una semplice spiegazione di quale fosse la mia idea iniziale.
Richard J. Ross III,

Il codice non funziona più. Puoi prendere nota del codice corretto?
futureelite7,

@ futureelite7 no. Quel codice è stato una dimostrazione del mio primo tentativo, non è mai stato progettato per funzionare. Se ritieni che sia ambiguo, sentiti libero di modificare il contesto che circonda quel blocco di codice, ma non modificare il codice stesso. Se ti senti fortemente interessato alla modifica del codice stesso, ti preghiamo di portare questa cover a meta e vedremo cosa hanno da dire le altre mod.
Richard J. Ross III,

8
@mike ecco perché leggi le risposte, non la domanda.
Richard J. Ross III,

Risposte:


615

Poiché questa è apparentemente la mia risposta più popolare, proverò a modificarla per contenere un po 'più di informazioni.

Nonostante il suo nome, NSDatedi per sé segna semplicemente un punto nel tempo della macchina, non una data. Non esiste alcuna correlazione tra il punto temporale specificato da un NSDatee un anno, mese o giorno. Per questo, devi fare riferimento a un calendario. Ogni dato momento restituirà informazioni sulla data diverse in base al calendario che stai visualizzando (le date non sono le stesse nei calendari gregoriano ed ebraico, ad esempio) e mentre il calendario gregoriano è il calendario più utilizzato nella mondo - presumo - siamo un po 'di parte che NSDatedovrebbe sempre usarlo. NSDate, per fortuna, è molto più bipartisan.


Ottenere la data e l'ora dovrà passare NSCalendar, come hai già detto, ma c'è un modo più semplice per farlo:

NSDateComponents *components = [[NSCalendar currentCalendar] components:NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear fromDate:[NSDate date]];

Ciò genera un NSDateComponentsoggetto contenente il giorno, il mese e l'anno dal calendario di sistema corrente per il giorno corrente. ( Nota: questo non è necessariamente l'attuale calendario specificato dall'utente , solo quello di sistema predefinito.)

Naturalmente, se stai utilizzando un calendario o una data diversi, puoi facilmente cambiarlo. Un elenco di calendari e unità di calendario disponibili è disponibile nel NSCalendarriferimento di classe . Ulteriori informazioni su NSDateComponentssono disponibili nel NSDateComponentsriferimento di classe .


Per riferimento, accedere ai singoli componenti da NSDateComponentsè piuttosto semplice:

NSInteger day = [components day];
NSInteger month = [components month];
NSInteger year = [components year];

Devi solo essere consapevole: NSDateComponentsnon conterrà informazioni valide per tutti i campi che richiedi a meno che tu non li abbia generati con quelle informazioni valide (cioè la richiesta NSCalendardi fornire tali informazioni con NSCalendarUnit). NSDateComponentsnon contengono informazioni di riferimento in sé e per sé - sono solo semplici strutture che contengono numeri a cui puoi accedere. Se vuoi ottenere anche un'era, per esempio NSDateComponents, dovrai alimentare il metodo del generatore NSCalendarcon la NSCalendarUnitErabandiera.


3
Una correzione a questo, la prima riga dovrebbe avere NSDayCalendarUnit invece di NSWeekCalendarUnit.
Whitehawk,

@Erik Quale calendario stai usando? Codice?
Itai Ferber,

7
@Jonny I risultati ottenuti dipendono dal calendario che stai utilizzando. NSCalendarIl +currentCalendarmetodo restituirà il calendario di sistema, quindi se il telefono dell'utente è impostato sulla modalità ora giapponese o tailandese, otterrai un anno diverso. Se si desidera forzare un sistema di calendario specifico, creare un calendario e inizializzarlo con le impostazioni internazionali appropriate. Ad esempio, per forzare un calendario gregoriano, ti consigliamo di utilizzare quanto segue:[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]
Itai Ferber,

2
enums NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit DEPRECATED usa invece NSCalendarUnitDay.
Kunal Balani,

2
Avviso: non utilizzare [NSCalendar currentCalendar] a meno che non si stia tentando di mostrare un valore all'utente. Considera che gli utenti potrebbero seguire un calendario buddista (l'anno è ora 2558 o qualcosa del genere) o qualsiasi altro numero di calendari dispari. Non vuoi che la tua app si interrompa in questi casi. Usa il calendario gregoriano a meno che tu non abbia un motivo molto specifico per non farlo. Questo bug è difficile da individuare perché tu e i tuoi tester potete usare gregorian come predefinito.
n13,

51

È possibile ottenere un componente separato di un NSDate utilizzando NSDateFormatter:

NSDateFormatter *df = [[NSDateFormatter alloc] init];

[df setDateFormat:@"dd"];
myDayString = [df stringFromDate:[NSDate date]];

[df setDateFormat:@"MMM"];
myMonthString = [df stringFromDate:[NSDate date]];

[df setDateFormat:@"yy"];
myYearString = [df stringFromDate:[NSDate date]];

Se si desidera ottenere il numero del mese anziché l'abbreviazione, utilizzare "MM". Se desideri ottenere numeri interi, utilizza[myDayString intValue];


1
Allargato al suo con questo senso . Divertiti --- puoi inserirlo nel tuo codice.
DogEatDog

Risolto il mio problema con l'utilizzo delle date per la ricerca in un dizionario :) Grazie!
mlunoe,

1
Questo in realtà non funziona al 100% come previsto per tutto il tempo. Ad esempio, se NSDate è 2013-12-31 00:00:00 +0000, la data formattata restituirà il 2014 per l'anno, anche se il numero effettivo nella data è 2013.
margusholland,

come posso ottenere il giorno dell'anno, ad es. il 10 aprile è il giorno corrente è il 99 ° giorno dell'anno corrente ?? -
Sviluppatore iOS

17

Giusto per riformulare il codice eccellente (e funzionante!) Di Itai, ecco come sarebbe una classe helper di esempio, per restituire il valore dell'anno di una determinata variabile NSDate.

Come puoi vedere, è abbastanza facile modificare questo codice per ottenere il mese o il giorno.

+(int)getYear:(NSDate*)date
{
    NSDateComponents *components = [[NSCalendar currentCalendar] components:NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit fromDate:date];

    int year = [components year];
    int month = [components month];
    int day = [components day];

    return year;
}

(Non posso credere che dovremo scrivere le nostre funzioni di data iOS di base come questa, nel 2013 ...)

Un'altra cosa: non usare mai <e> per confrontare due valori NSDate.

XCode accetterà felicemente tale codice (senza errori o avvisi), ma i suoi risultati sono una lotteria. È necessario utilizzare la funzione "confronta" per confrontare le date NSD:

if ([date1 compare:date2] == NSOrderedDescending) {
    // date1 is greater than date2        
}

4
I risultati del confronto dei puntatori sono lungi dall'essere una lotteria - hanno risultati molto ben definiti, purché li usi per quello a cui sono destinati - confrontare i puntatori, non gli oggetti.
Richard J. Ross III,

Potrebbe non essere una lotteria, ma DateTime di C # è molto più intuitivo. In iOS, l'operatore di meno di dovrebbe davvero confrontare due NSDate ... qualcuno vorrebbe davvero confrontare i puntatori di due variabili NSDate? Per lo meno, XCode mostra un avviso per chiedere se questo è davvero ciò che l'utente intende realmente.
Mike Gledhill,

1
Questo è solo un segno di un programmatore pigro che non capisce i fondamenti della lingua in cui sta scrivendo. E ci sono state situazioni per me in cui i confronti dei puntatori sono necessari per gli oggetti ObjC, specialmente se stai creando un contenitore personalizzato (sebbene le cose diventano più strane con ARC).
Richard J. Ross III,

1
Devo essere un programmatore pigro che non capisce i fondamenti, ma questo è un ottimo consiglio Mike!
Pier-Luc Gendreau,

4
I confronti dei puntatori possono essere necessari ma sono il caso d'uso molto meno comune quando si confrontano due date. Il 99,99% delle volte qualsiasi programmatore sarebbe più interessato a confrontare le date piuttosto che i puntatori. Fondamentalmente C # e il framework .NET sono stati progettati per rendere più semplici gli scenari più comuni, rendendo così i programmatori più produttivi e in molti casi obiett-c sembra che renda le cose intenzionalmente più ardue. Se hai tempo di leggere un libro di 800 pagine sui fondamenti di ogni lingua, evviva, ma il resto di noi ha app da consegnare in tempo e in budget.
Crake,

16

In Swift 2.0:

    let date = NSDate()
    let calendar = NSCalendar(identifier: NSCalendarIdentifierGregorian)!
    let components = calendar.components([.Month, .Day], fromDate: date)

    let (month, day) = (components.month, components.day)

11

Sto scrivendo questa risposta perché è l'unico approccio che non ti restituisce gli opzionali dalle NSDateComponentvariabili e / o forza di scartare quelle variabili (anche per Swift 3).

Swift 3

let date = Date()
let cal = Calendar.current
let year = cal.component(.year, from: date)
let month = cal.component(.month, from: date)
let day = cal.component(.day, from: date)

Swift 2

let date = NSDate()
let cal = NSCalendar.currentCalendar()
let year = cal.component(.Year, fromDate: date)
let month = cal.component(.Month, fromDate: date)
let day = cal.component(.Day, fromDate: date)

Bonus Swift 3 versione divertente

let date = Date()
let component = { (unit) in return Calendar.current().component(unit, from: date) }
let year = component(.year)
let month = component(.month)
let day = component(.day)

come posso ottenere il giorno dell'anno, ad es. il 10 aprile è il giorno corrente è il 99 ° giorno dell'anno corrente ?? -
Sviluppatore iOS

E assicurati di utilizzare il calendario gregoriano, ad esempio il componente dell'anno per il calendario giapponese restituisce 1 cifra ..
Flovettee

8

Novità in iOS 8

objC

NSDate *date = [NSDate date];
NSInteger era, year, month, day;
[[NSCalendar currentCalendar] getEra:&era year:&year month:&month day:&day fromDate:date];

veloce

let date = NSDate.init()
var era = 0, year = 0, month = 0, day = 0
NSCalendar.currentCalendar().getEra(&era, year:&year, month:&month, day:&day, fromDate: date)

2
Sorprendente! @Yuchen Zhong
Lito

1
Geniale! Sintassi decisamente migliore!
Giovanna,

4

Se scegli come target iOS 8+, puoi utilizzare i nuovi NSCalendarmetodi di praticità per raggiungere questo obiettivo in un formato più conciso.

Per prima cosa crea un NSCalendare usa tutto ciò che NSDateè richiesto.

NSCalendar *calendar = [NSCalendar currentCalendar];
NSDate *date = [NSDate date];

È possibile estrarre i componenti singolarmente tramite component:fromDate:

NSInteger year = [calendar component:NSCalendarUnitYear fromDate:date];
NSInteger month = [calendar component:NSCalendarUnitMonth fromDate:date];
NSInteger day = [calendar component:NSCalendarUnitDay fromDate:date];

O, ancora più sinteticamente, usa i NSIntegerpuntatori viagetEra:year:month:day:fromDate:

NSInteger year, month, day;
[calendar getEra:nil year:&year month:&month day:&day fromDate:date];

Per ulteriori informazioni ed esempi, consulta Manipolazione NSDate resa semplice in iOS 8 . Disclaimer, ho scritto il post.


come posso ottenere il giorno dell'anno, ad es. il 10 aprile è il giorno corrente è il 99 ° giorno dell'anno corrente ?? -
Sviluppatore iOS

4

A partire da iOS 8.0 (e OS X 10) è possibile utilizzare il metodo componente per semplificare l'ottenimento di un singolo componente data in questo modo:

int year = [[NSCalendar currentCalendar] component:NSCalendarUnitYear fromDate:[NSDate date]];

Dovrebbe rendere le cose più semplici e speriamo che questo sia implementato in modo efficiente.



2
    NSDate *currDate = [NSDate date];
    NSCalendar*       calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
    NSDateComponents* components = [calendar components:NSDayCalendarUnit|NSMonthCalendarUnit|NSYearCalendarUnit fromDate:currDate];
    NSInteger         day = [components day];
    NSInteger         month = [components month];
    NSInteger         year = [components year];
    NSLog(@"%d/%d/%d", day, month, year);

Questo chiaramente non mi dà l'anno, il mese o il giorno come numero intero, che è quello che ho richiesto nel PO. -1.
Richard J. Ross III,

1
Richard J. Ross III: l'ho appena risolto, mi dispiace perché la mia risposta è andata persa.
Linh Nguyen,

2

Ecco la soluzione in Swift:

let todayDate = NSDate()
let calendar = NSCalendar(identifier: NSCalendarIdentifierGregorian)!

// Use a mask to extract the required components. Extract only the required components, since it'll be expensive to compute all available values.
let components = calendar.components(.CalendarUnitYear | .CalendarUnitMonth | .CalendarUnitDay, fromDate: todayDate)

var (year, month, date) = (components.year, components.month, components.day) 

2

Prova questo . . .

Snippet di codice:

 NSDateComponents *components = [[NSCalendar currentCalendar] components:NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear fromDate:[NSDate date]];
 int year = [components year];
 int month = [components month];
 int day = [components day];

Fornisce l'anno, il mese e la data attuali


1

Prova quanto segue:

    NSString *birthday = @"06/15/1977";
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setDateFormat:@"MM/dd/yyyy"];
    NSDate *date = [formatter dateFromString:birthday];
    if(date!=nil) {
        NSInteger age = [date timeIntervalSinceNow]/31556926;
        NSDateComponents *components = [[NSCalendar currentCalendar] components:NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear fromDate:date];
        NSInteger day = [components day];
        NSInteger month = [components month];
        NSInteger year = [components year];

        NSLog(@"Day:%d Month:%d Year:%d Age:%d",day,month,year,age);
    }
    [formatter release];

1

Swift 2.x

extension NSDate {
    func currentDateInDayMonthYear() -> String {
        let dateFormatter = NSDateFormatter()
        dateFormatter.dateFormat = "d LLLL yyyy"
        return dateFormatter.stringFromDate(self)
    }
}

Puoi usarlo come

NSDate().currentDateInDayMonthYear()

Produzione

6 March 2016

1

veloce

Modo più semplice per ottenere qualsiasi elemento della data come stringa opzionale.

extension Date {

  // Year 
  var currentYear: String? {
    return getDateComponent(dateFormat: "yy")
    //return getDateComponent(dateFormat: "yyyy")
  }

  // Month 
  var currentMonth: String? {
    return getDateComponent(dateFormat: "M")
    //return getDateComponent(dateFormat: "MM")
    //return getDateComponent(dateFormat: "MMM")
    //return getDateComponent(dateFormat: "MMMM")
  }


  // Day
  var currentDay: String? {
    return getDateComponent(dateFormat: "dd")
    //return getDateComponent(dateFormat: "d")
  }


  func getDateComponent(dateFormat: String) -> String? {
    let format = DateFormatter()
    format.dateFormat = dateFormat
    return format.string(from: self)
  }


}

let today = Date()
print("Current Year - \(today.currentYear)")  // result Current Year - Optional("2017")
print("Current Month - \(today.currentMonth)")  // result Current Month - Optional("7")
print("Current Day - \(today.currentDay)")  // result Current Day - Optional("10")

0

lo faccio in questo modo ....

NSDate * mydate = [NSDate date];

NSCalendar * mycalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];

NSCalendarUnit units = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay;

NSDateComponents * myComponents  = [mycalendar components:units fromDate:mydate];

NSLog(@"%d-%d-%d",myComponents.day,myComponents.month,myComponents.year);

0

Per ottenere una stringa leggibile dall'uomo (giorno, mese, anno), puoi fare:

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
NSString *string = [dateFormatter stringFromDate:dateEndDate];
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.