Jak działają wartości DATETIME w SQLite?

110

Tworzę aplikacje na Androida i muszę zapisać datę / godzinę utworzenia rekordu. Dokumentacja SQLite mówi jednak, że „SQLite nie ma klasy pamięci przeznaczonej na przechowywanie dat i / lub godzin” i „może przechowywać daty i godziny jako wartości TEKST, REAL lub INTEGER”.

Czy istnieje techniczny powód, aby używać jednego typu zamiast innego? I czy pojedyncza kolumna może przechowywać daty w dowolnym z trzech formatów od wiersza do wiersza?

Później będę musiał porównać daty. Na przykład w moich aplikacjach pokażę wszystkie rekordy utworzone między datą A a datą B. Obawiam się, że brak prawdziwej kolumny DATETIME może utrudnić porównania.

Khairil Ushan
źródło

Odpowiedzi:

83

SQlite nie ma określonego typu daty i godziny. Można użyć TEXT, REALlubINTEGER typy, w zależności odpowiada Twoim potrzebom.

Prosto z DOCS

SQLite nie ma klasy pamięci przeznaczonej do przechowywania dat i / lub godzin. Zamiast tego wbudowane funkcje daty i czasu w SQLite mogą przechowywać daty i godziny jako wartości TEXT, REAL lub INTEGER:

  • TEKST jako ciągi ISO8601 („RRRR-MM-DD GG: MM: SS.SSS”).
  • REAL jako liczba dni juliańskich, liczba dni od południa w Greenwich 24 listopada 4714 rpne według proleptycznego kalendarza gregoriańskiego.
  • INTEGER jako czas uniksowy, liczba sekund od 1970-01-01 00:00:00 UTC.

Aplikacje mogą wybrać przechowywanie dat i godzin w dowolnym z tych formatów i swobodnie konwertować między formatami za pomocą wbudowanych funkcji daty i czasu.

Wbudowane funkcje daty i czasu SQLite można znaleźć tutaj .

neo108
źródło
11
Ważna uwaga - wszystkie metody przechowywania dat używają formatów, które można porównać za pomocą standardowych operatorów =, <,> i BETWEEN.
Larry Lustig
2
„SQLite nie ma klasy pamięci zarezerwowanej do przechowywania dat i / lub godzin” - z wyjątkiem tego, że ma typy DATE i DATETIME, które nigdy nie są wymienione w dokumentacji
Slabko
12
@Slabko Nie. SQLite zezwala na wszystko (w tym DATETIME) jako zadeklarowany typ kolumny. Na tej podstawie nadaje tej kolumnie powinowactwo z klasą pamięci (w dokumentacji znajduje się nawet przykład, jak to działa dla DATETIME). To powinowactwo przypomina raczej wskazówkę, ponieważ każdy wpis w kolumnie może mieć inną klasę pamięci. Klasa magazynu jest nadal o krok słabsza niż typ i może być obsługiwana przez wiele typów. Więc tak, możesz użyć DATETIME. Nie, w rzeczywistości nie obsługuje go jako typu lub klasy pamięci. Tak, dokumentacja faktycznie zawiera słowo „DATETIME”.
Jasper
20

SQLite nie ma klasy pamięci przeznaczonej do przechowywania dat i / lub godzin. Zamiast tego wbudowane funkcje daty i czasu w SQLite mogą przechowywać daty i godziny jako wartości TEXT, REAL lub INTEGER:

TEKST jako ciągi ISO8601 („RRRR-MM-DD GG: MM: SS.SSS”). REAL jako liczba dni juliańskich, liczba dni od południa w Greenwich 24 listopada 4714 rpne według proleptycznego kalendarza gregoriańskiego. INTEGER jako czas uniksowy, liczba sekund od 1970-01-01 00:00:00 UTC. Aplikacje mogą wybrać przechowywanie dat i godzin w dowolnym z tych formatów i swobodnie konwertować między formatami za pomocą wbudowanych funkcji daty i czasu.

Powiedziawszy to, użyłbym INTEGER i przechowałbym sekundy od epoki Uniksa (1970-01-01 00:00:00 UTC).

Diego Torres Milano
źródło
1
Ja też to wolę. Standardowe klasy związane z datą / godziną i tak są wewnętrznie wspierane przez wartości długie, a porównywanie wartości długich jest dość łatwe.
Karakuri
1
@dtmilano Dlaczego wolisz tutaj INTEGER zamiast String?
IgorGanapolsky
1
INTEGER używa tylko 8 bajtów, w tym przykładzie TEXT używa 23 bajtów. Nie jest jasne, jak wybrać typ, w którym będą przechowywane dane. Czy to oznacza, że ​​jeśli utworzę kolumnę typu INTEGER, funkcje będą automatycznie przechowywać jako czas uniksowy?
rayzinnz
2
REAL również wykorzystuje 8 bajtów. Sekundy epoki będą miały 10 cyfr do późnego 2286 roku, a ponieważ podwójne IEEE obsługują 15-17 cyfr znaczących , daje to rozdzielczość lepszą niż milisekundowa. RSQLitewydaje się, że konwertuje się POSIXctna epokę numeryczną, więc dla mnie działa wystarczająco dobrze.
r2evans
@ r2evans Nie jestem pewien, co mówisz. Jeśli chcę przechowywać milisekundy od Epoki, jak mam to zrobić?
Michael
14

Jedną z potężnych funkcji SQLite jest możliwość wyboru typu przechowywania. Zalety / wady każdej z trzech różnych możliwości:

  • Ciąg ISO8601

    • Porównanie ciągów daje prawidłowe wyniki
    • Przechowuje ułamki sekund, do trzech cyfr dziesiętnych
    • Potrzebuje więcej miejsca do przechowywania
    • Jego wartość zobaczysz bezpośrednio podczas korzystania z przeglądarki bazy danych
    • Potrzeba analizowania do innych celów
    • Modyfikator kolumny „default current_timestamp” będzie przechowywany w tym formacie
  • Prawdziwy numer

    • Wysoka precyzja w zakresie ułamków sekund
    • Najdłuższy zakres czasu
  • Liczba całkowita

    • Najniższa przestrzeń dyskowa
    • Szybkie operacje
    • Mały zakres czasu
    • Możliwy problem z roku 2038

Jeśli chcesz porównać różne typy lub wyeksportować do zewnętrznej aplikacji, możesz w razie potrzeby użyć własnych funkcji konwersji daty i godziny oprogramowania SQLite .

Zso
źródło
1
Dlaczego jest problem 2038? Wydaje się, że INTEGER obsługuje pamięć 64-bitową.
guan boshen
1
@guanboshen O ile wiem, jedynym powodem do zmartwień o 2038 będzie wsparcie na platformie hosta. Dokumentacja SQLite twierdzi, że używa C localtime_r()( sqlite.org/lang_datefunc.html#caveats_and_bugs ) w implementacji referencyjnej i localtime()może być potencjalnie podatna na 2038, jeśli platforma hosta ma 32-bitową wersjętime_t . To powiedziawszy, ponieważ SQLite twierdzi, że chroni przed taką możliwością, mapując daty zewnętrzne w bezpiecznym zakresie przed konwersją (zobacz ten sam link), myślę, że jest to mało prawdopodobne, z wyjątkiem może ezoterycznych przypadków.
Zoë Sparks
@ ZoëSparks Dziękuję za wyjaśnienie.
guan boshen
7

Praktycznie we wszystkich sprawach dotyczących daty i czasu wolę upraszczać rzeczy, bardzo, bardzo proste ... Aż do sekund zapisanych w liczbach całkowitych.

Liczby całkowite zawsze będą obsługiwane jako liczby całkowite w bazach danych, płaskich plikach itp. Wykonujesz trochę matematyki i przerzucasz ją na inny typ, a datę możesz sformatować tak, jak chcesz.

Robiąc to w ten sposób, nie musisz się martwić, gdy [wstaw tutaj bieżącą ulubioną bazę danych] zostanie zastąpione przez [przyszłą ulubioną bazę danych], która przypadkowo nie używała formatu daty, który wybrałeś dzisiaj.

To tylko trochę narzutów matematycznych (np. Metody - zajmuje dwie sekundy, w razie potrzeby opublikuję streszczenie) i upraszcza wiele operacji dotyczących daty / czasu później.

KelvinEWilliams
źródło
7

Przechowuj go w polu typu long. Zobacz Date.getTime()inew Date(long)

koem
źródło
jak mogę to porównać? czy możesz mi dać próbkę zapytania ..: D
Khairil Ushan
Spójrz na Joda Time dla porównań w kodzie ( joda-time.sourceforge.net ) i użyj prostego długiego porównania w SQL (np. Porównanie numeryczne).
Składnia
wybierz * z tabeli, gdzie tworzenie między a i b;
koem