2009-08-05 23 views
8

Ho cercato di trovare un modo sensato di memorizzare i dati giornalieri utilizzando Core Data su iPhone.Come memorizzare le date senza orari in Core Data

mia app riceve i dati in formato CSV, con una data ma non c'è tempo:

date, cycles 
2009-08-01, 123 
2009-08-02, 234 
2009-08-03, 345 
2009-08-04, 456 

Quando questi dati vengono memorizzati, ci dovrebbe essere solo un record per giorno. Ho pensato che la cosa migliore da fare fosse creare un NSDate da archiviare, ma eliminare i dati relativi al fuso orario &.

Posso facilmente creare un NSDate senza ore, minuti o secondi utilizzando NSDateComponents o un NSDateFormatter. Tuttavia, anche quando ho impostato il fuso orario in modo esplicito su UTC oppure a zero secondi da GMT, l'output di una data creata con NSLog() sempre ha il mio fuso orario locale come:

2009-07-29 00:00:00 +0100 

Qualcuno sa di un modo migliore per rendere NSDate senza componenti temporali? O forse un modo migliore di memorizzare le date?

risposta

9

Una buona regola di programmazione è memorizzare sempre le date in UTC. Non importa se usi i dati di base o meno; dovrai ancora lavorare perché le lezioni di data di Apple fanno schifo.

Le date sono rappresentate internamente come un numero di secondi da una data di riferimento che è, credo, 1 gennaio 2001 00:00:00 (sebbene la data di riferimento effettiva non sia molto importante). Il punto è, gli oggetti NSDate sono sempre in modo nativo in UTC. Se sono locali le date che stai ricevendo nel file CSV, è necessario fare qualcosa di simile per ottenere il tempo UTC:

NSDate *UTCDate = [localDate addTimeInterval:-[[NSTimeZone localTimeZone] secondsFromGMT]]; 

Poi, mi piacerebbe impostare il tempo di 00:00:00 . Ora stai salvando la data, a mezzanotte, in UTC. Per scopi di presentazione, verrà utilizzato un NSDateFormatter configurato con il fuso orario desiderato (il fuso orario del sistema è l'impostazione predefinita se non si specifica uno) per visualizzare tali date.

I fusi orari non hanno molta importanza quando si tratta solo di date. Se ti assicuri di impostare il fuso orario su NSDateFormatter in UTC, mostrerai sempre la stessa data, indipendentemente dal fuso orario che l'utente ha selezionato sul suo dispositivo.

Se non ti piace questa soluzione, puoi sempre memorizzare le date in un formato alternativo. È possibile utilizzare uno double o int per memorizzare la data in un formato personalizzato (ad es.il numero di giorni da qualche data di riferimento), oppure è possibile persino eseguire il rollover della propria classe per modellare la data esattamente come si desidera e memorizzarla come un oggetto NSData. Finché la classe implementa NSCoding, è possibile serializzarlo su un oggetto NSData in Dati principali. Devi solo impostare il tipo di attributo in Dati principali su "Trasformabile".

Qui ci sono un sacco di opzioni e nessuna di queste implica lo sforzo di scrivere query e database SQLite.

+1

Grazie mille. L'ho risolto ora. La tua risposta rende le conversioni più sensate e Peter Hosey di seguito spiega l'output di NSLog. – Ben

2

L'oggetto NSDate includerà sempre data di scadenza - per citare i documenti "rappresenta [s] un singolo punto nel tempo" e lo fa memorizzando un valore temporale dalla data di riferimento (l'inizio del 1 ° gennaio 2001 a GMT , sempre secondo i documenti). Pertanto non è possibile avere un NSDate che non è a conoscenza dell'ora del giorno.

Anziché provare a memorizzare le date a modo tuo, utilizzerei comunque NSDate nel modello e prendere in considerazione l'aggiunta di un paio di metodi alla classe di entità, una delle quali farà quanto descritto sopra, impostando NSDate su 00: 00:00 in un dato giorno. L'altro potrebbe restituire solo la data da un NSDate nel formato preferito. Questi utilizzerebbero quindi il getter e il setter generati dai Core Data per accedere alla proprietà NSDate.

Utilizzando ancora NSDate si sta utilizzando una classe con cui Core Data può lavorare in modo nativo, il che significa che è possibile utilizzare facilmente i predicati per filtrare o ordinare i risultati recuperati per data senza doversi preoccupare troppo.

+0

Grazie per la risposta. Questo lascia comunque il problema dei fusi orari. Ad esempio: salvo i miei dati a luglio a Londra (GMT + 0100) e qualcun altro lo salva a Cupertino (GMT-0700). Ora c'è una differenza di 8 ore nella data memorizzata. Penso che sia probabilmente più efficiente solo per tornare a SQLite raw. – Ben

+0

Non capisco il problema: la data in un NSDate è memorizzata come una data assoluta, secondi da 00:00:00 1/1/2001 * GMT *. Quindi se due persone in diversi fusi orari memorizzano la data "corrente" esattamente nello stesso istante, i loro NSDate sono identici. Il fuso orario funziona solo con il recupero/la visualizzazione e, a meno che non comunichi a NSDate, il fuso orario verrà impostato sul sistema. In altre parole, se le due serie di dati sono memorizzate nello stesso momento a Londra e Cupertino, le date memorizzate sono le stesse, senza alcuna differenza. – marramgrass

3

Un NSDate non ha un fuso orario. NSLog utilizza il fuso orario locale; dice +0100 perché è lì che sei.

+0

Grazie. Non ero a conoscenza del fatto che NSLog utilizzava il fuso orario locale. Dopo averlo sottolineato, ho giocato con i pref di data e ora di sistema e ora ha molto più senso. – Ben

+0

Non ho capito il +0100. Cosa rappresenta esattamente? –

+0

srikanth rongali: Fuso orario fuso. L'interrogante era un'ora prima del GMT: GMT + 0100. (L'ultimo paio di cifre sono minuti, quindi un fuso orario cinque ore e mezzo prima del GMT sarebbe +0530.) –