Este é um problema que já encontrei algumas vezes. Imagine que você tem um registro que deseja armazenar em uma tabela de banco de dados. Esta tabela possui uma coluna DateTime chamada "date_created". Esse registro em particular foi criado há muito tempo e você não tem certeza da data exata, mas sabe o ano e o mês. Outros registros que você conhece apenas o ano. Outros registros que você conhece o dia, mês e ano.
Você não pode usar um campo DateTime, porque "maio de 1978" não é uma data válida. Se você o dividir em várias colunas, perderá a capacidade de consultar. Alguém mais se deparou com isso? Em caso afirmativo, como você lidou com isso?
Para esclarecer o sistema que estou construindo, é um sistema que rastreia arquivos. Algum conteúdo foi produzido há muito tempo, e tudo o que sabemos é "maio de 1978". Eu poderia armazená-lo em 1º de maio de 1978, mas apenas com alguma maneira de indicar que essa data é precisa apenas para o mês. Dessa forma, alguns anos depois, quando estou recuperando esse arquivo, não fico confuso quando as datas não coincidem.
Para meus propósitos, é importante diferenciar "dia desconhecido em maio de 1978" com "1º de maio de 1978". Além disso, eu não gostaria de armazenar as incógnitas como 0, como "0 de maio de 1978", porque a maioria dos sistemas de banco de dados rejeitará isso como um valor de data inválido.
fonte
Respostas:
Armazene todas as datas no campo DATE normal no banco de dados e tenha um campo de precisão adicional com a precisão do campo DATE.
date_created_accuracy: 1 = data exata, 2 = mês, 3 = ano.
Se a sua data for imprecisa (por exemplo, maio de 1980), armazene-a no início do período (por exemplo, 1º de maio de 1980). Ou se sua data for precisa para o ano (por exemplo, 1980), armazene-a como 1º de janeiro. 1980 com o valor de precisão correspondente.
Dessa maneira, é possível consultar facilmente de uma maneira um tanto natural e ainda ter noção de como as datas são precisas. Por exemplo, isso permite consultar datas entre
Jan 1st 1980
eFeb 28th 1981
, e obter datas difusas1980
eMay 1980
.fonte
select * from mytable where date_created between "1980/1/1" and "1981/2/28" and date_created_accuracy <= 2;
. Gênio.date_created_accuracy
campo. Você pode mostrar "maio de 1980" ou apenas "1980" nos resultados ou na interface do usuário se isso for tão preciso quanto o campo indica.Se você não precisar usar esse tipo de dados como informações regulares de data e hora, qualquer formato simples de string seria necessário.
Mas se você precisar manter toda a funcionalidade, existem duas soluções alternativas que podem ser consideradas, ambas exigindo informações adicionais armazenadas no banco de dados:
min date
emax date
campos, que tenham valores diferentes para dados "incompletos", mas coincidam com datas precisas.type
campo aos registros e mantenha as informações ausentes.fonte
min date
emax date
campos. Eu acho que é a solução mais flexível, precisa e fácil de usar.Isso é realmente mais uma definição de requisitos do que um problema técnico - o que você precisa focar é "como podemos definir as datas no passado" e a solução técnica fluirá.
Nas vezes em que tive que abordar algo assim, normalmente:
Às vezes, é necessário fazer algo como tornar as datas imprecisas - por exemplo, essa data pode precisar responder a uma consulta em maio de 1978. Isso é possível - basta fazer seus campos create_date 2, registros antigos obtêm 30 dias, conforme apropriado, os novos obtêm 2 valores idênticos.
fonte
A maneira mais simples de indicar se a data é precisa é criar um campo de precisão INT (1) com NULL padrão
Se a data for exata, armazene a data e a hora em "date_created" e deixe a precisão NULL
Se a data for precisa apenas para armazenar a data e hora do mês como 1º do mês com valor de precisão 1
Se a data for precisa apenas para a data do ano da loja, data de 1º de janeiro com o valor de precisão 2
Você pode usar números diferentes para armazenar valores diferentes, como primeiro trimestre, etc.
fonte
No passado, eu armazenava datas com precisão como uma data de início e uma data de término. O dia 21 de maio de 2012 seria representado como início = 12 horas, maio 21,2012 e final = 12 horas, 22 de maio de 2012. O ano de 2012 seria representado como início = 12 horas, jan1,2012 final = 12 horas, jan1,2013.
Não tenho certeza se eu recomendaria essa abordagem. Ao exibir as informações para o usuário, você precisa detectar adequadamente que um período cobre exatamente um dia para mostrar "25 de maio" em vez de dois pontos de extremidade excessivamente específicos (o que significa lidar com o horário de verão e assim por diante).
No entanto, quando você não está tentando traduzir para humanos, programar com os pontos de extremidade é muito mais fácil do que com a precisão central +. Você não acaba com muitos casos. Isso é muito legal.
fonte
Por que não armazenar duas datas.
Created_After e Created_Before. A semântica real sendo "criada em ou depois" e "criada em ou antes"
Portanto, se você souber a data exata, Created_After e Created_Before serão a mesma data.
Se você souber que foi a primeira semana de maio de 2000, Created_After = '2000-05-01' e Created_Before = '2000-05-07'.
Se você conhece maio de 1999, os valores serão '1999-05-01' e '1999-05-30'.
Se for "verão de 42", os valores serão '1942-06-01' e '1942-08-31'.
Esse esquema é simples de consultar com SQL normal e bastante fácil para um usuário não técnico seguir.
Por exemplo, para encontrar todos os documentos que podem ter sido criados em maio de 2001:
Por outro lado, para encontrar todos os documentos que foram definitivamente criados em maio de 2001:
fonte
O formato de data e hora ISO 8601 é fornecido com definição de duração, por exemplo
2012-01-01P1M
(leia-se: 2012, 1º de janeiro, período: 1 mês) é o que deve ser “em janeiro de 2012”.Eu usaria isso para armazenar os dados. Você pode precisar de um campo de banco de dados do tipo String para fazer isso. É um tópico diferente sobre como realizar uma pesquisa sensata sobre isso.
fonte
Geralmente, eu ainda as armazeno, pois as datas para o uso geral de consultas ainda são possíveis, mesmo que um pouco menos precisas.
Se é importante saber a precisão que eu tinha no passado, armazenou uma "janela" de precisão como um decimal +/- ou como uma pesquisa (dia, mês, ano etc.). Noutros casos, em vez da janela, guardo o valor da data original como uma cadeia e converto o que posso para uma data e hora, possivelmente 1978-05-01 00:00:00 e "maio de 1978" para o seu exemplo.
fonte
Quem disse? Aqui está o que você faz:
Portanto, se eu fizer uma inserção como: o
insert into thistable (Day, Month, Year) values (-1, 2, 2012);
TheDate se tornará 01/02/2013, mas saberei que é realmente uma data indeterminada em 2/2012 por causa do -1 no campo Dia.Se
insert into thistable (TheDate) values ('2/5/2012');
então o dia for 5, o mês será 2 e o ano será 2012 e, como nenhum deles é -1, saberei que esta é a data exata.Não perco a capacidade de consultar porque o gatilho de inserção / atualização garante que meus 3 campos (dia, mês, ano) sempre produzam um valor DateTime em TheDate que pode ser consultado.
fonte
Outra opção seria armazenar as datas como números inteiros do formulário
YYYYMMDD
.19510000
19510300
19510314
0
Benefícios
Você pode armazenar sua data difusa em um campo em vez de dois campos de data ou uma data e uma precisão, conforme sugerem muitas das outras respostas.
As consultas ainda são fáceis:
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 seja bastante fácil de implementar.99
o 'preenchimento' em vez do00
mês ou dia.fonte
A ISO 8601 também especifica uma sintaxe para "datas difusas". 12 de fevereiro de 2012 às 15:00 seria "2012-02-12T15" e fevereiro de 2012 poderia ser simplesmente "2012-02". Isso se estende muito bem usando a classificação lexicográfica padrão:
fonte
Aqui está a minha opinião sobre isso:
Vá da data difusa para o objeto datetime (que caberá em um banco de dados)
E então uma função que pega o objeto datetime e o move de volta para uma data difusa.
E depois um teste de unidade. Perdi alguns casos?
Há um caso de canto em que um evento que ocorreu precisamente,
2001-01-01T00:00:00.333333
mas o sistema interpretará como sendo apenas "2001", mas isso parece muito improvável.fonte
Eu trabalho para uma editora que lida com muitos livros antigos, onde geralmente não conseguimos as datas exatas para isso. Nós normalmente têm dois campos para uma determinada entrada de data, a data e um circa boolean:
Usamos o campo de data para indicar a data de algum evento ou uma data "suficientemente próxima" no caso em que não sabemos a data verdadeira. No caso de não conhecermos a data verdadeira, marcamos o
dateCirca
campo comoY
e fornecemos uma data suficientemente próxima, marcada como o "1º", comofonte
visão global
Existem muitas representações possíveis e, portanto, esquemas de banco de dados, para armazenar datas e horários nebulosos (ou mesmo datas nebulosas):
[1], [2] e [3] são todos (implicitamente) intervalos uniformes, isto é, um conjunto de (igualmente) pontos possíveis no tempo.
[4] é a mais expressiva, ou seja, ao permitir quaisquer frases ou frases possíveis (ou pelo menos arbitrariamente longas) em linguagem escrita. Mas também é o mais difícil de trabalhar. No limite, a IA em nível humano seria necessária para lidar com valores arbitrários. Na prática, o intervalo de valores possíveis precisaria ser severamente restringido, e valores 'estruturados' alternativos provavelmente seriam preferidos para muitas operações, por exemplo, classificação e pesquisa.
[5] é provavelmente o mais geral compacto representação que é (um pouco) prático.
Intervalos uniformes
Intervalos uniformes são a maneira mais simples e compacta de representar um conjunto de (possíveis) valores de data e hora.
Para [1], partes do valor de data e hora são ignoradas, isto é, as partes correspondentes a unidades mais finas que a precisão ou exatidão indicada; caso contrário, isso é equivalente a [2] e o código de precisão / exatidão é equivalente a um intervalo com as mesmas unidades (e uma quantidade implícita de 1).
[2] e [3] são expressivamente equivalentes. [1] é estritamente menos expressivo do que qualquer um, pois existem intervalos efetivos que não podem ser representados por [1], ex. uma data e hora difusa equivalente a um intervalo de 12 horas que abrange um limite de data.
[1] é mais fácil para os usuários inserirem do que qualquer outra representação e geralmente deve exigir (pelo menos um pouco) menos digitação. Se a data e a hora puderem ser inseridas em várias representações de texto, por exemplo, "2013", "2014-3", "2015-5-2", "30/07/2016 11p", "31-07-2016 18:15" , a precisão ou a exatidão também podem ser inferidas automaticamente a partir da entrada.
A exatidão ou precisão de [1] também é mais fácil de converter em um formulário a ser transmitido aos usuários, por exemplo, '2015-5 com precisão de mês' para "maio de 2015", versus "13 de maio de 2015 2p, mais ou menos 13,5 dias" (note que este último não pode ser representado por [1] de qualquer maneira).
Cordas
Na prática, os valores das strings precisarão ser convertidos em outras representações para consulta, classificação ou comparação de vários valores. Portanto, embora qualquer linguagem natural (humana) escrita seja estritamente mais expressiva que [1], [2], [3] ou [5], ainda não temos os meios de lidar com muito além das representações ou formatos padrão de texto. Dado isso, essa é provavelmente a representação menos útil por si só .
Uma vantagem dessa representação é que, na prática, os valores devem ser apresentáveis aos usuários como estão e não exigem que a transformação seja facilmente compreensível.
Distribuições de probabilidade
As distribuições de probabilidade generalizam as representações de intervalo uniformes [1], [2], [3] e (sem dúvida) são equivalentes à representação de seqüência de caracteres (geral) [4].
Uma vantagem das distribuições de probabilidade sobre as strings é que a primeira é inequívoca.
[5-1] seria apropriado para valores que (principalmente) estejam em conformidade com uma distribuição existente, por exemplo, um valor de data e hora gerado por um dispositivo cujas medidas são conhecidas (ou consideradas) como estando em conformidade com uma distribuição específica.
[5-2] é provavelmente a melhor maneira (um pouco) prática de representar de maneira compacta os valores arbitrários de 'fuzzy datetime'. É claro que a computabilidade das distribuições de probabilidade específicas usadas é importante e existem definitivamente problemas interessantes (e talvez impossíveis) a serem resolvidos ao consultar, classificar ou comparar valores diferentes, mas muito disso provavelmente já é conhecido ou resolvido em algum lugar existente. literatura matemática e estatística, então isso definitivamente se destaca como uma representação extremamente geral e inequívoca.
fonte
Eu realmente gosto da solução de James Anderson - Limitar com precisão as datas é o caminho para obter a estrutura de consulta mais flexível. Outra maneira de conseguir o mesmo é usar um centro de início, fim ou mesmo
date
mais uminterval
(disponível pelo menos no PostgreSQL , Oracle e SQLAlchemy ).fonte
No seu caso, você precisa apenas de ano, mês e dia. Ano e mês são obrigatórios, o dia é opcional. Eu usaria algo assim:
Além disso, você ainda pode usar índices de maneira muito eficaz. As filas (tiny = minus) ficam um pouco mais "complicadas" (mais longas).
fonte
1978-??-31
?Simplesmente armazenaria a hora exata das datas normais e tornaria genérica a parte da hora da data nebulosa, como 00:00:00. Eu faria todas as datas confusas no primeiro dia do mês.
Quando você consulta, você
Existem soluções melhores do que isso, mas eu pessoalmente odeio metadados (dados sobre meus dados). Ele apenas tem o hábito de ficar fora de controle depois de um tempo.
fonte