Timestamp Saat Ini MySQL: NOW(), CURRENT_TIMESTAMP, SYSDATE(), UTC, dan Praktik Terbaik

目次

1. SQL terpendek untuk mendapatkan tanggal/waktu saat ini di MySQL

Jika Anda ingin mendapatkan tanggal/waktu saat ini di MySQL, fungsi pertama yang harus diingat adalah NOW() dan CURRENT_TIMESTAMP. Di bawah ini contoh SQL terpendek berdasarkan kasus penggunaan.

1.1 Dapatkan tanggal/waktu saat ini (dasar)

SELECT NOW();

atau

SELECT CURRENT_TIMESTAMP;
  • Keduanya mengembalikan tanggal/waktu saat ini (YYYY-MM-DD HH:MM:SS).
  • Dalam satu query yang sama, waktu tetap pada “waktu mulai query”.

Kasus penggunaan

  • Pencatatan log
  • Mendapatkan timestamp pembuatan record
  • Mendapatkan waktu referensi

Kesalahan umum

  • Zona waktu aplikasi dan zona waktu DB berbeda sehingga terjadi “pergeseran waktu.” → Periksa dengan SELECT @@session.time_zone;

1.2 Dapatkan tanggal hari ini saja

SELECT CURDATE();
  • Format yang dikembalikan: YYYY-MM-DD
  • Tipe adalah DATE (hanya tanggal, bukan datetime)

Kasus penggunaan

  • Mencari data “hari ini”
  • Agregasi harian

Catatan

  • Tidak seperti NOW(), tidak menyertakan waktu.
  • Jika Anda membutuhkan waktu untuk kueri rentang, gunakan NOW().

1.3 Dapatkan waktu saat ini saja

SELECT CURTIME();
  • Format yang dikembalikan: HH:MM:SS
  • Tipe adalah TIME (hanya waktu)

Kasus penggunaan

  • Menampilkan waktu eksekusi batch
  • Mencetak hanya bagian waktu dalam log

Jebakan umum

  • Karena tidak menyertakan tanggal, Anda tidak dapat menggunakannya untuk perbandingan datetime.

1.4 Dapatkan waktu saat ini dalam UTC (penting)

SELECT UTC_TIMESTAMP();
  • Mengembalikan UTC terlepas dari zona waktu server.
  • Disarankan untuk layanan global.

Kebijakan dasar dalam proyek nyata

  • Simpan dalam UTC
  • Konversi ke waktu lokal saat menampilkan

Catatan

  • Jika aplikasi sudah mengonversi ke UTC, waspadai konversi ganda.

1.5 Dapatkan milidetik / mikrodetik

SELECT NOW(3);  -- milliseconds (3 digits after the decimal point)
SELECT NOW(6);  -- microseconds (6 digits after the decimal point)
  • Tersedia di MySQL 5.6.4 dan setelahnya.
  • Digunakan untuk log berpresisi tinggi dan audit transaksi.

Kesalahpahaman umum

  • NOW() saja tidak dapat mengembalikan detik pecahan.
  • Kolom Anda juga harus menentukan presisi, misalnya DATETIME(6).

1.6 Fungsi terbaik berdasarkan kasus penggunaan (mulai di sini jika tidak yakin)

Use caseRecommended function
General current datetimeNOW()
Table default valueCURRENT_TIMESTAMP
Date onlyCURDATE()
Time onlyCURTIME()
Unified UTC managementUTC_TIMESTAMP()
High-precision logsNOW(6)

Poin penting yang sering terlewat orang

  • NOW() dan CURRENT_TIMESTAMP pada dasarnya setara (nilai sama)
  • Dalam satu query yang sama, waktu tetap
  • Nilai yang ditampilkan berubah tergantung pada pengaturan zona waktu
  • Untuk mikrodetik, definisi kolom Anda harus menentukan presisi

2. Perbedaan antara NOW() / CURRENT_TIMESTAMP / SYSDATE()

Ada beberapa fungsi untuk mendapatkan waktu saat ini, tetapi bagian yang paling membingungkan adalah perbedaan antara NOW(), CURRENT_TIMESTAMP, dan SYSDATE().
Jika Anda tidak memahaminya dengan benar, Anda dapat mengalami perilaku tak terduga dalam log dan pemrosesan transaksi.

2.1 NOW() dan CURRENT_TIMESTAMP pada dasarnya setara

SELECT NOW(), CURRENT_TIMESTAMP;
  • Keduanya mengembalikan datetime saat ini (nilai DATETIME).
  • Dalam satu query yang sama, waktu tetap pada “waktu mulai query.”
  • CURRENT_TIMESTAMP juga dapat digunakan dengan sintaks pemanggilan fungsi:
    SELECT CURRENT_TIMESTAMP();
    

Cara memilih dalam proyek nyata

Use caseRecommended
Simple retrievalNOW()
Table DEFAULT / ON UPDATECURRENT_TIMESTAMP

Poin penting

  • Makna nilai yang diambil sama.
  • Perbedaan utama terletak pada sintaks/penggunaan (misalnya, diperbolehkan di DEFAULT).
  • Bukan perbedaan tipe (mudah disalahpahami).

2.2 SYSDATE() mengembalikan waktu pada “waktu evaluasi”

SYSDATE() terlihat mirip dengan NOW(), tetapi waktu ketika nilai tersebut tetap berbeda.

SELECT NOW(), SLEEP(2), NOW();

Result (example):

2025-02-23 14:00:00
2025-02-23 14:00:00
SELECT SYSDATE(), SLEEP(2), SYSDATE();

Result (example):

2025-02-23 14:00:00
2025-02-23 14:00:02

Perbedaan esensial

FunctionWhen the time is fixed
NOW()Query start time
SYSDATE()Evaluation time

2.3 Catatan untuk transaksi dan replikasi

Karena NOW() ditetapkan pada awal kueri, maka
lebih aman ketika Anda membutuhkan waktu referensi yang konsisten di dalam sebuah transaksi.

Di sisi lain, karena SYSDATE() bergantung pada waktu eksekusi, hal ini dapat memengaruhi reproduktifitas dalam:

  • Replikasi
  • Pekerjaan batch
  • Pemrosesan log massal

Aturan praktis

  • Ingin waktu referensi tetap → NOW()
  • Membutuhkan momen tepat setiap saat → SYSDATE() (penggunaan terbatas)

2.4 Catatan: CURRENT_DATE / CURRENT_TIME / LOCALTIME

MySQL juga mendukung:

SELECT CURRENT_DATE;
SELECT CURRENT_TIME;
SELECT LOCALTIME;
  • CURRENT_DATE → sama dengan CURDATE()
  • CURRENT_TIME → sama dengan CURTIME()
  • LOCALTIME → sama dengan NOW()

Kebingungan umum

  • Ini kebanyakan “perbedaan kosmetik”; perbedaannya secara fungsional sangat kecil.
  • Untuk keamanan, prioritaskan keterbacaan dan standarisasi dalam proyek.

Poin penting dari bagian ini

  • NOW() dan CURRENT_TIMESTAMP pada dasarnya memiliki arti yang sama.
  • SYSDATE() berperilaku berbeda karena didasarkan pada waktu evaluasi.
  • Untuk waktu referensi tetap, gunakan NOW() sebagai default.
  • Gunakan CURRENT_TIMESTAMP untuk DEFAULT dan ON UPDATE.

3. Ubah format tampilan tanggal/waktu saat ini

Waktu saat ini yang Anda dapatkan dengan NOW() secara default ditampilkan sebagai YYYY-MM-DD HH:MM:SS. Dalam pekerjaan nyata, Anda sering membutuhkan hal-hal seperti:

  • Tampilkan hanya tanggal
  • Gunakan YYYY/MM/DD
  • Gunakan format lokal (mis., 23 Feb 2025)
  • Tampilkan milidetik

Untuk ini, gunakan DATE_FORMAT() (mengonversi datetime ke format string arbitrer).

3.1 Sintaks dasar DATE_FORMAT()

DATE_FORMAT(datetime, 'format_string')

Contoh: Mengonversi waktu saat ini ke YYYY/MM/DD HH:MM

SELECT DATE_FORMAT(NOW(), '%Y/%m/%d %H:%i');

Contoh output:

2025/02/23 14:35

Spesifikator format umum

SpecifierMeaningExample
%Y4-digit year2025
%m2-digit month02
%d2-digit day23
%HHour (24-hour)14
%iMinutes35
%sSeconds50
%fMicroseconds123456

Catatan

  • Beberapa spesifikator berbeda antara huruf besar/kecil.
  • %h adalah waktu 12 jam, %H adalah waktu 24 jam.

3.2 Contoh format umum (sering dalam pekerjaan nyata)

1. Dipisahkan dengan garis miring

SELECT DATE_FORMAT(NOW(), '%Y/%m/%d');

2. Lokal (Inggris)

SELECT DATE_FORMAT(NOW(), '%b %d, %Y');

3. Tanpa detik

SELECT DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i');

Jebakan umum

  • Karena mengembalikan string, Anda tidak dapat menggunakannya untuk perhitungan numerik.
  • Untuk perbandingan dan pencarian, Anda sebaiknya menggunakan tipe DATETIME asli.

3.3 Ekstrak hanya bagian tanggal atau waktu

Anda juga dapat mengambil bagian sambil mempertahankan tipe (alih-alih memformat menjadi string).

SELECT DATE(NOW());   -- date only (DATE type)
SELECT TIME(NOW());   -- time only (TIME type)
SELECT YEAR(NOW());   -- year only
SELECT MONTH(NOW());  -- month only
SELECT DAY(NOW());    -- day only

Penggunaan yang direkomendasikan

GoalRecommended
Formatting for displayDATE_FORMAT
Calculation / comparisonDATE() / TIME()

3.4 Tampilkan dengan mikrodetik

Saat Anda membutuhkan log dengan presisi tinggi:

SELECT NOW(6);

Dengan pemformatan:

SELECT DATE_FORMAT(NOW(6), '%Y-%m-%d %H:%i:%s.%f');

Catatan penting

  • Kolom Anda harus DATETIME(6) atau TIMESTAMP(6), jika tidak presisi tidak akan disimpan.
  • Tidak tersedia pada versi MySQL yang lebih lama dari 5.6.4 (tergantung lingkungan).

Kesalahan umum

  • Menggunakan DATE_FORMAT() dalam klausa WHERE mencegah penggunaan indeks. wp:list /wp:list

    • Contoh buruk: WHERE DATE_FORMAT(created_at, '%Y-%m-%d') = '2025-02-23'
    • Disarankan: WHERE created_at >= '2025-02-23 00:00:00' AND created_at < '2025-02-24 00:00:00'
    • Menyimpan string yang diformat untuk tampilan secara langsung (merusak kinerja pencarian)

Poin penting dari bagian ini

  • Gunakan DATE_FORMAT() untuk mengubah format tampilan.
  • Untuk perhitungan/perbandingan, pertahankan tipe asli.
  • Jika Anda membutuhkan mikrodetik, tentukan presisi dalam definisi kolom.
  • Menggunakan fungsi dalam klausa WHERE dapat menyebabkan masalah kinerja.

4. Perhitungan datetime menggunakan waktu saat ini

Di MySQL, biasanya menghitung hal seperti “N jam kemudian,” “N hari yang lalu,” atau “N hari terakhir” berdasarkan waktu saat ini.
Kasus dunia nyata yang paling umum adalah “mengambil data dari 24 jam terakhir.”

Dasar aritmatika datetime adalah INTERVAL (sintaks untuk menambah/mengurangi satuan waktu).

4.1 Tambah/kurangi dengan INTERVAL

Dapatkan 1 jam kemudian

SELECT NOW() + INTERVAL 1 HOUR;

Dapatkan 3 hari yang lalu

SELECT NOW() - INTERVAL 3 DAY;

Dapatkan 1 bulan kemudian

SELECT NOW() + INTERVAL 1 MONTH;

Satuan umum

UnitMeaning
SECONDSeconds
MINUTEMinutes
HOURHours
DAYDays
WEEKWeeks
MONTHMonths
YEARYears

Kesalahan umum

  • DAY dalam INTERVAL 1 DAY berfungsi meskipun huruf kecil, tetapi Anda sebaiknya menstandarkan dalam tim.
  • Perhitungan akhir bulan dapat berbeda dari harapan karena jumlah hari bervariasi (mis., 31 Jan + 1 bulan).

4.2 Mengambil data dari 24 jam terakhir (pola paling umum)

SELECT *
FROM users
WHERE created_at >= NOW() - INTERVAL 1 DAY;

Makna

  • Menargetkan “dari sekarang kembali hingga 24 jam yang lalu.”

Catatan

  • Jika Anda menggunakan CURDATE(), baseline menjadi “hari ini pada 00:00,” yang mengubah maknanya.

Contoh (data hari ini):

SELECT *
FROM users
WHERE created_at >= CURDATE();

Memahami perbedaan sangat penting

ExpressionMeaning
NOW() - INTERVAL 1 DAYPast 24 hours
CURDATE()Since today 00:00

4.3 Mendapatkan selisih hari dengan DATEDIFF()

SELECT DATEDIFF('2025-03-01', '2025-02-23');

Hasil:

6
  • Satuannya “hari”
  • Bagian waktu diabaikan

Catatan

  • Tanda berubah tergantung pada urutan argumen.
  • Anda tidak dapat menghitung selisih dalam jam/menit/detik.

4.4 Gunakan TIMESTAMPDIFF() untuk jam/menit/detik

SELECT TIMESTAMPDIFF(HOUR,
                     '2025-02-23 12:00:00',
                     '2025-02-23 18:30:00');

Hasil:

6

Menit

SELECT TIMESTAMPDIFF(MINUTE,
                     '2025-02-23 12:00:00',
                     '2025-02-23 12:30:00');

Detik

SELECT TIMESTAMPDIFF(SECOND,
                     '2025-02-23 12:00:00',
                     '2025-02-23 12:00:45');

Kasus penggunaan

  • Perhitungan durasi sesi
  • Pemeriksaan kedaluwarsa
  • Keputusan timeout

4.5 Mendapatkan awal bulan / akhir bulan (perangkap umum di dunia nyata)

Dapatkan hari pertama bulan ini:

SELECT DATE_FORMAT(NOW(), '%Y-%m-01');

Hari pertama bulan berikutnya:

SELECT DATE_FORMAT(NOW() + INTERVAL 1 MONTH, '%Y-%m-01');

Catatan

  • Akhir bulan bukan tanggal tetap.
  • Untuk kueri rentang, “>= start AND < hari pertama bulan berikutnya” aman.

Ringkasan kesalahan umum

  • Menggunakan BETWEEN dengan nilai hanya tanggal dan melupakan waktu
  • Menonaktifkan indeks dengan menggunakan DATE(created_at) dalam klausa WHERE
  • Terjebak oleh masalah “hari ke-31” dalam perhitungan bulan
  • Salah paham perbedaan antara NOW() dan CURDATE()

Poin penting dari bagian ini

  • INTERVAL adalah dasar aritmatika datetime.
  • 24 jam terakhir = NOW() - INTERVAL 1 DAY.
  • Hari = DATEDIFF(); satuan lebih kecil = TIMESTAMPDIFF().
  • Hati-hati dengan kondisi akhir untuk perhitungan berbasis bulan.

5. Untuk kueri rentang, ini lebih aman daripada BETWEEN

Saat melakukan pencarian rentang tanggal di MySQL, banyak pemula menggunakan BETWEEN. Namun, sering menghasilkan hasil yang tidak diinginkan jika Anda salah menangani batas waktu, sehingga pola yang lebih aman direkomendasikan dalam pekerjaan nyata.

5.1 Dasar-dasar BETWEEN dan jebakan

Kuery umum

SELECT *
FROM orders
WHERE order_date BETWEEN '2025-02-01' AND '2025-02-10';

Terlihat baik, tetapi secara internal setara dengan:

WHERE order_date &gt;= '2025-02-01 00:00:00'
  AND order_date &lt;= '2025-02-10 00:00:00'

Jadi tidak termasuk data setelah 00:00 pada 10 Feb.


5.2 Pola yang lebih aman (direkomendasikan)

Pola yang direkomendasikan

SELECT *
FROM orders
WHERE order_date &gt;= '2025-02-01 00:00:00'
  AND order_date &lt;  '2025-02-11 00:00:00';

Poin penting

  • Tentukan batas akhir sebagai “kurang dari hari berikutnya pada 00:00”
  • Lebih aman daripada <= 23:59:59 (mendukung mikrodetik)

5.3 Cara yang benar untuk mendapatkan data hari ini

Contoh buruk:

WHERE DATE(created_at) = CURDATE();

Masalah:

  • Menerapkan fungsi pada kolom menonaktifkan indeks
  • Dapat menyebabkan perlambatan serius pada tabel besar

Direkomendasikan:

WHERE created_at &gt;= CURDATE()
  AND created_at &lt;  CURDATE() + INTERVAL 1 DAY;

Ini memastikan:

  • Indeks dapat digunakan
  • Pencarian cepat
  • Tidak ada masalah batas

5.4 Pola aman untuk 7 hari terakhir / 30 hari terakhir

7 hari terakhir

WHERE created_at &gt;= NOW() - INTERVAL 7 DAY;

30 hari terakhir

WHERE created_at &gt;= NOW() - INTERVAL 30 DAY;

Catatan

  • CURDATE() - INTERVAL 7 DAY didasarkan pada “hari ini 00:00”
  • NOW() - INTERVAL 7 DAY didasarkan pada “waktu saat ini”
  • Pilih berdasarkan kebutuhan

5.5 Aturan kunci untuk menjaga indeks tetap efektif

Buruk:

WHERE DATE(created_at) = '2025-02-23';

Baik:

WHERE created_at &gt;= '2025-02-23 00:00:00'
  AND created_at &lt;  '2025-02-24 00:00:00';

Mengapa:

  • Indeks bekerja pada “kolom itu sendiri”
  • Menerapkan fungsi mencegah penggunaan indeks (pemindaian penuh)

Ringkasan kesalahan umum

  • Lupa menyertakan waktu pada batas akhir dalam BETWEEN
  • Kehilangan mikrodetik saat menggunakan 23:59:59
  • Menggunakan DATE() dalam klausa WHERE dan memperlambat query
  • Meninggalkan “now” vs “today 00:00” ambigu

Poin penting dari bagian ini

  • Query rentang paling aman dengan >= start AND < end.
  • BETWEEN memerlukan penanganan batas yang hati-hati.
  • Untuk menjaga indeks tetap efektif, jangan membungkus kolom dengan fungsi.
  • Pilih dengan jelas antara logika berbasis NOW() dan berbasis CURDATE().

6. DEFAULT CURRENT_TIMESTAMP dan ON UPDATE (dasar desain tabel)

Dalam desain basis data, biasanya mengelola created_at dan updated_at secara otomatis.
Di MySQL, CURRENT_TIMESTAMP memungkinkan Anda menetapkan waktu saat ini secara otomatis pada saat insert dan update.

6.1 Menetapkan otomatis created_at (DEFAULT CURRENT_TIMESTAMP)

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Perilaku:

INSERT INTO users (name) VALUES ('Alice');

→ Waktu saat ini secara otomatis dimasukkan ke dalam created_at.

Poin penting

  • CURRENT_TIMESTAMP dapat digunakan dalam DEFAULT.
  • NOW() tidak dapat digunakan langsung dalam DEFAULT.

Kesalahan umum

created_at DATETIME DEFAULT NOW();  -- error

Alasan:

  • Di MySQL, biasanya Anda tidak dapat menetapkan fungsi sebagai DEFAULT (kecuali CURRENT_TIMESTAMP).

6.2 Pembaruan otomatis updated_at (ON UPDATE)

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
               ON UPDATE CURRENT_TIMESTAMP
);

Perilaku:

UPDATE users SET name = 'Bob' WHERE id = 1;

updated_at secara otomatis diperbarui ke waktu saat ini.

Kasus penggunaan

  • Pelacakan login terakhir
  • Riwayat pembaruan
  • Log audit

6.3 DATETIME vs TIMESTAMP (penting)

TypeRangeTime zone impact
DATETIMEYear 1000 to 9999No
TIMESTAMP1970 to 2038Yes

Perbedaan penting

  • TIMESTAMP disimpan secara internal dalam UTC dan dikonversi ke zona waktu sesi saat ditampilkan.
  • DATETIME menyimpan nilai literal (tanpa konversi).

Pedoman

CaseRecommended type
Log managementTIMESTAMP
Future dates (after 2038)DATETIME
Fixed values not requiring TZ conversionDATETIME

6.4 CURRENT_TIMESTAMP juga dapat digunakan dengan DATETIME

Di MySQL 5.6 dan versi lebih baru, Anda dapat menentukan CURRENT_TIMESTAMP sebagai DEFAULT dan ON UPDATE untuk kolom DATETIME juga.

created_at DATETIME DEFAULT CURRENT_TIMESTAMP

Catatan

  • Versi MySQL yang lebih lama memiliki pembatasan (tergantung lingkungan).
  • Jika Anda memerlukan presisi:
    DATETIME(6) DEFAULT CURRENT_TIMESTAMP(6)
    

6.5 Jika Anda ingin menggunakan NOW(): alternatif (trigger)

CREATE TRIGGER set_created_at
BEFORE INSERT ON logs
FOR EACH ROW
SET NEW.created_at = NOW();

Kasus penggunaan

  • Logika nilai awal yang kompleks
  • Penetapan cap waktu bersyarat

Catatan

  • Trigger sulit untuk di‑debug.
  • Hindari kecuali memang diperlukan.

Kesalahan desain umum

  • Menambahkan ON UPDATE pada created_at dan updated_at sekaligus
  • Membingungkan perilaku DATETIME dan TIMESTAMP
  • Menunda keputusan zona waktu

Hal penting yang harus diingat dari bagian ini

  • Gunakan CURRENT_TIMESTAMP untuk DEFAULT.
  • Gunakan ON UPDATE CURRENT_TIMESTAMP untuk pelacakan pembaruan.
  • Pilih tipe berdasarkan perilaku zona waktu dan masalah tahun 2038.
  • Jika Anda memerlukan presisi, jangan lupa (6).

7. Desain zona waktu (simpan dalam UTC, tampilkan dalam waktu lokal)

Saat menangani waktu saat ini, desain zona waktu yang buruk menyebabkan drift waktu dan konversi ganda.
Dalam praktiknya, default yang paling aman adalah “simpan dalam UTC, konversi ke waktu lokal untuk tampilan.”

MySQL timezone architecture storing timestamps in UTC and converting to local time (JST)

Figure: Arsitektur dasar untuk menyimpan UTC di MySQL dan menampilkan waktu lokal

7.1 Periksa zona waktu saat ini

Pertama, periksa zona waktu mana yang sedang dijalankan MySQL.

SELECT @@global.time_zone, @@session.time_zone;
  • @@global.time_zone → pengaturan untuk seluruh server
  • @@session.time_zone → pengaturan koneksi/sesi saat ini
  • Jika menampilkan SYSTEM, maka bergantung pada pengaturan OS

Masalah umum

  • Server produksi dan pengembangan memiliki zona waktu OS yang berbeda
  • Aplikasi mengonversi ke UTC, lalu DB mengonversi lagi (konversi ganda)

7.2 Ubah zona waktu per sesi

SET time_zone = 'Asia/Tokyo';

atau seragamkan ke UTC:

SET time_zone = '+00:00';

Poin penting

  • Akan kembali ke semula ketika koneksi ditutup
  • Jika Anda menggunakan connection pooling, periksa pengaturan aplikasi Anda

7.3 Mengapa menyimpan dalam UTC (prinsip dunia nyata)

Kebijakan yang direkomendasikan

  1. Simpan data dalam UTC
  2. Konversi ke zona waktu pengguna saat menampilkan

Alasan:

  • Dukungan internasional yang lebih mudah
  • Menghindari masalah daylight saving time (DST)
  • Meminimalkan dampak saat memindahkan server

Dapatkan UTC:

SELECT UTC_TIMESTAMP();

7.4 Konversi zona waktu dengan CONVERT_TZ()

Contoh: UTC → JST

SELECT CONVERT_TZ('2025-02-23 05:35:00', '+00:00', '+09:00');

Menggunakan nama zona waktu:

SELECT CONVERT_TZ('2025-02-23 05:35:00', 'UTC', 'Asia/Tokyo');

Contoh dunia nyata

SELECT CONVERT_TZ(created_at, 'UTC', 'Asia/Tokyo')
FROM users;

7.5 Mengapa CONVERT_TZ() mengembalikan NULL

Jika mengembalikan NULL, penyebab umum meliputi:

  • Tabel zona waktu MySQL belum dimuat
  • Nama zona waktu yang diberikan tidak ada

Contoh pemuatan di Linux:

mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root -p mysql

Catatan

  • Di produksi, pastikan izin dan apakah restart diperlukan
  • Di Docker, zoneinfo mungkin tidak termasuk tergantung pada image

7.6 Ubah zona waktu seluruh server

File konfigurasi (my.cnf / my.ini):

[mysqld]
default_time_zone = '+00:00'

Verifikasi setelah restart:

SELECT @@global.time_zone;

Penting

  • Untuk perubahan produksi, pastikan ruang lingkup dampaknya
  • Hati‑hati dengan data yang sudah ada (kadang hanya perubahan tampilan)

Kesalahan umum

  • Menyimpan waktu lokal alih‑alih UTC, lalu menambahkan dukungan internasional belakangan
  • Konversi ganda antara aplikasi dan DB
  • Mendesain dengan DATETIME tanpa mempertimbangkan zona waktu
  • Pengaturan TZ yang berbeda antara pengujian dan produksi

Hal penting yang harus diingat dari bagian ini

  • Simpan dalam UTC dan konversi saat menampilkan.
  • Gunakan UTC_TIMESTAMP() .
  • Saat menggunakan CONVERT_TZ(), verifikasi tabel TZ.
  • Selalu perhitungkan perbedaan lingkungan pada zona waktu.

8. Contoh praktis yang dapat langsung Anda gunakan

Berikut contoh SQL konkret yang menunjukkan cara menggunakan waktu saat ini MySQL dalam pengembangan/operasi nyata.
Ditulis agar Anda dapat menyalin dan menempelkannya langsung.

8.1 Secara otomatis menyisipkan waktu saat ini ke dalam log

Buat tabel

CREATE TABLE system_logs (
    id INT AUTO_INCREMENT PRIMARY KEY,
    level VARCHAR(50),
    message TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Memasukkan log

INSERT INTO system_logs (level, message)
VALUES ('ERROR', 'Failed to connect to the DB');

Poin kunci

  • created_at dimasukkan secara otomatis
  • Tidak perlu mengirim timestamp dari aplikasi
  • Desain esensial untuk audit dan investigasi insiden

Kesalahan umum

  • Mengelola waktu di aplikasi dan DB
  • Ketidakkonsistenan waktu karena zona waktu yang tidak seragam

8.2 Memperbarui waktu login terakhir

Desain tabel

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(255),
    last_login TIMESTAMP DEFAULT CURRENT_TIMESTAMP
               ON UPDATE CURRENT_TIMESTAMP
);

Pembaruan saat login

UPDATE users
SET last_login = NOW()
WHERE id = 1;

Catatan

  • ON UPDATE hanya dipicu ketika kolom berubah
  • Beberapa pernyataan UPDATE mungkin tidak mengubah nilai dan sehingga tidak memperbarui

8.3 Memperbaiki waktu referensi dalam pekerjaan batch

Untuk proses yang berjalan lama, lebih aman untuk memperbaiki waktu referensi.

SET @base_time = NOW();

SELECT *
FROM orders
WHERE created_at &gt;= @base_time - INTERVAL 1 DAY;

Mengapa

  • Waktu tidak bergeser di tengah proses
  • Konsistensi tetap terjaga

8.4 Agregasi untuk hari ini / kemarin / 7 hari terakhir

Penjualan hari ini

SELECT SUM(amount)
FROM orders
WHERE created_at &gt;= CURDATE()
  AND created_at &lt;  CURDATE() + INTERVAL 1 DAY;

Penjualan kemarin

SELECT SUM(amount)
FROM orders
WHERE created_at &gt;= CURDATE() - INTERVAL 1 DAY
  AND created_at &lt;  CURDATE();

7 hari terakhir

SELECT COUNT(*)
FROM users
WHERE created_at &gt;= NOW() - INTERVAL 7 DAY;

Penting

  • Jangan terapkan fungsi pada kolom dalam klausa WHERE
  • Tulis kondisi yang menjaga indeks tetap dapat digunakan

8.5 Pemeriksaan kedaluwarsa (sesi/token)

SELECT *
FROM sessions
WHERE expires_at &gt; NOW();

Hapus baris yang kedaluwarsa

DELETE FROM sessions
WHERE expires_at &lt;= NOW();

Kesalahan umum

  • Menggunakan CURDATE() dan mengabaikan waktu
  • Menyimpan UTC tetapi membandingkan dengan NOW() lokal

8.6 Mendapatkan baris yang kedaluwarsa dalam N jam

SELECT *
FROM coupons
WHERE expires_at &lt;= NOW() + INTERVAL 1 HOUR;

Kasus penggunaan:

  • Peringatan kedaluwarsa
  • Notifikasi kedaluwarsa

Apa yang harus selalu Anda ingat

  • Jadilah eksplisit apakah baseline Anda adalah “sekarang” atau “hari ini 00:00”
  • Tulis predikat yang menjaga indeks efektif
  • Putuskan desain zona waktu di awal
  • Jangan campur NOW() dan UTC_TIMESTAMP() tanpa kebijakan yang jelas

Poin utama dari bagian ini

  • Untuk log/audit/pelacakan pembaruan, gunakan CURRENT_TIMESTAMP
  • Untuk agregasi, gunakan pola aman >= DAN <
  • Untuk manajemen sesi, bandingkan dengan NOW()
  • Perbaiki waktu baseline untuk menjaga pemrosesan tetap konsisten

9. Pertanyaan yang Sering Diajukan (FAQ)

Berikut adalah pertanyaan umum tentang waktu saat ini di MySQL, terutama jebakan yang muncul dalam pekerjaan nyata.

9.1 Apa perbedaan antara NOW() dan CURRENT_TIMESTAMP?

Kesimpulan: arti nilai yang dikembalikan sama.

SELECT NOW(), CURRENT_TIMESTAMP;

Keduanya mengembalikan datetime saat ini.

Perbedaan utama adalah penggunaan sintaksis

  • CURRENT_TIMESTAMP dapat digunakan dalam DEFAULT dan ON UPDATE
  • NOW() tidak dapat digunakan langsung dalam DEFAULT

Catatan

  • Ini bukan perbedaan tipe
  • Anda dapat menentukan presisi dengan argumen seperti (6)

9.2 Haruskah Anda menggunakan SYSDATE()?

SYSDATE() mengembalikan waktu pada “waktu evaluasi.”

SELECT SYSDATE(), SLEEP(2), SYSDATE();

Nilai dapat berubah bahkan dalam query yang sama.

Kapan menggunakannya

  • Ketika Anda perlu mencatat instan waktu nyata yang tepat

Kapan menghindarinya

  • Replikasi
  • Pemrosesan transaksi di mana konsistensi penting

Dalam kebanyakan kasus, menggunakan NOW() sudah cukup.

9.3 Mengapa waktu bergeser?

Penyebab utama:

  1. Pengaturan zona waktu server
  2. Pengaturan zona waktu sesi
  3. Konversi ganda dengan aplikasi
  4. Perilaku konversi otomatis tipe TIMESTAMP

Periksa dengan:

SELECT @@global.time_zone, @@session.time_zone;

Mitigasi

  • Simpan dalam UTC secara default
  • Konversi hanya saat menampilkan
  • Samakan kebijakan antara aplikasi dan DB

9.4 CONVERT_TZ() returns NULL

Penyebab:

  • Tabel zona waktu tidak dimuat
  • Nama zona waktu tidak tepat

Perbaikan:

mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root -p mysql

Berhati-hatilah terutama di lingkungan Docker.

9.5 Range shifts with BETWEEN

Buruk:

WHERE created_at BETWEEN '2025-02-01' AND '2025-02-10';

Aman:

WHERE created_at &gt;= '2025-02-01 00:00:00'
  AND created_at &lt;  '2025-02-11 00:00:00';

Alasan:

  • Masalah waktu batas akhir
  • Kebocoran mikrodetik
  • Efisiensi indeks

9.6 Bagaimana Anda memilih antara DATETIME dan TIMESTAMP?

  • Dukungan internasional / manajemen UTC → TIMESTAMP
  • Setelah 2038 atau datetime tetap → DATETIME

Putuskan ini saat perancangan.

9.7 Mikrodetik tidak disimpan

Penyebab:

  • Tidak ada presisi yang ditentukan dalam definisi kolom

Perbaikan:

created_at DATETIME(6)

Poin penting dari bagian ini

  • Mulai dengan NOW() dan CURRENT_TIMESTAMP
  • Untuk kueri rentang, gunakan >= AND <
  • Penyimpanan UTC adalah default paling aman
  • Jangan lupa pemilihan tipe dan presisi

10. Ringkasan

Artikel ini menyusun cara praktis untuk mengambil, memformat, menghitung, dan mengelola waktu saat ini di MySQL.
Akhirnya, berikut esensial minimum yang harus Anda ketahui untuk tetap aman.

10.1 Mendapatkan waktu saat ini (dasar)

  • Pengambilan umum → NOW()
  • DEFAULT tabel / pelacakan pembaruan → CURRENT_TIMESTAMP
  • Hanya tanggal → CURDATE()
  • Hanya waktu → CURTIME()
  • UTC → UTC_TIMESTAMP()
  • Presisi tinggi → NOW(6)

Aturan praktis

  • Jika ragu, menggunakan NOW() baik dalam kebanyakan kasus.
  • Untuk desain skema, gunakan CURRENT_TIMESTAMP .

10.2 Kueri rentang: “>= AND <” adalah aturan emas

Pola aman:

WHERE created_at &gt;= 'START'
  AND created_at &lt;  'END'

Mengapa:

  • Mencegah baris yang hilang pada batas akhir
  • Bekerja dengan mikrodetik
  • Menjaga indeks tetap dapat digunakan

Contoh buruk

WHERE DATE(created_at) = CURDATE();

Jangan membungkus kolom dengan fungsi.

10.3 Dasar aritmetika datetime

  • Tambah/kurangi → INTERVAL
  • Selisih hari → DATEDIFF()
  • Selisih waktu → TIMESTAMPDIFF()

Selalu ingat apakah dasar Anda adalah “now” atau “today 00:00.”

10.4 Prinsip desain zona waktu

  • Simpan dalam UTC
  • Konversi saat ditampilkan
  • Samakan kebijakan antara aplikasi dan DB

Periksa dengan:

SELECT @@global.time_zone, @@session.time_zone;

10.5 Praktik terbaik desain tabel

created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
           ON UPDATE CURRENT_TIMESTAMP
  • Peralatan standar untuk audit/pencatatan/pelacakan pembaruan
  • Jika Anda membutuhkan presisi, tentukan (6)

4 poin paling penting dalam dunia nyata

  1. Jangan salah mengartikan perbedaan antara NOW() dan CURRENT_TIMESTAMP
  2. Untuk kueri rentang, gunakan >= AND <
  3. Simpan dalam UTC secara default
  4. Tentukan tipe (DATETIME vs TIMESTAMP) saat perancangan

Penanganan waktu saat ini di MySQL merupakan dasar untuk pencatatan, agregasi penjualan, manajemen otentikasi/sesi, pekerjaan batch, dan lainnya.
Jika Anda mengikuti prinsip-prinsip dalam artikel ini, Anda dapat menghindari banyak masalah umum seperti pergeseran waktu, bug batas, dan penurunan kinerja.