Estoy tan ridículamente frustrado por tener que usar los valores de DateTime para conjuntos de datos que realmente son "solo un día". Los cumpleaños son el ejemplo más común, pero esto aparece en las aplicaciones comerciales todo el tiempo.
Me he acostumbrado a configurar la parte Hora de los registros "solo de fecha" en "mediodía" (lo que evita que la fecha cambie sin importar la zona horaria). Esto parece un truco, y siempre encuentro errores de desarrolladores junior que se tropiezan con este problema.
El tiempo siempre es relativo a un punto fijo. 4PM son 4 horas después del meridiano, o mediodía. El punto más alto del sol en tránsito es observable y nos permite establecer un sistema de coordenadas. 3 horas antes del mediodía (Ante Meridian), 2 horas después del mediodía, 1441899402938 milisegundos desde el 1 de enero de 1970. Para las personas criadas en un mundo cartesiano, esta es una segunda naturaleza.
Pero nuestro calendario es anterior a Descartes. Mi argumento es que se considera más propiamente como una enumeración sobre la cual se aplica una función de módulo. El lunes sigue al domingo, y así sucesivamente hasta llegar al hecho de que el domingo sigue al sábado. No hay positivo ni negativo, es un módulo o valor absoluto.
Del mismo modo con años repitiendo. Cada 365 días (más o menos) hay varios días especiales para mí: cumpleaños, aniversarios, cumpleaños de niños, etc. etc. Las aplicaciones de programación comercial abundan con ejemplos de reuniones cada siete días, el primer martes del mes, etc. Simplemente porque PODEMOS mapear esto en un número de coma flotante, y en verdad mapearlo en dicho número resuelve MUCHOS problemas que son realmente difíciles a la antigua usanza, pero eso no significa que sea la única forma de hacerlo.
El conocimiento y la comprensión de la naturaleza de "clavija cuadrada en un agujero redondo" del uso de DateTimes para almacenar fechas lo convierten en un mejor programador en mi opinión.
¿Existe algún valor en una aplicación explícitamente pensada como una aplicación de programación para definir una clase de fecha, o es "establecer todo el tiempo al mediodía" el mejor enfoque? ¿Qué problemas puede haber con el uso de DateTime y la configuración del componente Time en Noon? ¿Se puede explicar el cambio de zona horaria en este enfoque? He usado MomentJS, pero creo que es solo una mejor clase de fecha.
fuente
Respuestas:
En primer lugar, eliminemos una cosa: los cumpleaños son una cosa, las fechas de nacimiento son otra. Un cumpleaños es un tipo de datos exótico porque carece no solo de componentes de horas, minutos, etc., sino que también carece del componente de año. Si realmente desea lidiar con los cumpleaños, le recomendaría inventar su propio tipo de datos que no contenga más que un número de mes y un número de día, y que no esté relacionado con ninguno de los tipos de datos de fecha y hora incorporados.
Por otro lado, si también desea realizar un seguimiento del año de nacimiento, lo que tiene no son cumpleaños, sino fechas de nacimiento . Entonces, la pregunta ahora es por qué no hay un tipo de datos solo de fecha, para que pueda representar convenientemente las fechas de nacimiento, y en cambio los idiomas populares parecen obligarlo a usar algún tipo que también incluya un componente de tiempo.
Permítanme mencionar brevemente que no es cierto que todos los lenguajes de programación solo ofrezcan tipos de datos temporales que incluyan un componente de tiempo. Me he encontrado con tipos de datos solo de fecha en RDBMS y en sus dialectos SQL correspondientes. Pero eso es irrelevante: el hecho de que estos tipos de datos existan no significa que sean buenos, y los RDBMS tienen una larga historia de confusión de almacenamiento con representación.
Comprenderá por qué es una mala idea tener esos tipos de datos solo de fecha en el momento en que se da cuenta de que el tiempo es una coordenada. La mayoría de las personas tienen una idea muy vaga de qué hora es, y esta idea contiene nociones culturales arcanas como años, meses y días, sin darse cuenta de que estas nociones son exclusivamente representativas : solo son útiles para representar el tiempo para un humano y para recibir tiempo como entrada de un humano. En cualquier capa debajo del control de la GUI de entrada de tiempo real, el tiempo debe representarse, y generalmente se representa, como una coordenada de tiempo, que es un número único de unidades de tiempo desde cierto origen.
Por ejemplo, en el
DateTime
tipo de datos de Microsoft Dotnet, la unidad de tiempo es de 100 nanosegundos, y el origen del tiempo es 12:00 de la medianoche, 1 de enero de 0001 CEOtro ejemplo de una notación arcana, exclusivamente representativa, es la medición de ángulos usando grados, minutos de un grado y segundos de un grado. Por supuesto, para realizar cualquier cálculo útil, debe usar radianes internamente y, si es necesario, convertir hacia y desde grados al interactuar con un usuario humano.
Por lo tanto, no confunda la representación legible por humanos de una medición con la naturaleza real de la medición. Muy a menudo, el método ideal para realizar una medición, que se asemeja más a la naturaleza de la medición, es muy diferente de la representación legible por los humanos de esa medición.
A la luz de todo esto, su solicitud de un tipo de datos temporales que represente solo fechas es similar a una solicitud de un tipo de datos angular que solo sea capaz de representar grados, evitando explícitamente una mayor precisión. Tal tipo de datos sería bastante limitado y, en última instancia, inútil, porque de todos modos tendría que convertirlo hacia y desde radianes para poder hacer algo útil con él.
Su problema con la fecha de nacimiento es que tiene una coordenada de tiempo imprecisa : la persona, por supuesto, nació en un momento específico en el tiempo, pero el hospital no registró la hora y los minutos, o nosotros no. preocuparse por ellos. Entonces, lo que realmente está sucediendo es que su coordenada de fecha y hora de nacimiento tiene un margen de error, una tolerancia o incertidumbre si lo desea, y es mejor tratarlo como tal: póngalo exactamente en el medio del día, y considere una incertidumbre implícita de +12 a 12 horas. Y esa es precisamente la solución a la que ha llegado intuitivamente.
fuente
Las fechas y horas son diferentes según el contexto, y necesita muchos tipos distintos para cubrir todos los casos de uso.
El
DateTime
tipo presente en muchos idiomas representa un punto preciso en el tiempo ("tiempo instantáneo"). Más allá de esto, tenemos una serie de conceptos relativos o temporales "humanos", como días calendario, fechas recurrentes, meses, años, etc., que en muchos casos son ambiguos y dependen del contexto. Estos tipos no son tan universalmente útiles, pero necesarios en dominios de aplicación específicos como calendarios, herramientas de programación y otras aplicaciones que interactúan con conceptos humanos del tiempo.Si está escribiendo algo así como una aplicación de calendario, definitivamente se beneficiaría al usar una biblioteca como Joda-time que proporciona un conjunto más rico de tipos de tiempo. Por ejemplo
LocalDate
, una fecha sin tiempo. Esto tiene una semántica diferente a la ordinariaDateTime
con la parte de tiempo establecida en cero, ya que elDateTime
todavía indica un punto específico en el tiempo (medianoche en una zona horaria específica), mientras queLocalDate
indica todo el día y no está vinculado a una zona horaria específica. Esto también significa que no puede traducir directamente uno al otro.LocalDate
es ciertamente más simple queDateTime
porque no tiene que tomar en cuenta las zonas horarias, pero debe tener en cuenta los otros problemas, por ejemplo, que la fecha actual puede retroceder cuando cruza una zona horaria y que el mismo instante en el tiempo puede corresponden a diferentes fechas en diferentes zonas horarias. Si está utilizando fechas locales en aplicaciones web o en red, debe tener mucho cuidado con estos problemas. ¡Eliminar la parte de tiempo de una fecha no resuelve el problema fundamental de las zonas horarias! Y si toma en cuenta las fechas históricas y las diferentes culturas, se vuelve aún más complicado, ya que la misma fecha puede corresponder a instancias muy diferentes en el tiempo, por ejemplo, el calendario juliano versus el gregoriano.Ahora pregunta por qué los idiomas no tienen algo como
LocalDate
incorporado . En primer lugar, algunos lenguajes como SQL y Visual Basic tienen un tipo de fecha sin parte de tiempo. Y Java también ha agregado unLocalDate
en la versión reciente. Pero otras plataformas como .Net no. Solo los diseñadores de idiomas realmente pueden responder por qué esto no está incluido en la biblioteca estándar, pero supongo que el "tiempo instantáneo" es conceptualmente simple y universalmente útil, mientras que los otros conceptos de tiempo solo son útiles para dominios de aplicación específicos (como calendarios, etc. .). Por lo tanto, tiene sentido dejar que el desarrollador de la aplicación escriba tipos personalizados para manejar los casos de uso más complejos, o dejar que lo maneje una biblioteca de terceros (como Joda-time).fuente
Esto probablemente se deba a que el calendario es complicado y se usa de muchas maneras diferentes, por lo que nadie ha podido calcular una clase que sea simple pero lo suficientemente general como para ser útil en muchos campos.
El tipo de fecha que se encuentra comúnmente en los lenguajes de programación se puede usar para fechar con precisión las transacciones en un sistema informático. Es probable que otros casos de uso requieran una biblioteca personalizada.
Aquí hay una breve lista de datos sobre calendarios, que demuestran su complejidad: la mayoría de ellos son históricos, por lo que si restringe su atención a las fechas posteriores al 1.1.1970, esto no lo afectará. Sin embargo, si su solicitud necesita trabajar con fechas que ocurrieron antes de fines del siglo XIX, entonces estos hechos serían importantes. Los posibles casos de uso son bases de datos históricas de todo tipo (libros, genealogía) pero también activos de grandes empresas u organizaciones que todavía están en actividad hoy en día.
Todos estos hechos se citan de las excelentes preguntas frecuentes que se encuentran en la biblioteca de calendario para OCaml escrita por Julien Signolles.
El calendario juliano fue introducido por Julio César en el 45 a. C. Era de uso común hasta el año 1500, cuando los países comenzaron a cambiar al calendario gregoriano (sección 2.2). Sin embargo, algunos países (por ejemplo, Grecia y Rusia) lo usaron en la década de 1900, y la iglesia ortodoxa en Rusia todavía lo usa, al igual que otras iglesias ortodoxas.
El cambio del calendario juliano al gregoriano no se produjo de manera uniforme y, según el año de cambio, se han eliminado de 10 a 13 días. Por ejemplo, en Francia el 9 de diciembre de 1582 fue seguido por el 20 de diciembre de 1582 y en Grecia el 9 de marzo de 1924 fue seguido por el 23 de marzo de 1924.
Incluso en la era moderna, se utilizan muchos calendarios diferentes (gregoriano, ortodoxo, islámico y chino) para citar algunos, que utilizan diferentes formas de calcular años y aniversarios o la fecha de las celebraciones religiosas.
Ahora espera un tipo de fecha incluido con operaciones útiles para operaciones comerciales generales. Supongo que no existen las operaciones comerciales generales. Por ejemplo, en el mundo financiero, necesitamos calcular:
Las fracciones de año (como "6 meses" corresponde a "0.5"), que se utilizan junto con una tasa de interés para calcular el interés real de un préstamo para un plazo determinado. Hay 6 a 10 recetas para calcular estas fracciones, cada una de las cuales difiere en la forma en que manejan la duración de un año bisiesto, la posición del período con respecto al último día de febrero y la duración de un mes.
Fecha límite, cuando calculamos aniversarios, utilizamos un calendario comercial y una regla (elegida de un conjunto de más de 6 reglas diferentes) para cambiar un aniversario de un día festivo a un día hábil.
Para las personas que trabajan en la industria financiera, cualquier tipo de calendario que no implemente todas estas funciones y reglas es inútil. Es probable que muchas otras industrias tengan otros tipos de hábitos y convenciones que requieren cálculos personalizados en el calendario.
Si necesita realizar un seguimiento de un solo día calendario, la mejor manera es probablemente usar un número entero grande que represente el día juliano de ese día calendario. Los algoritmos para convertir de ida y vuelta del día juliano al día calendario, que se describe con año, mes y calendario, son ampliamente conocidos y probados exhaustivamente, para que pueda implementarlos fácilmente en su aplicación, y descubrir qué regla es pertinente en su caso para calcular el aniversario de un evento que ocurre en el 29 de febrero.
fuente
Creo que Mike Nakis en su respuesta anterior hace un mejor trabajo que yo al explicar cómo el tiempo en general es una coordenada medida absoluta y cualquier otra comunicación, supuesto estado o persistencia de esa coordenada de tiempo es simplemente una representación abstracta de dicha coordenada de tiempo.
Usted habla de tales representaciones cuando se refiere al Día de la Semana como simplemente una especie de módulo de representación de un punto en el tiempo real. En realidad es algo más complicado que eso. Si se le asignó la tarea de escribir una función que devolverá el Día de la semana para un momento determinado, considere la siguiente información que necesitará como entrada para dicho algoritmo. Necesitará el punto en el tiempo, el Calendario, la zona horaria a tener en cuenta (tenga en cuenta que las zonas horarias cambian TODO EL TIEMPO, por lo que debe saber cuándo comenzó esa zona horaria efectiva cuando terminó en coordenadas de tiempo específicas. ¡cambiaron los suyos, por ejemplo!), y si el horario de verano está vigente, esto también cambia con el tiempo. Ahora considere si le dieron una fecha y hora en la zona horaria local,
Puedes ver lo complicada que puede ser esta pregunta aparentemente simple.
Sé el dolor que siente cuando estaba en su lugar en un momento arreglando todos los errores en una aplicación de programación de visitas para un producto que fue escrito por desarrolladores inexpertos. Todo el asunto tuvo que ser desechado.
El tiempo es de hecho una coordenada, pero además de una simple Fecha, considere otros datos sensibles al tiempo que podrían ser necesarios como:
Duración: un lapso de milisegundos que puede ocurrir que significa una longitud o paso del tiempo sin coordenadas de tiempo específicas especificadas. Un caso de uso podría ser,
Intervalo: un rango de tiempo entre dos coordenadas de tiempo específicas. Un caso de uso en el que es posible que desee considerar un intervalo.
Otro punto rápido que quería hacer es que hiciste un comentario sobre los números de punto flotante para los datos basados en el tiempo y no lo aconsejo. La aritmética de punto flotante inevitablemente conduce a errores de redondeo que pueden no proporcionarle una medición tan precisa como sea necesaria para el tiempo.
En conclusión, toda esta información conduce inevitablemente a las siguientes consideraciones de diseño:
fuente
En resumen, porque la mayoría de los tipos de tiempo basados en computadora se centran en manejar el problema de hora y zona horaria correctamente.
Hay 2 casos extremos que no se atienden bien con el enfoque habitual. Establecer un punto en el tiempo que esté al otro lado de un cambio de horario de verano utilizando la hora local, que luego se convierte en el UTC por una capa de abstracción inferior, y luego te hace 1 hora más temprano / tarde para tu reunión.
El otro es (según la pregunta) modelar información de fecha arbitraria, como registrar la fecha de nacimiento de una persona. Imagine el caso en el que nacen dos personas al mismo tiempo, una en Nueva Zelanda y la otra en Hawai. La probabilidad es que tengan diferentes fechas de nacimiento en sus pasaportes, y si la persona nacida en Hawai se muda a Nueva Zelanda, se la considerará un día mayor que la persona nacida en Nueva Zelanda, a pesar de haber vivido exactamente el mismo tiempo.
La sugerencia en la pregunta como establecer la fecha para tener una hora del mediodía, UTC funcionará, casi en todas partes. Las compensaciones de UTC varían de -12 a +14, por lo que hay algunos lugares en el Pacífico donde este enfoque fallará. Tiendo a tratar estos tipos de datos como cadenas, en un formato aaaammdd, y si tengo que hacer cálculos de comparación entre dos fechas, esto se puede hacer de forma segura como una comparación de cadenas. Al hacer comparaciones delta (por ejemplo, entre la fecha y ahora, o cuánto tiempo hasta que alcancen la edad X), debe asegurarse de que todas las fechas se creen en el mismo desplazamiento UTC, y luego puede usar las funciones de hora estándar para hacer el trabajo.
fuente
Date
tipo de datos, solo se lleva aString
Por las mismas razones, creo, que los valores de DateTime generalmente se especifican en UTC: simplicidad y confiabilidad . El punto de un valor de DateTime es especificar un único punto en el tiempo que no se vea afectado por la zona horaria, el horario de verano, el calendario y otros ajustes locales. Los valores de fecha y hora especifican un instante (hasta el límite de la resolución del tipo), no un período de tiempo o un conjunto de horas. Estas limitaciones permiten comparar los valores de DateTime de una manera confiable, predecible y sin complicaciones.
Intentar especificar una fecha con un valor DateTime es como intentar usar un punto para especificar un área.Puede hacer que eso funcione usando una convención, como "este punto representa el centro de un círculo con un radio de 100 m", pero hay muchos problemas allí: todos deben usar la misma convención, usted necesita escribir un montón de código de soporte para hacer que trabajar con el tipo incorrecto sea menos doloroso, y está prácticamente garantizado que en algún momento necesitará especificar un área que sea más grande o más pequeña que el área convencional. Lo mismo ocurre con las fechas: puede usar 'mediodía' como la hora convencional para especificar fechas, pero luego ingresa a las zonas horarias porque las personas esperan especificar fechas en su hora local en lugar de UTC. E incluso si encuentra una manera satisfactoria de usar un DateTime para especificar una fecha, necesitará más información para saber si es una fecha absoluta o relativa: ¿es el 4 de julio? ¿1776 o cada 4 de julio? ¿Qué pasa si quieres repetir usando algún otro período? Y los calendarios tienen todo tipo de problemas locos: algunos meses son más largos que otros, algunos años son más largos que otros, algunos días son incluso más largos que otros, y algunos calendarios tienen lagunas. No querrá resolver estos problemas solo durante días enteros, porque los mismos problemas surgen por períodos más cortos: probablemente le gustaría poder escribir código que exprese "tome 1 píldora cada 4 horas" tan fácilmente como "el el grupo se reúne cada tercer viernes ".
Entonces, hay muchas complicaciones involucradas al trabajar con fechas. Es relativamente fácil (sin juego de palabras) proporcionar un tipo que especifique un punto en el tiempo y trabajar con él como lo haría con un número, pero es extremadamente difícil proporcionar un tipo que aborde todas las formas en que se usan las fechas.
Como otros han señalado, no son lenguajes y bibliotecas que proporcionan un buen apoyo para las fechas, y es a menudo una buena idea para usarlos dado que es muy difícil conseguir el código de fecha relacionada con la razón.
fuente
Hay muchos tipos de este tipo en varias bibliotecas para varios idiomas. Es casi seguro que haya uno para su idioma actual. El paquete de utilidades Java tenía una API horrible para los cálculos de tiempo, pero la introducción del paquete java.time ha mejorado mucho la vida. Consulte java.time.LocalDate, que contiene un valor año-mes-día, o java.time.MonthDay, que contiene solo un número de mes y día.
fuente
La manipulación calendárica es uno de los aspectos menos conocidos de la informática. Se han escrito libros completos sobre el tema. @MichealBlackburn tiene toda la razón al solicitar un tipo de datos solo de fecha, uno que no se resuelva hasta un punto en una línea de tiempo, sujeto a reinterpretación. Históricamente, ha habido disputas legítimas sobre el significado de una fecha. Uno no tiene que buscar más allá de la adopción del calendario gregoriano para descubrir cuán complejo puede llegar a ser. Además, los años no siempre han comenzado el 1 de enero, incluso en Europa occidental y sus colonias ( por ejemplo , Gran Bretaña y América británica comenzaron el año el 25 de marzo).
fuente
En respuesta a:
La razón más común podría ser "porque no es necesario". Si desea una fecha y hora que no se preocupe por horas, minutos, segundos, etc., simplemente debe inicializarla así:
Si lo desea, puede extender DateTime usted mismo:
Nota: Estoy ignorando intencionalmente la hora y zona horaria predeterminadas. Realmente no importa en qué los configures, siempre que sean los mismos para todos
Date
. Puede presentar un caso para UTC. Puede presentar un caso para usar la zona horaria en la que se encuentra su servidor; de cualquier manera, no creo que sea importante para representar un valor impreciso comoDate
. Lo mismo con el tiempo predeterminado: puede ponerlo en 0, puede hacerlo al mediodía. No importa. Si Facebook me envía una notificación de cumpleaños a las 00:01 pero nací a las 23:59, realmente no me importa, y no me ofende que hayan faltado más de 12 horas.Lo anterior está en Java, pero funcionaría de manera similar en cualquier lenguaje con una
DateTime
herencia y. Java en realidad tiene numerosas formas de resolver esto, y lo anterior está en desuso (quieren que lo usesCalendar
ahora). Pero, como otros publicados en los comentarios, algunos idiomas realidad hacen proporcionar unaDate
clase, presumiblemente por esta razón.Con toda probabilidad, cada
Date
implementación es probablemente solo un contenedor para el lenguajeDateTime
y pone a cero el tiempo. De lo contrario, necesitaría un código duplicado para resolver problemas como la cantidad de días entre dos fechas / fechas y horas, o si dosDate
s son iguales (¿Qué pasa con el 29 de febrero y el 1 de marzo?). Ese tipo de cosas generalmente se resuelven en laDateTime
clase. Tiene sentido reutilizar el mismo código para aDate
.fuente
LocalDate
oDate
tiene que 'rodar por su cuenta'.new Date(2000, 1, 1);
ynew Date(2000, 1, 1);
? ¿Puedes decir cuál tiene horas, minutos y segundos vacíos debajo? Si le preocupa que aparezcan funciones adicionales (como setMinutes ()), entonces podría tomar la ruta deDate
envolver enDateTime
lugar de heredar de él, y luego solo expondrá setYear, setMonth, setDay, etc. Y ciertamente no es menos correcto que el DateTime de la biblioteca que está utilizando.