Perché non restituire le date come una stringa dal database?


41

In una tipica applicazione Web, le date vengono recuperate dal livello del database fortemente tipizzato (ad es. In c # come System.DateTime come opposto System.String).

Quando una data deve essere espressa come una stringa (ad es. Visualizzata su una pagina), la conversione da DateTime a stringa viene effettuata nel livello di presentazione.

Perchè è questo? Perché è negativo convertire DateTime in una stringa sul livello del database?

Vedi anche il acceso dibattito nella chat e la domanda originale che ha dato il via a tutto ciò .


73
Lascia che ti chieda questo: convertiresti quindi ogni singolo tipo in una stringa? Cosa rende Date diverso?
gardenhead,

7
Buona domanda! Si prega di consultare il acceso dibattito in corso, qui .
John Wu,

8
Bene, sembra abbastanza ovvio che l'altro ragazzo ha torto, e tutti gli altri hanno ragione. Non è proprio una domanda qui
gardenhead,

7
A volte è necessario eseguire la matematica della data al di fuori del database. Molto più difficile se tutto ciò che hai è stringhe.
Eric King,

14
Un altro problema: che tipo di stringa ti serve? Esistono MOLTI modi per rappresentare un datetime come stringa. E se avessi un database che restituiva solo l'ora corrente, rappresentata come numero di secondi dall'epoca, come una stringa (ad esempio, l'ora corrente è "1474496980"). Sarebbe utile? Vorresti usare un database del genere?
riwalk

Risposte:


168

Date, DateTimes e qualsiasi altro oggetto tipizzato, generalmente dovrebbero essere lasciati nel loro formato correttamente digitato fino al momento in cui ne hai bisogno per essere trasformati in qualche altro tipo, specialmente quando quel tipo è una forma leggibile dall'uomo, e specialmente quando è un lossy / tipo di conversione unidirezionale.

Perché? Poiché si presume che il tipo fornisca molte utili funzionalità integrate, come il corretto test di uguaglianza, l'addizione e la sottrazione, il confronto (maggiore di, minore di), la funzionalità di fuso orario e locale (particolarmente importante per qualsiasi cosa legata al tempo), ecc. Se decidi di supportare gli americani e il formato "Month Day [th], Year" e lo stile britannico comune di "Day Month Year" o lo standard ISO di "Year-Month-Day"? Cosa faresti se fosse una stringa e dovessi apportare quella modifica, analizzarla nuovamente in una Data? Uh, no grazie - ci sono molti mali e insetti malvagi in quel modo, che è meglio evitare del tutto.

Più specificamente, hai citato l'architettura a livelli, che ha il livello di presentazione separato dai dati in un secondo momento. Questo è in realtà l'altro grande motivo per passare una data come una data e non una stringa - perché in quale tipo di formattazione della stringa deve essere inserita la data? Inglese, cinese, con o senza secondi / millisecondi, nome completo del mese o cifre, vuoi ordinare in seguito il campo della data (l'ordinamento su una stringa richiede un certo formato di stringa se vuoi che funzioni correttamente), ecc.? Questa è tutta una questione di presentazione - come l'utente dovrebbe visualizzare i dati - e mettere quella logica in qualsiasi altro posto limiterebbe il vantaggio di avere l'architettura a più livelli in primo luogo. Il database non dovrebbe avere bisogno di sapere o preoccuparsi di come vorresti visualizzare la data in futuro.

Infine, quasi tutte le applicazioni complesse (che è ciò a cui servono le architetture a più livelli) che si occupano del tempo inevitabilmente useranno tempi / date in molti, molti modi diversi e spesso a tutti i diversi livelli dell'architettura. Gli oggetti digitati relativi a tempi e date esistono per una ragione davvero buona: il tempo stesso, e in particolare i sistemi di calendario umani, sono strani e difficili. In definitiva, i tempi e le date non sono stringhe per lo stesso motivo per cui numeri interi e punti fluttuanti non sono stringhe, e renderà la tua vita più difficile solo se provi a far finta che siano solo matrici di caratteri, perché semplicemente non lo sono.


26
+1 solo per usare la parola sgarbatamente. Sono d'accordo con i tuoi argomenti convincenti e la tua spiegazione esauriente, ma è per questo che ho dovuto accedere e votare per te.
Adrian Larson,

1
Rappresentare il datetime come secondi da un tempo definito in passato è anche robusto tra diversi calendari. Ad esempio, i calendari islamici e cinesi non usano nessuno dei mesi Greogrian, il numero dell'anno ecc. Considererei questa gestione a livello di database una cattiva pratica.
rexkogitans,

Le date sono spesso presentate come "X giorni fa". Buona fortuna analizzandolo al valore originale.
Agent_L

5
Non dimentichiamo inoltre i problemi di modifica dell'ora legale (e altri simili). Will "Nov 6, 2016 01:30:26" essere la prima volta o la seconda volta che avrà successo questa data e l'ora? UTC DateTime è almeno unico e puoi sempre tradurlo nella rappresentazione locale per quel momento - tornare indietro nell'altro modo non è sempre possibile.
J ...

3
Why? Because it is assumed that the type provides you with lots of handy built in functionalitySecondo me questo è solo secondario. La vera ragione è che il tipo ti dice che cos'è qualcosa . Una data non è una stringa, capita semplicemente di tradursi facilmente in una stringa leggibile dall'uomo.
Doval,

53

Sta dicendo di usare il web server per convertire l'ora dei dati in una stringa. Sto dicendo di farlo sul server di database e non sul server web. Perché pensi che sia meglio? - Testa MT

Voglio sapere il tipo.

Non mi interessa davvero se il tuo database memorizza le informazioni in una stringa, alcuni ints o byte, perché, alla fine, sono sempre comunque byte. Quella stringa che occupa più spazio di quanto è necessario nel tuo database non mi disturba. Ciò che mi dà fastidio sta incontrando date come questa:

2016/11/10

E non sapendo se quello è l'undicesimo mese o il decimo mese.

Ma è convalidato che dici. Sicuro di averlo sottoposto a processi di validazione. La data è perfettamente corretta. Ma qui sto mantenendo questa cosa e tutto quello che so è che la data è una stringa. Non posso nemmeno dirti che data è questa.

"Decimo giorno di novembre nel duemilasei anno del nostro signore."

Questa è una stringa. Una delle nostre presentazioni ne ha bisogno in quel formato. Hai detto che il database converte tutte le date in stringhe, giusto? Divertiti con quello.

Il compito del database è archiviare i dati non presenti. Certo, potresti farlo in stringhe ma poi devi analizzarlo per renderlo utile presentare per altri formati. Memorizzarlo in un formato standard analizzato per qualsiasi tipo offerto dal DB ci rende il più vicino possibile a presentare come possiamo essere senza aver preso una decisione di presentazione. Non importa davvero se il DB esegue il backup di quel tipo con una stringa o ints o byte. Finché sa cosa sta facendo.

Ma quando non fai sapere al DB che abbiamo a che fare con una data e memorizziamo una data come stringa, stai prematuramente presentando e favorendo una presentazione rispetto a tutte le altre. Ciò costringe tutti gli altri presentatori ad analizzare prima della conversione. No, il database non fa parte del livello di presentazione. Non chiederlo.

Allo stesso modo, il livello di presentazione non fa parte del database, pertanto non è consigliabile associare un report ai dettagli del database. È molto più robusto agire sui tipi.


Questa risposta indirizza l' archiviazione come stringhe. Tuttavia, non risolve il modello comune di memorizzazione delle date in un tipo di data nativo, ma la formattazione in una stringa nella query SQL , utilizzando funzioni come CONVERT (T-SQL), né che un DBMS in genere serializzi le sue date in una stringa in un formato configurabile qualunque sia la query. Ad esempio: postgresql.org/docs/9.5/static/…
dcorking

Questo è un rapporto. Succede dopo la conservazione. Come convertire la mia data di nascita nella mia età.
candied_orange,

2
Volevo solo incoraggiarti ad estendere la tua risposta, poiché l'argomento del PO è come "le date vengono recuperate dal livello del database". Esiste un modello ben definito, sebbene discutibilmente deprecato, in cui un report richiede al database le stringhe di date formattate e localizzate. Penso che l'OP vorrebbe sentire quegli argomenti di deprecazione. So che lo farei.
apertura

@dcorking note update.
candied_orange,

+1 aggiungendo più acqua al mulino: basta creare un sistema su una base installata che si estende su più fusi orari in cui l'istante assoluto è fondamentale e vedere come si fa bene con le conversioni di timestamp stringa <-> ovunque. Peggio ancora, fai in modo che le persone creino i propri plugin e fornisca loro i timestamp mentre le stringhe vedono quanto saranno costanti questi timestamp!
Newtopian,

19

località

La conversione della data in stringa per scopi di presentazione richiede la conoscenza delle preferenze dell'utente, poiché la stessa data esatta dovrebbe essere visualizzata in modo diverso per gli utenti in diverse località. Anche se si utilizza una singola locale nell'applicazione, il comportamento corretto dovrebbe usare la locale dell'applicazione anziché il server di database; e non è garantito che siano identici anche se in questo momento coincidono casualmente.

La conversione da un tipo di dati di data universale a una stringa specifica della locale dovrebbe avvenire nel livello di presentazione perché è il livello che sa come eseguire tale conversione.


3
Per un esempio di vita reale di una mancata corrispondenza delle impostazioni locali, immagina di scrivere un'app per Maine, gli utenti degli Stati Uniti e poi è ospitata nella server farm della costa occidentale di Amazon. ;) Questa non è una situazione così improbabile, in realtà.
jpmc26,

@ jpmc26 Non capisco la differenza - Maine usa un formato data diverso dal resto degli Stati Uniti?
Pete Kirkham,

2
@PeteKirkham Maine e la costa occidentale degli Stati Uniti utilizzano fusi orari distanti 3 ore.
jpmc26,

1
O un altro scenario di vita reale: immagina di eseguire un server in Svizzera che deve servire i clienti in quattro (tedesco, francese, italiano, inglese) lingue diverse con impostazioni locali diverse (e regole di formattazione leggermente diverse). Buona fortuna a scegliere le impostazioni locali giuste per il tuo server in una situazione del genere.
Voo,

1
@ jpmc26 fusi orari e locali non sono la stessa cosa. Ad esempio, abbiamo uffici a Glasgow, Scozia, Atlanta, Stati Uniti e Pune India. I consulenti di questi uffici a loro volta monitorano i siti (campus, ospedali, hotel ecc.) In tutto il mondo 24 ore su 24. Il database dell'applicazione funziona in UTC ma visualizza l'ora in ora locale per il sito da monitorare. I consulenti statunitensi hanno date localizzate in MM / GG / AAAA, ma le località del Regno Unito e dell'India sono GG / MM / AAAA - ciò dipende dalle impostazioni locali, non dal fuso orario del sito o dell'utente.
Pete Kirkham,

9

Questo non è desiderabile per lo stesso motivo per cui non si vorrebbe semplicemente convertire ciecamente qualsiasi tipo in una stringa non appena raggiunge il livello dell'applicazione. È molto probabile che tu voglia utilizzare quell'oggetto in qualche modo prima di presentarlo all'utente (se lo presenti anche all'utente). Per questo esempio specifico, immagina di dover fare dei calcoli con la data sull'oggetto. Non vi è alcun aspetto negativo nel convertire l'oggetto in una stringa proprio prima di visualizzarlo.


4

I tipi esistono per una ragione, se non aggiungessero alcun vantaggio, non li avremmo e non li useremmo e avremmo semplicemente "il tipo" e tutto sarebbe quello. Non solo sono convenienti, ma aggiungono anche sicurezza ed efficienza. Di seguito è riportato un elenco dei motivi per cui dovresti sempre mantenere i tipi nel loro formato nativo e non come stringhe . Ho usato DateTimecome esempio la maggior parte delle volte ma gli stessi principi si applicano a qualsiasi tipo primitivo come numeri interi, decimali, binari, ecc.


Archivio dati

vincoli

Digitare Vincolo

Quasi tutti gli archivi dati consentono di specificare vincoli sui dati, inclusi i vincoli di tipo. Uno dei principali vantaggi della specifica di DateTimeun'istanza è che i dati memorizzati saranno vincolati a quel tipo. Non sarà mai possibile inserire altro che una data e ora indipendentemente da come i dati sono stati inseriti nel negozio. Quest'ultimo è importante per i sistemi più grandi in cui esistono più processi che interagiscono direttamente con il negozio. Ciò include anche il tentativo di aggiungere date errate come il 30 febbraio (di qualsiasi anno) poiché febbraio può avere solo 29 giorni in un anno bisestile e 28 giorni per gli anni non bisestili.

Vincoli di convalida

Esistono anche vincoli di convalida che possono essere implementati nell'archivio dati come garantire che una data inserita non superi la data corrente o che una data di inizio si verifichi prima di una data di fine.

operazioni

La maggior parte degli archivi di dati ha anche operazioni / funzioni integrate come DateAddo DatePartin MS SQL Server. Ciò consente di iniziare a filtrare o selezionare dati specifici mentre i dati sono ancora nell'archivio (non ancora recuperati nell'applicazione).

Formato universalmente accettato

Usando il tipo nativo, altri sviluppatori o sistemi che interagiscono anche con il negozio non devono essere informati nei minimi dettagli su come è memorizzato quel tipo primitivo. Questo non è il caso se quel tipo è stato memorizzato come stringa, quindi devi assicurarti che tutti comprendano il formato di quella DateTimerappresentazione di stringa. Questo sistema diventa fragile quando si tratta di dati che si estendono su locali, regioni e culture nell'origine dei dati, la posizione fisica di un'applicazione e gli attributi dell'utente finale / sistema che interagisce con tali dati. Esempio: il formato della data in un paese potrebbe essere MM / gg / aaaa (come negli Stati Uniti) ma in un altro potrebbe essere gg / MM / aaaa, rilevando che la differenza diventa quasi impossibile.

Velocità

La velocità di recupero, la velocità di convalida, la velocità delle operazioni e l'efficienza dello stoccaggio sono tutti fattori importanti. Esempio di velocità di recupero: gli archivi di dati consentono indici su colonne e questi indici possono essere generalmente utilizzati in modo più efficiente se il tipo è archiviato nel suo formato nativo.

Applicazione

Accesso ai dati

L'esecuzione di query sullo store diventa più semplice utilizzando il sistema di tipi nativi poiché gli sviluppatori, ancora una volta, non devono indovinare il formato di archiviazione. Quasi tutti i fornitori di applicazioni per l'archivio dati ( esempio: ado.net ) forniscono meccanismi per la creazione delle query con parametri corretti basate sui tipi nativi passati. Ecco un esempio di aggiunta della parte Data a una query ado.net contro un negozio Sql Server, fare lo stesso con le stringhe sarebbe molto ingombrante e fragile / soggetto a errori.

command.Parameters.Add(new SqlParameter("@startDate", SqlDbType.Date) {Value = myDateInstance.Date});

operazioni

I tipi nativi nel codice forniscono anche operazioni standard come il tipo .net System.Date. Le operazioni sono generalmente di natura matematica come l'aggiunta di date, la ricerca della differenza tra le date, ecc. Ancora una volta, questo non è possibile fare facilmente sui tipi di stringa.

Livello di presentazione

località

Quando un tipo primitivo viene infine convertito in una stringa nel livello di presentazione ( la posizione corretta nello stack del programma per farlo ), il programmatore ora ha varie opzioni per visualizzarlo correttamente in base al contesto in cui viene presentato. Questo contesto è generalmente costituito dal significato effettivo dei dati e dalle impostazioni locali dell'utente.

Esempio 1

Un'istanza di datetime può essere formattata automaticamente in base alle impostazioni internazionali dell'utente.

DateTime.Now.ToString("D", CultureInfo.GetCultureInfo(userContext.Culture))
Esempio 2

Un'istanza decimale potrebbe rappresentare un importo (valuta) e le impostazioni internazionali dell'utente dovrebbero quindi visualizzare l'importo in base alle loro preferenze. Un'applicazione c # potrebbe quindi visualizzare il valore utilizzando

amount.ToString("C", CultureInfo.GetCultureInfo(userContext.Culture))

Questo potrebbe essere fondamentale poiché diverse culture visualizzano i numeri in modo diverso. Nel periodo degli Stati Uniti (.) E la virgola (,) hanno l'esatto significato inverso come nei Paesi Bassi.

Posizione

Questo è molto specifico per le DateTimeistanze. Una data e ora rappresentano un evento in un determinato momento, ma di solito questo deve essere trasmesso / presentato all'utente in base al proprio fuso orario. Esempio: DateTimeun'istanza 2016-09-21T23:38:21.399Zpuò essere visualizzata come 9/21/2016 5:21 PMper un utente nel fuso orario orientale negli Stati Uniti. Esistono molti modi per farlo, ma diventa quasi impossibile se l'istanza di data e ora viene mantenuta in memoria come tipo di stringa o nell'archivio dati come tipo di stringa.


Regola generale

Le regole generali 2 per un'applicazione seguono quando si tratta di convertire qualsiasi tipo primitivo in una rappresentazione di stringa sono come queste

  • Quando si accetta l'input, convertire quell'input nel tipo di primitiva corretto il più presto possibile nello stack del programma (di solito nel livello di presentazione)
  • Quando si recuperano i dati da visualizzare, convertirli nella rappresentazione di stringa il più tardi possibile nello stack del programma (di nuovo, di solito nel livello di presentazione)

0

Non c'è davvero nulla di sbagliato nel fare questo (è fatto sempre nei servizi) purché tu stia usando un formato non ambiguo per la tua data. Per non ambiguo, intendo non solo la data è chiara (ad es. MM / GG vs. GG / MM) ma anche in quale fuso orario è. Quindi, in anticipo, se hai intenzione di rappresentare le tue date come testo, usa un formato ISO . Preferisco fortemente le stringhe temporali basate su UTC.

Professionisti:

  • Le stringhe di data / ora basate su standard sono portatili e di facile comprensione
  • Spesso le date nei DB contengono un componente orario. Se questo non è significativo per i tuoi dati, questo può effettivamente semplificare le cose.

Contro:

  • Dimensione dei dati Il formato interno di una data in un DB utilizzerà generalmente molto meno spazio del rendering String di quella data.
  • In genere vorrai inserirlo in una struttura di data o ora reale sul client, quindi potrebbe essere necessario un tempo extra per l'analisi.

Se qualcuno dicesse di voler fare questo, chiederei "perché?" perché non ha davvero molto senso. Se il motivo per cui qualcuno vuole restituire la data come stringa è perché la visualizzeranno direttamente, questa non è una buona ragione per usare le stringhe dal DB.

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.