Este es un problema con el que me he encontrado algunas veces. Imagine que tiene un registro que desea almacenar en una tabla de base de datos. Esta tabla tiene una columna DateTime llamada "date_created". Este registro en particular fue creado hace mucho tiempo, y no estás realmente seguro de la fecha exacta, pero sabes el año y el mes. Otros registros que conoces solo el año. Otros registros que conoces el día, mes y año.
No puede usar un campo DateTime, porque "mayo de 1978" no es una fecha válida. Si lo divide en varias columnas, pierde la capacidad de consultar. ¿Alguien más se ha encontrado con esto? De ser así, ¿cómo lo manejaste?
Para aclarar el sistema que estoy construyendo, es un sistema que rastrea archivos. Algunos contenidos se produjeron hace mucho tiempo, y todo lo que sabemos es "mayo de 1978". Podría almacenarlo el 1 de mayo de 1978, pero solo con alguna forma de denotar que esta fecha solo es precisa para el mes. De esa manera, algunos años después, cuando estoy recuperando ese archivo, no me confundo cuando las fechas no coinciden.
Para mis propósitos, es importante diferenciar "día desconocido en mayo de 1978" con "1 de mayo de 1978". Además, no quisiera almacenar las incógnitas como 0, como "0 de mayo de 1978" porque la mayoría de los sistemas de bases de datos lo rechazarán como un valor de fecha no válido.
fuente
Respuestas:
Almacene todas las fechas en el campo DATE normal en la base de datos y tenga un campo de precisión adicional de la precisión del campo DATE en realidad.
date_created_accuracy: 1 = fecha exacta, 2 = mes, 3 = año.
Si su fecha es confusa (por ejemplo, mayo de 1980) guárdela al inicio del período (por ejemplo, 1 de mayo de 1980). O si su fecha es exacta al año (por ejemplo, 1980), guárdela como el 1 de enero. 1980 con el correspondiente valor de precisión.
De esta manera, puede consultar fácilmente de una manera algo natural y aún tener noción de cuán precisas son las fechas. Por ejemplo, esto le permite consultar fechas entre
Jan 1st 1980
yFeb 28th 1981
, y obtener fechas difusas1980
yMay 1980
.fuente
select * from mytable where date_created between "1980/1/1" and "1981/2/28" and date_created_accuracy <= 2;
. Genio.date_created_accuracy
campo. Puede mostrar "mayo de 1980" o simplemente "1980" en los resultados o la interfaz de usuario si eso es tan preciso como lo indica el campo.Si no necesita usar este tipo de datos como información regular de fecha y hora, cualquier formato de cadena simple lo haría.
Pero si necesita mantener toda la funcionalidad, se me ocurren dos soluciones alternativas, ambas requieren información adicional almacenada en la base de datos:
min date
ymax date
campos, que tienen valores diferentes para datos "incompletos", pero coincidirán para fechas precisas.type
campo a los registros y guarde qué información falta.fuente
min date
ymax date
campos. Creo que es la solución más flexible, precisa y fácil de usar.Esta es realmente más una definición de requisitos que un problema técnico: en lo que debe centrarse es en "cómo podemos definir las fechas en el pasado" y la solución técnica fluirá.
Las veces que he tenido que acercarme a algo como esto, típicamente:
A veces, uno debe hacer algo como hacer que las fechas sean difusas, por ejemplo, que una fecha deba responder a una consulta para cualquier cosa en mayo de 1978. Esto es factible: solo haga sus campos create_date 2, los registros antiguos obtienen un 30 los días se extienden según corresponda, los nuevos obtienen 2 valores idénticos.
fuente
La forma más sencilla de indicar si la fecha es precisa es crear un campo de precisión INT (1) con NULL predeterminado
Si la fecha es precisa, guarde la fecha y hora en "date_created" y deje la precisión NULL
Si la fecha solo es exacta al mes, guarde la fecha y hora como el 1er mes con un valor de precisión 1
Si la fecha solo es precisa para la fecha y hora de la tienda del año 1 de enero con un valor de precisión 2
Puede usar diferentes números para mantener diferentes valores, como el primer trimestre, etc.
fuente
En el pasado, he almacenado fechas con precisión como una fecha de inicio y una fecha de finalización. El día may21,2012 se representaría como start = 12 am, may21,2012 y end = 12 am,may22,2012. El año 2012 se representaría como inicio = 12 a.m., enero1,2012 final = 12 a.m., enero1,2013.
No estoy seguro si recomendaría este enfoque. Al mostrar la información al usuario, debe detectar correctamente que un rango de fechas cubre exactamente un día para mostrar "25 de mayo" en lugar de dos puntos finales demasiado específicos (lo que significa lidiar con el horario de verano, etc.).
Sin embargo, cuando no está tratando de traducir a humanos, la programación con los puntos finales es mucho más fácil que con la precisión central +. No terminas con muchos casos. Eso es muy lindo.
fuente
¿Por qué no guardar dos fechas?
Created_After y Created_Before. La semántica real es "creada en o después" y "creada en o antes"
Entonces, si conoce la fecha exacta, Created_After y Created_Before serán la misma fecha.
Si sabe que fue la primera semana de mayo de 2000, Created_After = '2000-05-01' y Created_Before = '2000-05-07'.
Si conoce mayo de 1999, los valores serán '1999-05-01' y '1999-05-30'.
Si es "Verano de '42", entonces los valores serían '1942-06-01' y '1942-08-31'.
Este esquema es simple de consultar con SQL normal, y bastante fácil de seguir para un usuario no técnico.
Por ejemplo, para encontrar todos los documentos que podrían haberse creado en mayo de 2001:
Por el contrario, para encontrar todos los documentos que se crearon definitivamente en mayo de 2001:
fuente
El formato de fecha y hora ISO 8601 viene con definición de duración, p. Ej.
2012-01-01P1M
(léase: 2012, 1 de enero, período: 1 mes) es lo que debería ser "en enero de 2012".Lo usaría para almacenar los datos. Es posible que necesite un campo de base de datos de tipo Cadena para hacerlo. Es un tema diferente cómo realizar una búsqueda sensata sobre eso.
fuente
En general, todavía los almaceno como fechas para consultas generales, aún es posible aunque sea un poco menos preciso.
Si es importante saber la precisión que tengo en el pasado, o bien almacené una "ventana" de precisión como un decimal +/- o como una búsqueda (día, mes, año, etc.). En otros casos, en lugar de la ventana, simplemente almaceno el valor de la fecha original como una cadena y convierto lo que puedo a una fecha y hora, posiblemente 1978-05-01 00:00:00 y "mayo de 1978" para su ejemplo dado.
fuente
¿Dice quién? Esto es lo que haces:
Entonces, si hago una inserción como:
insert into thistable (Day, Month, Year) values (-1, 2, 2012);
entonces TheDate se convertirá en 2/1/2013, pero sabré que realmente es una fecha indeterminada en 2/2012 debido al -1 en el campo Día.Si
insert into thistable (TheDate) values ('2/5/2012');
entonces el día será 5, el mes será 2 y el año será 2012, y debido a que ninguno de ellos es -1, sabré que esta es la fecha exacta.No pierdo la capacidad de consultar porque el activador de inserción / actualización se asegura de que mis 3 campos (Día, Mes, Año) siempre produzcan un valor DateTime en TheDate que se puede consultar.
fuente
Otra opción sería almacenar las fechas como enteros del formulario
YYYYMMDD
.19510000
19510300
19510314
0
Beneficios
Puede almacenar su fecha difusa en un campo en lugar de dos campos de fecha o una fecha y una precisión como sugieren muchas de las otras respuestas.
Las consultas siguen siendo fáciles:
SELECT * FROM table WHERE thedate>=19510000 and thedate<19520000
SELECT * FROM table where thedate>=19510300 and thedate<19510400
SELECT * FROM table where thedate=19510314
NOTAS
GetDateString(int fuzzyDate)
que sea bastante fácil de implementar.99
el 'relleno' en lugar del00
mes o día.fuente
ISO 8601 también especifica una sintaxis para "fechas difusas". El 12 de febrero de 2012 a las 3pm sería "2012-02-12T15" y febrero de 2012 podría ser simplemente "2012-02". Esto se extiende muy bien usando la clasificación lexicográfica estándar:
fuente
Aquí está mi opinión sobre esto:
Ir de la fecha difusa al objeto datetime (que se ajustará a una base de datos)
Y luego una función que toma el objeto datetime y lo mueve de nuevo a una fecha difusa.
Y luego una prueba unitaria. ¿Me perdí algún caso?
Hay un caso de esquina en el que ocurrió un evento que ocurrió con precisión
2001-01-01T00:00:00.333333
pero que el sistema interpretará como solo "2001", pero eso parece muy poco probable.fuente
Trabajo para una editorial que se ocupa de muchos libros antiguos donde a menudo no podemos obtener las fechas exactas de las cosas. Normalmente tenemos dos campos para una entrada de fecha dada, la fecha y un booleano circa :
Usamos el campo de fecha para indicar la fecha de algún evento, o una fecha que está "lo suficientemente cerca" en el caso de que no sepamos la fecha verdadera. En el caso de que no sepamos la fecha verdadera, marcamos el
dateCirca
campo comoY
y damos una fecha lo suficientemente cercana, que está marcada como "1ra", comofuente
Visión de conjunto
Hay muchas representaciones posibles, y por lo tanto esquemas de bases de datos, para almacenar fechas y horas difusas (o incluso solo fechas difusas):
[1], [2] y [3] son todos (implícitamente) intervalos uniformes, es decir, un conjunto de puntos (igualmente) posibles en el tiempo.
[4] es el más expresivo, es decir, cuando permite oraciones o frases escritas posibles (o al menos arbitrariamente largas). Pero también es el más difícil de trabajar. En el límite, se requeriría una IA de nivel humano para manejar valores arbitrarios. Prácticamente, el rango de valores posibles necesitaría restringirse severamente, y probablemente se preferirían valores 'estructurados' alternativos para muchas operaciones, por ejemplo, ordenar, buscar.
[5] es probablemente la representación compacta más general que es (algo) práctica.
Intervalos uniformes
Los intervalos uniformes son la forma compacta más simple de representar un conjunto de valores (posibles) de fecha y hora.
Para [1], se ignoran porciones del valor de fecha y hora, es decir, las porciones correspondientes a unidades más finas que la precisión o exactitud indicada; de lo contrario, esto es equivalente a [2] y el código de precisión / exactitud es equivalente a un intervalo con las mismas unidades (y una cantidad implícita de 1).
[2] y [3] son expresamente equivalentes. [1] es estrictamente menos expresivo que cualquiera de los dos, ya que existen intervalos efectivos que no pueden representarse por [1], ej. una fecha y hora difusa equivalente a un intervalo de 12 horas que abarca un límite de fecha.
[1] es más fácil de ingresar para los usuarios que cualquier otra representación y generalmente debería requerir (al menos un poco) menos tipeo. Si se pueden ingresar fechas y horas en varias representaciones de texto, por ejemplo, "2013", "2014-3", "2015-5-2", "30/7/2016 11p", "2016-07-31 18:15" , la precisión o exactitud también podría inferirse automáticamente de la entrada.
La precisión o precisión de [1] también es más fácil de convertir a un formulario para ser transmitido a los usuarios, por ejemplo, '2015-5 con precisión de mes' a "mayo de 2015", frente a "13 de mayo de 2015 2p, más o menos 13.5 días" (aunque tenga en cuenta que este último no puede ser representado por [1] de todos modos).
Instrumentos de cuerda
Prácticamente, los valores de cadena deberán convertirse a otras representaciones para consultar, ordenar o comparar valores múltiples. Entonces, si bien cualquier lenguaje natural (humano) escrito es estrictamente más expresivo que [1], [2], [3] o [5], todavía no tenemos los medios para manejar mucho más allá de las representaciones o formatos de texto estándar. Dado eso, esta es probablemente la representación menos útil por sí misma .
Una ventaja de esta representación es que, en la práctica, los valores deben ser presentables a los usuarios tal cual y no requieren transformación para ser fácilmente comprensibles.
Distribuciones de probabilidad
Las distribuciones de probabilidad generalizan las representaciones de intervalo uniformes [1], [2], [3] y (posiblemente) son equivalentes a la representación de cadena (general) [4].
Una ventaja de las distribuciones de probabilidad sobre las cadenas es que la primera es inequívoca.
[5-1] sería apropiado para valores que (en su mayoría) se ajustan a una distribución existente, por ejemplo, una salida de valor de fecha y hora de un dispositivo para el que se sabe (o se piensa) que las mediciones se ajustan a una distribución específica.
[5-2] es probablemente la mejor forma (algo) práctica de representar de forma compacta los valores arbitrarios de 'fecha y hora difusa'. Por supuesto, la computabilidad de las distribuciones de probabilidad específicas utilizadas es importante y definitivamente hay problemas interesantes (y tal vez imposibles) que se deben resolver al consultar, ordenar o comparar diferentes valores, pero es probable que mucho de esto ya se conozca o se resuelva en algún lugar de los existentes. literatura matemática y estadística, por lo que definitivamente es una representación extremadamente general y poco ambigua.
fuente
Realmente me gusta la solución de James Anderson : limitar con precisión las fechas es la forma de obtener la estructura de consulta más flexible. Otra forma de lograr lo mismo es usar un inicio, un final o incluso un centro
date
más uninterval
(disponible al menos en PostgreSQL , Oracle y SQLAlchemy ).fuente
En su caso solo necesita año, mes y día. Se requieren año y mes, el día es opcional. Yo usaría algo así:
Además, aún puede usar índices de manera muy efectiva. Las (minúsculas = menos, colas se vuelven un poco más "complicadas" (más largas).
fuente
1978-??-31
?Simplemente almacenaría la hora exacta para las fechas normales y haría que la parte de la fecha difusa sea genérica como 00:00:00. Luego haría todas las fechas difusas el 1 de cada mes.
Cuando consulta, usted
Hay mejores soluciones que esta, pero personalmente odio los metadatos (datos sobre mis datos). Simplemente tiene la costumbre de salirse de control después de un tiempo.
fuente