Berapa pesanan yang masuk bulan lalu? Kapan jatuh tempo pembayaran pelanggan? SQLite menjawab pertanyaan semacam itu dengan pendekatan yang berbeda dari database lain: engine SQLite tidak menyediakan tipe data DATE atau TIMESTAMP sama sekali. Sebagai gantinya, tanggal disimpan memakai konvensi format teks atau angka, lalu diolah oleh keluarga fungsi khusus. Fleksibilitas ini menguntungkan bila kita patuh aturan — dan berbahaya bila lalai, karena '2025-13-45' pun diterima sebagai teks biasa.

Data Contoh #

Kita memakai tabel pesanan dengan kolom tanggal berformat ISO-8601 (YYYY-MM-DD HH:MM:SS) — konvensi yang akan kita pilih sebagai format utama:

sql
CREATE TABLE pesanan (
  id INTEGER PRIMARY KEY,
  pelanggan TEXT NOT NULL,
  tanggal TEXT NOT NULL,
  total REAL NOT NULL
);

INSERT INTO pesanan (id, pelanggan, tanggal, total) VALUES
  (1, 'Budi', '2025-06-01 09:15:00', 150000),
  (2, 'Siti', '2025-06-03 14:30:00', 75000),
  (3, 'Budi', '2025-06-10 10:00:00', 220000),
  (4, 'Ani',  '2025-07-05 16:45:00', 45000),
  (5, 'Siti', '2025-07-12 08:20:00', 130000);

Tidak Ada Tipe Date — Hanya Konvensi Penyimpanan #

Meskipun deklarasi kolomnya TEXT, yang tersimpan tetap teks. Kita bisa membuktikannya dengan fungsi typeof():

sql
SELECT typeof(tanggal), tanggal FROM pesanan WHERE id = 1;

Output yang Dihasilkan:

text
text|2025-06-01 09:15:00

Dokumentasi resmi SQLite mengakui tiga konvensi penyimpanan yang dipahami oleh fungsi tanggal:

KonvensiTipeContohCocok untuk
ISO-8601TEXT'2025-06-15 10:30:00'Keterbacaan dan perbandingan string
Unix epochINTEGER1749983400Berinteraksi dengan sistem lain
Julian dayREAL2460842.0Perhitungan astronomis dan selisih waktu lama

Praktik terbaik untuk aplikasi umum adalah ISO-8601: formatnya terbaca manusia, dapat dibandingkan langsung sebagai string, dan dikenali semua fungsi tanggal SQLite.

Fungsi Tanggal dan Waktu #

Empat fungsi inti menerima nilai waktu lalu memformatnya kembali: date() menghasilkan tanggal, time() hanya jam, dan datetime() keduanya:

sql
SELECT date('2025-06-15 10:30:00'), time('2025-06-15 10:30:00'), datetime('2025-06-15 10:30:00');

Output yang Dihasilkan:

text
2025-06-15|10:30:00|2025-06-15 10:30:00

Ketepatan format dicapai lewat strftime(), yang menyalin tanggal ke template berisi kode format:

sql
SELECT strftime('%Y', '2025-06-15'), strftime('%H:%M', '2025-06-15 10:30:00'),
       strftime('%j', '2025-06-15'), strftime('%W', '2025-06-15');

Output yang Dihasilkan:

text
2025|10:30|166|23

Kode-kode yang paling sering dipakai:

KodeArtiContoh hasil
%Y %m %dTahun, bulan, tanggal2025, 06, 15
%H %M %SJam, menit, detik10, 30, 00
%sDetik Unix1749983400
%jHari ke-n dalam tahun (001-366)166
%WPekan ke-n dalam tahun (00-53)23

Dua fungsi konversi melengkapi kelompok ini. unixepoch() (hadir sejak SQLite 3.38) menghasilkan detik Unix, sedangkan julianday() menghasilkan bilangan hari Julian — berguna untuk menghitung selisih waktu dalam satuan hari pecahan:

sql
SELECT unixepoch('2025-06-15 10:30:00'), julianday('2025-06-15 12:00:00');

Output yang Dihasilkan:

text
1749983400|2460842.0

Keduanya bisa dibalik: tambahkan modifier 'unixepoch' untuk bilangan bulat, atau berikan REAL Julian langsung ke fungsi tanggal:

sql
SELECT datetime(1749983400, 'unixepoch'), date(2460842.0);

Output yang Dihasilkan:

text
2025-06-15 10:30:00|2025-06-15

Satu nilai waktu istimewa adalah 'now' — waktu UTC saat query dijalankan:

sql
SELECT datetime('now');

Output yang Dihasilkan (berubah mengikuti waktu eksekusi):

text
2026-10-13 04:26:01

Aritmetika Tanggal dengan Modifier #

Fungsi tanggal menerima modifier tambahan yang menggeser atau menyetel nilai waktu. '+7 days' menambah hari, 'start of month' memundurkan ke tanggal satu bulan, dan 'weekday N' maju ke hari-N berikutnya (0 = Minggu):

sql
SELECT date('2025-06-15', '+7 days'), date('2025-06-15', 'start of month'), date('2025-06-15', 'weekday 1');

Output yang Dihasilkan:

text
2025-06-22|2025-06-01|2025-06-16

Tanggal 2025-06-15 jatuh hari Minggu, sehingga weekday 1 melompat ke Senin 2025-06-16. Modifier bisa dirangkai dan diproses dari kiri ke kanan:

sql
SELECT datetime('2025-06-15 10:30:00', '+2 hours', '-15 minutes');

Output yang Dihasilkan:

text
2025-06-15 12:15:00

Pola paling praktis: menghitung jatuh tempo 14 hari dari setiap pesanan:

sql
SELECT id, pelanggan, tanggal, date(tanggal, '+14 days') AS jatuh_tempo
FROM pesanan ORDER BY id;

Output yang Dihasilkan:

text
1|Budi|2025-06-01 09:15:00|2025-06-15
2|Siti|2025-06-03 14:30:00|2025-06-17
3|Budi|2025-06-10 10:00:00|2025-06-24
4|Ani|2025-07-05 16:45:00|2025-07-19
5|Siti|2025-07-12 08:20:00|2025-07-26

Laporan Bulanan dan Rentang Tanggal #

Karena format ISO-8601 tersusun dari satuan terbesar ke terkecil, urutan abjadnya sama dengan urutan waktunya. Itulah sebabnya perbandingan string langsung memadai untuk menyaring rentang:

sql
SELECT id, pelanggan, tanggal FROM pesanan
WHERE tanggal >= '2025-07-01' ORDER BY tanggal;

Output yang Dihasilkan:

text
4|Ani|2025-07-05 16:45:00
5|Siti|2025-07-12 08:20:00

Untuk mengelompokkan per bulan, date(tanggal, 'start of month') menjadi kunci GROUP BY yang rapi:

sql
SELECT date(tanggal, 'start of month') AS bulan, SUM(total) AS omzet
FROM pesanan GROUP BY 1 ORDER BY 1;

Output yang Dihasilkan:

text
2025-06-01|445000.0
2025-07-01|175000.0

Alternatif yang lebih ringkas untuk label bulan adalah strftime('%Y-%m', ...):

sql
SELECT strftime('%Y-%m', tanggal) AS bulan, COUNT(*) AS jumlah_pesanan
FROM pesanan GROUP BY 1 ORDER BY 1;

Output yang Dihasilkan:

text
2025-06|3
2025-07|2

Jebakan Tanggal Tidak Valid #

Engine SQLite tidak memvalidasi isi kolom TEXT — string apa pun lolos. Fungsi tanggal adalah satu-satunya alat pemeriksa, dan jawabannya adalah NULL untuk nilai yang tak bisa dipahami:

sql
SELECT date('2025-13-45'), date('bukan tanggal');

Output yang Dihasilkan:

text
|

Kita bisa memaksa kualitas data lewat CHECK constraint. Trik tanggal IS datetime(tanggal) menuntut nilai tersimpan identik dengan bentuk bakunya — operator IS dipakai agar NULL dari datetime() ikut dianggap gagal:

sql
CREATE TABLE pesanan_aman (
  id INTEGER PRIMARY KEY,
  tanggal TEXT NOT NULL CHECK (tanggal IS datetime(tanggal))
);

Kolom ini kini menolak tanggal sampah:

bash
sqlite3 toko.db "INSERT INTO pesanan_aman (id, tanggal) VALUES (2, '2025-13-45 10:00:00');"

Output yang Dihasilkan:

text
Error: stepping, CHECK constraint failed: tanggal IS datetime(tanggal) (19)

Angka 19 di akhir adalah kode SQLITE_CONSTRAINT. Perlu dicatat juga bahwa trik ini menuntut format lengkap YYYY-MM-DD HH:MM:SS — nilai '2025-06-15' tanpa jam akan ditolak karena datetime('2025-06-15') menormalkannya menjadi '2025-06-15 00:00:00'.

Skema kolom tanggal kini aman. Fitur lanjutan berikutnya menyimpan data semi-terstruktur di satu kolom: JSON, yang dibahas pada Chapter Memproses JSON dalam SQLite.