¿Por qué no devolver fechas como una cadena de la base de datos?

41

En una aplicación web típica, las fechas se recuperan de la capa de la base de datos fuertemente tipada (por ejemplo, en c # como System.DateTime como System.String opuesto).

Cuando una fecha debe expresarse como una cadena (por ejemplo, mostrada en una página), la conversión de DateTime a cadena se realiza en el nivel de presentación.

¿Por qué es esto? ¿Por qué es malo convertir el DateTime en una cadena en el nivel de la base de datos?

Vea también el acalorado debate en el chat y la pregunta original que inició todo esto .

John Wu
fuente
73
Déjame preguntarte esto: ¿convertirías cada tipo en una cadena? ¿Qué hace que Date sea diferente?
cabeza de jardín
77
¡Buena pregunta! Vea el acalorado debate en progreso, aquí .
John Wu
8
Bueno, parece bastante obvio que el otro tipo está equivocado, y todos los demás tienen razón. Realmente no es una pregunta aquí
gardenhead
77
A veces necesita hacer cálculos de fechas fuera de la base de datos. Considerablemente más difícil si todo lo que tienes son cuerdas.
Eric King
14
Otro problema: ¿qué tipo de cuerda necesitas? Hay MUCHAS formas de representar una fecha y hora como una cadena. ¿Qué pasaría si tuviera una base de datos que solo devolviera la hora actual, representada como # de segundos desde la época, como una cadena (por ejemplo, la hora actual es "1474496980")? ¿Sería útil? ¿Te gustaría usar una base de datos como esa?
Riwalk

Respuestas:

168

Las fechas, fechas y realmente cualquier otro objeto escrito, generalmente deben dejarse en su formato escrito correctamente hasta el momento en que necesite que se conviertan en otro tipo, especialmente cuando ese tipo es una forma legible por humanos, y especialmente cuando es una pérdida / tipo de conversión unidireccional.

¿Por qué? Debido a que se supone que el tipo le brinda muchas funciones prácticas incorporadas, como pruebas de igualdad adecuadas, suma y resta, comparación (mayor que, menor que), zona horaria y funcionalidad local (especialmente importante para cualquier cosa relacionada con el tiempo), etc. Si decide que desea apoyar a los estadounidenses y el formato "Mes Día [th], Año", así como el estilo británico común de "Día Mes Año", o el estándar ISO de "Año-Mes-Día"? ¿Qué haría si fuera una cadena y necesitara hacer ese cambio, analizarlo nuevamente en una Fecha? Uf, no, gracias, hay muchos males y errores horribles de esa manera, que es mejor evitarlos por completo.

Más específicamente, mencionó la arquitectura escalonada, que tiene la capa de presentación separada de los datos más adelante. Esta es en realidad la otra gran razón para pasar una Fecha como Fecha y no una cadena, porque ¿en qué tipo de formato de cadena se debe poner la fecha? Inglés, chino, con o sin segundos / milisegundos, nombre completo del mes o dígitos, ¿querrá ordenar en el campo de fecha más tarde (la ordenación de una cadena exige un cierto formato de cadena si desea que funcione correctamente), etc.? Todo esto es una cuestión de presentación, cómo el usuario debe ver los datos, y poner esa lógica en cualquier otro lugar limitaría la ventaja de tener una arquitectura escalonada en primer lugar. La base de datos no debería necesitar saber o importar cómo querrá ver la fecha en el futuro.

Finalmente, casi todas las aplicaciones complejas (que es para lo que son las arquitecturas escalonadas) que se preocupan por el tiempo inevitablemente usarán horas / fechas de muchas, muchas maneras diferentes, y a menudo en todos los niveles diferentes de la arquitectura. Los objetos mecanografiados relacionados con horas y fechas existen por una muy buena razón: el tiempo mismo, y especialmente los sistemas de calendario humanos, son raros y difíciles. En última instancia, los tiempos y las fechas no son cadenas por la misma razón que los enteros y los puntos flotantes no son cadenas, y solo hará que su vida sea más difícil si intenta fingir que en realidad son solo matrices de caracteres, porque simplemente no lo son.

BrianH
fuente
26
+1 solo por usar la palabra dastardly. Estoy de acuerdo con sus argumentos convincentes y su explicación completa, pero es por eso que tuve que iniciar sesión y votar por usted.
Adrian Larson
1
Representar la fecha y hora como segundos desde un tiempo definido en el pasado también es robusto entre diferentes calendarios. Por ejemplo, los calendarios islámicos y chinos no usan ninguno de los meses de Greogrian, número de año, etc. Consideraría manejar esto a nivel de base de datos como una mala práctica.
rexkogitans
Las fechas a menudo se presentan como "Hace X días". Buena suerte volviendo al valor original.
Agent_L
55
Tampoco olvidemos el cambio de horario de verano (y otros problemas similares). ¿Será "6 de noviembre de 2016 1:30:26 AM" la primera vez o la segunda vez que esta fecha y hora habrá sucedido? UTC DateTime es al menos único y siempre puede traducirlo a la representación local para ese momento; no siempre es posible volver al otro lado.
J ...
3
Why? Because it is assumed that the type provides you with lots of handy built in functionalityEn mi opinión, esto es solo secundario. La verdadera razón es que el tipo te dice qué es algo . Una fecha no es una cadena, simplemente se traduce fácilmente en una cadena legible por humanos.
Doval
53

Está diciendo que use el servidor web para convertir el tiempo de datos en una cadena. Estoy diciendo que lo haga en el servidor de la base de datos y no en el servidor web. ¿Por qué crees que es mejor? - Cabeza MT

Quiero saber el tipo

Realmente no me importa si su base de datos almacena información en una cadena, algunas entradas o bytes, porque, al final, siempre son bytes de todos modos. Esa cadena que ocupa más espacio del necesario en su base de datos no me molesta. Lo que me molesta es encontrarse con fechas como esta:

10/11/2016

Y sin saber si ese es el undécimo mes o el décimo mes.

Pero está validado, dices. Seguro que lo pones a través de procesos de validación. La fecha es perfectamente correcta. Pero aquí estoy manteniendo esto y todo lo que sé es que la fecha es una cadena. Ni siquiera puedo decirte qué fecha es esta.

"Décimo día de noviembre del año dos mil dieciseisavo de nuestro señor".

Eso es una cuerda. Una de nuestras presentaciones lo necesita en ese formato. Usted dijo que la base de datos convierte todas las fechas en cadenas, ¿verdad? Divertirse con eso.

El trabajo de la base de datos es almacenar datos no presentes. Claro, puede hacerlo en cadenas, pero luego debe analizarlo para que sea útil presentarlo en otros formatos. Almacenarlo en una forma analizada estándar para cualquier tipo que ofrezca la base de datos nos permite estar tan listos para presentar como podamos sin haber tomado una decisión de presentación. Realmente no me importa si la base de datos respalda ese tipo con una cadena o entradas o bytes. Mientras sepa lo que está haciendo.

Pero cuando no le hace saber al DB que estamos tratando con una fecha y almacenamos una fecha como una cadena, está presentando prematuramente y favoreciendo una presentación sobre todas las demás. Esto obliga a todos los demás presentadores a analizar antes de convertir. No, la base de datos no es parte de la capa de presentación. No pidas que sea.

Del mismo modo, la capa de presentación no forma parte de la base de datos, por lo que no es aconsejable acoplar un informe a los detalles de la base de datos. Es mucho más robusto actuar según los tipos.

naranja confitada
fuente
Esta respuesta aborda el almacenamiento como cadenas. Sin embargo, no aborda el patrón común de almacenar fechas en un tipo de fecha nativo, pero luego formatea eso en una cadena en la consulta SQL , utilizando funciones como CONVERTIR (T-SQL), ni que un DBMS típicamente serializa sus fechas en una cadena en un formato configurable sea cual sea la consulta. Por ejemplo: postgresql.org/docs/9.5/static/…
dcorking el
Eso es un informe. Sucede después del almacenamiento. Como convertir mi fecha de nacimiento a mi edad.
candied_orange
2
Simplemente quería alentarlo a que extendiera su respuesta, ya que el tema del OP es cómo "se recuperan las fechas de la capa de la base de datos". Existe un patrón bien establecido, aunque posiblemente desaprobado, en el que un informe consulta en la base de datos cadenas de fechas formateadas y localizadas. Creo que al OP le gustaría escuchar esos argumentos de desaprobación. Sé que lo haría.
dcorking
Actualización de la nota @dcorking.
candied_orange
+1 agregando más agua al molino: solo cree un sistema en una base instalada que abarque varias zonas horarias donde el instante absoluto es primordial y vea qué tan bien le va con las conversiones de cadena de tiempo <-> en todas partes. ¡Lo peor es hacer un punto de extensión para que las personas creen sus propios complementos y les den marcas de tiempo a medida que las cadenas ven cuán consistentes serán estas marcas de tiempo!
Newtopian
19

Lugar

La conversión de la fecha en una cadena para fines de presentación requiere conocer las preferencias del usuario, ya que la misma fecha en general generalmente se debe mostrar de manera diferente para los usuarios en diferentes lugares. Incluso si usa una configuración regional única en su aplicación, el comportamiento adecuado debe usar la configuración regional de la aplicación en lugar del servidor de la base de datos; y no se garantiza que sean idénticos incluso si en este momento coinciden.

La conversión de un tipo de datos de fecha universal a una cadena específica de la localidad debe ocurrir en la capa de presentación porque es la capa que sabe cómo se debe realizar esa conversión.

Pedro es
fuente
3
Para un ejemplo de la vida real de un desajuste de la configuración regional, imagine escribir una aplicación para Maine, usuarios de EE. UU. Y luego se aloja en la granja de servidores de la costa oeste de Amazon. ;) Esta no es una situación poco probable, en realidad.
jpmc26
@ jpmc26 No entiendo la diferencia: ¿Maine usa un formato de fecha diferente al resto de los Estados Unidos?
Pete Kirkham el
2
@PeteKirkham Maine y la costa oeste de los EE. UU. Usan zonas horarias separadas por 3 horas.
jpmc26
1
U otro escenario de la vida real: imagine ejecutar un servidor en Suiza que tenga que atender a los clientes en cuatro idiomas diferentes (alemán, francés, italiano, inglés) con diferentes configuraciones regionales (y reglas de formato ligeramente diferentes). Buena suerte eligiendo el entorno local adecuado para su servidor en tal situación.
Voo
1
@ jpmc26 las zonas horarias y locales no son lo mismo. Por ejemplo, tenemos oficinas en Glasgow, Escocia, Atlanta, EE. UU. Y Pune India. Los consultores en estas oficinas a su vez supervisan los sitios (campus, hospitales, hoteles, etc.) en todo el mundo las 24 horas. La base de datos de la aplicación funciona en UTC pero muestra las horas en hora local para el sitio que se está monitoreando. Los consultores de EE. UU. Tienen fechas localizadas en MM / DD / AAAA, pero las ubicaciones del Reino Unido e India son DD / MM / AAAA; esto depende de la ubicación, no de la zona horaria del sitio o del usuario.
Pete Kirkham
9

Esto no es deseable por la misma razón por la que no querría convertir ciegamente cualquier tipo a una cadena tan pronto como llegue al nivel de la aplicación. Existe una alta probabilidad de que desee utilizar ese objeto de alguna manera antes de presentarlo al usuario (si incluso se lo presenta al usuario). Para este ejemplo específico, imagine que necesita hacer algo de matemática de fechas en el objeto. No hay inconveniente en convertir el objeto en una cadena precisamente antes de mostrarlo.

cabeza de jardín
fuente
4

Los tipos existen por una razón, si no agregaran ningún beneficio, entonces no los tendríamos y no los usaríamos y simplemente tendríamos "el tipo" y todo sería eso. No solo son convenientes, sino que también agregan seguridad y eficiencia. La siguiente es una lista de por qué siempre debe persistir los tipos en su formato nativo y no como cadenas . Usé DateTimecomo ejemplo la mayor parte del tiempo, pero los mismos principios se aplican a cualquier tipo primitivo como enteros, decimales, binarios, etc.


Almacén de datos

Restricciones

Restricción de tipo

Casi todos los almacenes de datos permiten especificar restricciones en los datos, esto incluye restricciones de tipo. Uno de los principales beneficios de especificar una DateTimeinstancia es que los datos almacenados estarán restringidos a ese tipo. Nunca será posible ingresar nada que no sea una fecha y hora, independientemente de cómo se insertaron los datos en la tienda. Esto último es importante para sistemas más grandes donde existen múltiples procesos que interactúan directamente con la tienda. Esto también incluye tratar de agregar fechas defectuosas como el 30 de febrero (de cualquier año) ya que febrero solo puede tener 29 días en un año bisiesto y 28 días para los años no bisiestos.

Restricciones de validación

También hay restricciones de validación que se pueden implementar en el Almacén de datos, como garantizar que una fecha insertada no supere la fecha actual o que se produzca una fecha de inicio anterior a una fecha de finalización.

Operaciones

La mayoría de los almacenes de datos también tienen operaciones / funciones integradas como DateAddo DateParten MS Sql Server. Esto le permite comenzar a filtrar o seleccionar datos específicos mientras los datos todavía están en la tienda (aún no se han recuperado en la aplicación).

Formato universalmente aceptado

Al usar el tipo nativo, otros desarrolladores o sistemas que también interactúan con la tienda no tienen que estar informados sobre los detalles minuciosos de cómo se almacena ese tipo primitivo. Este no es el caso si ese tipo se almacenó como una cadena, entonces debe asegurarse de que todos entiendan el formato de esa DateTimerepresentación de cadena. Este sistema se vuelve frágil cuando se trata de datos que abarcan entornos locales, regiones y culturas en el origen de datos, la ubicación física de una aplicación y los atributos del usuario / sistema final que está interactuando con esos datos. Ejemplo: el formato de fecha en un país podría ser MM / dd / aaaa (como en los EE. UU.) Pero en otro podría ser dd / MM / aaaa, detectar esa diferencia se vuelve casi imposible.

Velocidad

La velocidad de recuperación, la velocidad de validación, la velocidad de las operaciones y la eficiencia del almacenamiento también son factores importantes. Ejemplo de la velocidad de recuperación: los almacenes de datos permiten índices en columnas y estos índices generalmente se pueden usar de manera más eficiente si el tipo se almacena en su formato nativo.

Solicitud

Acceso a los datos

Ejecutar consultas en la tienda se vuelve más simple usando el sistema de tipo nativo ya que los desarrolladores, una vez más, no tienen que adivinar el formato de almacenamiento. Casi todos los proveedores de aplicaciones de almacenamiento de datos ( ejemplo: ado.net ) proporcionan mecanismos para crear las consultas parametrizadas adecuadas en función de los tipos nativos pasados. Aquí hay un ejemplo de cómo agregar la parte Fecha a una consulta ado.net en un almacén de SQL Server, hacer lo mismo con las cadenas sería muy engorroso y frágil / propenso a errores.

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

Operaciones

Los tipos nativos en el código también proporcionan operaciones estándar como el tipo .net System.Date. Las operaciones suelen ser de naturaleza matemática, como agregar fechas, encontrar la diferencia entre fechas, etc. Nuevamente, esto no es posible hacerlo fácilmente en los tipos de cadena.

Capa de presentación

Lugar

Cuando un tipo primitivo finalmente se convierte en una cadena en la capa de presentación ( la ubicación correcta en la pila de programas para hacerlo ) el programador ahora tiene varias opciones para mostrarlo correctamente de acuerdo con el contexto en el que se presenta. Este contexto generalmente consiste en el significado real de los datos y la configuración regional del usuario.

Ejemplo 1

Una instancia de fecha y hora se puede formatear automáticamente en función de la configuración regional del usuario.

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

Una instancia decimal podría representar una cantidad (moneda) y la configuración regional del usuario también debería mostrar la cantidad de acuerdo con sus preferencias. Una aplicación de C # podría mostrar el valor usando

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

Esto podría ser crítico ya que las diferentes culturas muestran los números de manera diferente. En el período de EE. UU. (.) Y la coma (,) tienen el significado inverso exacto que en los Países Bajos.

Ubicación

Esto es muy específico para las DateTimeinstancias. Una fecha y hora representan una ocurrencia en un momento específico en el tiempo, pero esto generalmente tiene que ser transmitido / presentado al usuario dependiendo de su propia zona horaria. Ejemplo: una DateTimeinstancia 2016-09-21T23:38:21.399Zpodría mostrarse como 9/21/2016 5:21 PMpara un usuario en la zona horaria del este de los EE. UU. Hay muchas maneras de lograr esto, pero se vuelve casi imposible si la instancia de fecha y hora se mantiene en la memoria como un tipo de cadena o en el almacén de datos como un tipo de cadena.


Regla general

Las 2 reglas generales para una aplicación que se siguen cuando se trata de convertir cualquier tipo primitivo en una representación de cadena son las siguientes

  • Al aceptar la entrada, convierta esa entrada al tipo primitivo correcto lo antes posible en la pila de programas (generalmente en la capa de presentación)
  • Al recuperar los datos que se mostrarán, conviértalos a la representación de cadena lo más tarde posible en la pila del programa (nuevamente, generalmente en la capa de presentación)
Igor
fuente
0

Realmente no hay nada de malo en hacer esto (se hace todo el tiempo en los servicios) siempre que esté utilizando un formato no ambiguo para su fecha. Por inequívoco, quiero decir que no solo la fecha está clara (por ejemplo, MM / DD vs. DD / MM) sino también en qué zona horaria está. Así que, por adelantado, si va a representar sus fechas como texto, use un formato ISO . Prefiero las cadenas de tiempo basadas en UTC.

Pros:

  • Fecha / hora basada en estándares Las cadenas son portátiles y fáciles de entender
  • A menudo, las fechas en DB contienen un componente de tiempo. Si esto no es significativo para sus datos, en realidad puede simplificar las cosas.

Contras:

  • Tamaño de datos. El formato interno de una fecha en un DB generalmente usará mucho menos espacio que la representación de Cadena de esa fecha.
  • Por lo general, querrá incluirlo en una estructura de fecha u hora real en el cliente, por lo que puede haber tiempo adicional en el análisis.

Si alguien dijera que quería hacer esto, le preguntaría "¿por qué?" porque realmente no tiene mucho sentido. Si la razón por la que alguien quiere devolver la fecha como una Cadena es porque simplemente la mostrará directamente, esta no es una buena razón para usar Cadenas de la base de datos.

JimmyJames
fuente