Como os valores DATETIME funcionam no SQLite?

110

Estou criando aplicativos Android e preciso salvar a data / hora do registro de criação. Os documentos SQLite dizem, entretanto, "SQLite não tem uma classe de armazenamento separada para armazenar datas e / ou horas" e é "capaz de armazenar datas e horas como valores TEXTO, REAL ou INTEGER".

Existe uma razão técnica para usar um tipo em vez de outro? E uma única coluna pode armazenar datas em qualquer um dos três formatos, linha a linha?

Vou precisar comparar as datas mais tarde. Por exemplo, em meus aplicativos, mostrarei todos os registros criados entre a data A até a data B. Estou preocupado porque não ter uma coluna DATETIME verdadeira pode dificultar as comparações.

Khairil Ushan
fonte

Respostas:

83

SQlite não tem um tipo específico de data e hora. Você pode usar TEXT, REALou INTEGERtipos, o que se adapte às suas necessidades.

Direto do DOCS

O SQLite não tem uma classe de armazenamento separada para armazenar datas e / ou horas. Em vez disso, as funções integradas de data e hora do SQLite são capazes de armazenar datas e horas como valores TEXT, REAL ou INTEGER:

  • TEXTO como strings ISO8601 ("AAAA-MM-DD HH: MM: SS.SSS").
  • REAL como números de dias julianos, o número de dias desde o meio-dia em Greenwich em 24 de novembro de 4714 aC de acordo com o calendário gregoriano proléptico.
  • INTEGER como Unix Time, o número de segundos desde 1970-01-01 00:00:00 UTC.

Os aplicativos podem escolher armazenar datas e horas em qualquer um desses formatos e converter livremente entre os formatos usando as funções integradas de data e hora.

As funções internas de data e hora do SQLite podem ser encontradas aqui .

neo108
fonte
11
Importante observar - todos os métodos de armazenamento de datas usam formatos que podem ser comparados usando os operadores padrão =, <,> e BETWEEN.
Larry Lustig
2
"SQLite não tem uma classe de armazenamento separada para armazenar datas e / ou horas" - exceto que tem tipos DATE e DATETIME que nunca são mencionados na documentação
Slabko
12
@Slabko Não faz. SQLite permite qualquer coisa (incluindo DATETIME) como tipo declarado de uma coluna. Com base nisso, dá a essa coluna uma afinidade com uma classe de armazenamento (tem até o exemplo de como isso funciona para DATETIME na documentação). Essa afinidade é mais como uma dica, pois cada entrada da coluna pode realmente ter uma classe de armazenamento diferente. Uma classe de armazenamento ainda é um passo mais fraco do que um tipo e pode ser apoiada por vários tipos. Então, sim, você pode usar DATETIME. Não, na verdade não oferece suporte como um tipo ou classe de armazenamento. Sim, a documentação realmente contém a palavra "DATETIME".
Jasper
20

O SQLite não tem uma classe de armazenamento separada para armazenar datas e / ou horas. Em vez disso, as funções integradas de data e hora do SQLite são capazes de armazenar datas e horas como valores TEXT, REAL ou INTEGER:

TEXTO como strings ISO8601 ("AAAA-MM-DD HH: MM: SS.SSS"). REAL como números de dias julianos, o número de dias desde o meio-dia em Greenwich em 24 de novembro de 4714 aC de acordo com o calendário gregoriano proléptico. INTEGER como Unix Time, o número de segundos desde 1970-01-01 00:00:00 UTC. Os aplicativos podem escolher armazenar datas e horas em qualquer um desses formatos e converter livremente entre os formatos usando as funções integradas de data e hora.

Dito isso, eu usaria INTEGER e armazenaria os segundos desde a época do Unix (1970-01-01 00:00:00 UTC).

Diego Torres Milano
fonte
1
Eu também prefiro isso. As classes padrão relacionadas a data / hora são apoiadas internamente por longos de qualquer maneira, e é muito fácil comparar longos.
Karakuri de
1
@dtmilano Por que você prefere INTEGER aqui em vez de uma String?
IgorGanapolsky
1
INTEGER usa apenas 8 bytes, TEXT usa 23 bytes neste exemplo. Não está claro como escolher em que tipo armazenar os dados. Isso significa que se eu criar uma coluna do tipo INTEGER, as funções serão armazenadas automaticamente como Unix Time?
rayzinnz de
2
REAL também usa 8 bytes. Os segundos da época terão 10 dígitos até o final de 2286 e, como o IEEE duplo oferece suporte a 15-17 dígitos significativos , isso oferece uma resolução melhor do que em milissegundos. RSQLiteparece estar se convertendo POSIXctem época numérica, então funciona bem o suficiente para mim.
r2evans
@ r2evans Não tenho certeza do que você está dizendo. Se eu quiser armazenar milissegundos desde a época, como faço isso?
Michael
14

Um dos recursos poderosos do SQLite é permitir que você escolha o tipo de armazenamento. Vantagens / desvantagens de cada uma das três possibilidades diferentes:

  • String ISO8601

    • A comparação de strings fornece resultados válidos
    • Armazena fração de segundos, até três dígitos decimais
    • Precisa de mais espaço de armazenamento
    • Você verá diretamente seu valor ao usar um navegador de banco de dados
    • Necessidade de análise para outros usos
    • o modificador de coluna "default current_timestamp" irá armazenar usando este formato
  • Número real

    • Alta precisão em relação à fração de segundos
    • Maior intervalo de tempo
  • Número inteiro

    • Menor espaço de armazenamento
    • Operações rápidas
    • Pequeno intervalo de tempo
    • Possível problema no ano de 2038

Se você precisar comparar diferentes tipos ou exportar para um aplicativo externo, você está livre para usar as próprias funções de conversão de data e hora do SQLite conforme necessário.

Zso
fonte
1
Por que há problema de 2038? INTEGER parece suportar armazenamento de 64 bits.
guan boshen
1
@guanboshen Pelo que eu posso dizer, o único motivo para se preocupar com 2038 seria o suporte na plataforma host. A documentação do SQLite afirma usar C's localtime_r()( sqlite.org/lang_datefunc.html#caveats_and_bugs ) na implementação de referência e localtime()pode ser potencialmente vulnerável a 2038 se a plataforma host tiver um de 32 bits time_t. Dito isso, uma vez que o SQLite afirma se proteger contra essa possibilidade mapeando datas externas em uma pré-conversão de intervalo seguro (consulte o mesmo link), acho improvável que seja um problema, exceto talvez em casos esotéricos.
Zoë Sparks
@ ZoëSparks Obrigado pelo esclarecimento.
guan boshen
7

Para praticamente todas as questões de data e hora eu prefiro simplificar as coisas, muito, muito simples ... Baixar para segundos armazenados em inteiros.

Inteiros sempre serão suportados como inteiros em bancos de dados, arquivos simples, etc. Você faz um pouco de matemática e converte em outro tipo e pode formatar a data da maneira que quiser.

Fazendo desta forma, você não precisa se preocupar quando [inserir banco de dados favorito atual aqui] for substituído por [banco de dados favorito futuro] que coincidentemente não usou o formato de data que você escolheu hoje.

É apenas uma pequena sobrecarga matemática (por exemplo, métodos - leva dois segundos, postarei uma ideia geral se necessário) e simplifica as coisas para muitas operações relacionadas a data / hora posteriormente.

KelvinEWilliams
fonte
7

Armazene-o em um campo do tipo long. Veja Date.getTime()enew Date(long)

koem
fonte
como posso comparar isso? você pode me dar um exemplo de consulta ...: D
Khairil Ushan
Veja Joda Time para comparações em código ( joda-time.sourceforge.net ) e use comparação longa simples em SQL (por exemplo, comparação numérica).
Sintaxe de
selecione * da tabela onde a criação entre a e b;
koem