Pada Chapter Benchmarking kita memakai std::chrono sebagai stopwatch. Waktu sebenarnya lebih luas dari sekadar stopwatch: program perlu mencatat kapan kejadian terjadi, menghitung jadwal, atau menentukan hari dalam seminggu untuk sebuah tanggal. Menyimpan waktu sebagai angka polos (int detik) menimbulkan kekeliruan satuan yang tidak tertangkap compiler — 90 yang berarti detik bisa salah dibaca sebagai menit. Header <chrono> (namespace std::chrono) menyelesaikan masalah ini dengan menjadikan satuan waktu bagian dari tipe. Chapter ini membahas tiga konsep intinya, literal waktu C++14, konversi antar duration, perbandingan dua clock terpenting, kalender C++20, dan pengantar time zone.

Tiga Konsep Inti: Duration, Clock, dan Time Point #

Semua kemampuan <chrono> berdiri di atas tiga tipe yang saling terkait. Duration mewakili rentang waktu — angka beserta satuan, misalnya 45 detik atau 1500 milidetik. Clock adalah sumber titik waktu, seperti system_clock yang mengikuti jam dinding sistem dan steady_clock yang berjalan monoton. Time point adalah titik waktu yang dihitung sebagai durasi dari titik acuan sebuah clock (epoch); now() milik clock mengembalikan time point saat ini. Hubungan ketiganya: time point lahir dari clock, dan selisih dua time point pada clock yang sama menghasilkan duration. Kita mulai dari duration karena dua konsep lain memakainya sebagai bahan bangunan.

KonsepMewakiliContoh tipe
durationrentang waktu (angka + satuan)seconds, milliseconds, hours
clocksumber titik waktusystem_clock, steady_clock
time_pointtitik pada sebuah clocksys_days, hasil clock::now()

Duration dan Literal Waktu C++14 #

Template std::chrono::duration<Rep, Period> menyimpan angka bertipe Rep yang diukur dalam satuan Period (seperseribu detik untuk milliseconds). Header ini menyediakan tipe siap pakai — nanoseconds hingga hours — sehingga kita jarang perlu membuat tipe sendiri. Sejak C++14, literal waktu membuat durasi terasa alami: 45s, 1500ms, 30min, 2h. Literal ini aktif setelah kita membuka namespace std::chrono_literals.

cpp
#include <chrono>   // std::chrono: duration, literal waktu
#include <iostream> // std::cout

int main() {
    using namespace std::chrono_literals; // mengaktifkan 2h, 30min, 45s, 250ms
    namespace ch = std::chrono;

    // Literal waktu saling menemukan tipe durasi bersama secara otomatis
    ch::seconds total = 2h + 30min + 45s;
    std::cout << "total : " << total.count() << " detik\n";
    std::cout << "total : " << total << "\n";

    // Tipe durasi siap pakai lainnya dari header yang sama
    ch::milliseconds tunggu = 250ms;
    ch::microseconds mikro  = 500us;
    ch::nanoseconds nano    = 100ns;
    std::cout << "tunggu: " << tunggu << "\n";
    std::cout << "mikro : " << mikro << "\n";
    std::cout << "nano  : " << nano << "\n";

    // Menjumlahkan dua tipe berbeda: hasil memakai tipe yang lebih halus
    std::cout << "campur: " << (1h + 30min) << "\n";

    return 0;
}

Output yang Dihasilkan:

text
total : 9045 detik
total : 9045s
tunggu: 250ms
mikro : 500us
nano  : 100ns
campur: 90min

Mari kita bedah:

  1. Baris 5 (using namespace std::chrono_literals;): membuka namespace literal sehingga 2h, 30min, 45s, 250ms, 500us, dan 100ns berlaku; tanpa baris ini 2h ditolak compiler.
  2. Baris 9 (ch::seconds total = 2h + 30min + 45s;): ketiga literal bertipe berbeda (hours, minutes, seconds). Operator + mencari tipe bersama paling kasar tanpa kehilangan informasi — di sini seconds — hasilnya 9045 detik.
  3. Baris 10-11: .count() mengembalikan angka tik saja (9045), sedangkan operator<< yang tersedia sejak C++20 mencetak angka beserta akhiran satuan (9045s).
  4. Baris 14-16: tipe milliseconds, microseconds, dan nanoseconds bertingkat lebih halus dari seconds; satuan menempel pada tipe, bukan pada nama variabel.
  5. Baris 22 (1h + 30min): tipe bersama untuk jam dan menit adalah minutes, sehingga hasilnya tercetak 90min — penjumlahan durasi tidak pernah memotong informasi.

Konversi Antar Duration #

Konversi antar tipe durasi punya aturan satu arah yang ketat. Jika tipe tujuan lebih halus (detik ke milidetik), konversi terjadi secara implisit karena tidak ada informasi yang hilang. Jika tipe tujuan lebih kasar (milidetik ke detik), informasi bisa hilang, sehingga compiler menolak konversi implisitnya dan kita wajib menyatakan maksud lewat std::chrono::duration_cast. Perlu diingat, duration_cast memotong ke arah nol (truncation), bukan membulatkan; C++17 menambahkan floor, ceil, dan round untuk perilaku lain.

cpp
#include <chrono>   // std::chrono: duration dan fungsi konversi
#include <iostream> // std::cout

int main() {
    using namespace std::chrono_literals;
    namespace ch = std::chrono;

    // 1. Implisit: tipe tujuan lebih halus, tidak ada informasi yang hilang
    ch::seconds duaJam = 2h;
    ch::milliseconds halus = duaJam;
    std::cout << "2h = " << halus.count() << " ms (implisit)\n";

    // 2. Eksplisit: tipe tujuan lebih kasar, wajib duration_cast
    ch::milliseconds m{1500};
    ch::seconds kasar = ch::duration_cast<ch::seconds>(m);
    std::cout << "1500 ms = " << kasar.count() << " s (duration_cast)\n";

    // 3. duration_cast memotong ke arah nol (truncation)
    ch::minutes menitKerja{125};
    ch::hours jamKerja = ch::duration_cast<ch::hours>(menitKerja);
    std::cout << "125 menit = " << jamKerja.count() << " jam, sisa "
              << (menitKerja - jamKerja).count() << " menit\n";

    // 4. Alternatif C++17: floor, ceil, dan round
    std::cout << "floor: " << ch::floor<ch::seconds>(m).count()
              << " | ceil: " << ch::ceil<ch::seconds>(m).count()
              << " | round: " << ch::round<ch::seconds>(m).count() << "\n";

    return 0;
}

Output yang Dihasilkan:

text
2h = 7200000 ms (implisit)
1500 ms = 1 s (duration_cast)
125 menit = 2 jam, sisa 5 menit
floor: 1 | ceil: 2 | round: 2

Mari kita bedah:

  1. Baris 9-11: 2h dikonversi dua kali secara implisit — ke seconds lalu ke milliseconds — hasilnya 7200000 ms; tidak ada langkah yang memotong informasi.
  2. Baris 14-16: baris 15 tidak bisa ditulis ch::seconds kasar = m; karena compiler menolak konversi yang bisa memotong data; duration_cast<ch::seconds> memotong 1500 ms menjadi 1 s.
  3. Baris 19-22: 125 menit dipotong menjadi 2 jam; sisanya dihitung lewat pengurangan menitKerja - jamKerja yang bertipe minutes — tercetak 5 menit.
  4. Baris 25-27: untuk 1500 ms, floor membulatkan ke bawah (1), ceil ke atas (2), dan round ke nilai terdekat (2, karena 1,5 dibulatkan ke angka genap).

steady_clock vs system_clock: Kapan Memakai yang Mana #

Setiap clock menyediakan now() yang mengembalikan time point, dan selisih dua time point pada clock yang sama adalah duration. system_clock mengikuti jam dinding sistem: sejak C++20, standar C++ mengikatnya ke Unix Time (titik acuan 1 Januari 1970 UTC), sehingga cocok untuk mencatat kapan kejadian terjadi. Nilai jam dinding bisa berubah — pengguna menggeser jam atau NTP menyesuaikan — sehingga pengukuran interval di atasnya tidak andal. steady_clock dijamin monotonik: nilainya tidak pernah mundur, cocok untuk mengukur durasi seperti pada Chapter Benchmarking. Clock ketiga, high_resolution_clock, hanyalah alias dari salah satu keduanya; menyebut pilihan secara eksplisit lebih jelas.

system_clocksteady_clock
Titik acuan1 Januari 1970 UTC (Unix Time, sejak C++20)tidak ditentukan standar
Monotoniktidak (bisa lompat atau mundur)ya, dijamin
Cocok untuktanggal, jam dinding, kalendermengukur interval dan benchmark
cpp
#include <chrono>   // std::chrono: clock, time_point, duration
#include <iostream> // std::cout

int main() {
    using namespace std::chrono_literals;
    namespace ch = std::chrono;
    std::cout << std::boolalpha;

    // Sifat is_steady ditentukan implementasi dan tetap untuk setiap jam
    std::cout << "system_clock::is_steady: " << ch::system_clock::is_steady << "\n";
    std::cout << "steady_clock::is_steady: " << ch::steady_clock::is_steady << "\n";

    // time_point: now() mengembalikan titik waktu pada jam masing-masing
    auto mulai = ch::steady_clock::now();
    long long hasil = 0;
    for (int i = 1; i <= 100000; ++i) hasil += i;
    auto akhir = ch::steady_clock::now();

    // Nilai pasti durasi bergantung mesin; sifatnya yang bisa kita klaim
    std::cout << "akhir >= mulai: " << (akhir >= mulai) << "\n";
    std::cout << "hasil loop: " << hasil << "\n";

    // time_point system_clock berpresisi hari (sys_days) mendukung aritmetika
    ch::sys_days epoch{1970y / ch::January / 1};
    ch::sys_days tanggal = 2026y / ch::April / 15;
    ch::days selisih = tanggal - epoch; // time_point - time_point = duration
    std::cout << "hari sejak epoch: " << selisih.count() << "\n";

    return 0;
}

Output yang Dihasilkan:

text
system_clock::is_steady: false
steady_clock::is_steady: true
akhir >= mulai: true
hasil loop: 5000050000
hari sejak epoch: 20558

Mari kita bedah:

  1. Baris 10-11: is_steady adalah anggota statis konstan milik setiap clock — ditentukan implementasi, tetap sepanjang masa program. Di lingkungan kita, system_clock tidak monotonik dan steady_clock monotonik.
  2. Baris 14-17: pola stopwatch — mulai dan akhir bertipe time point hasil steady_clock::now(), dipisahkan pekerjaan loop. Ekspresi akhir - mulai menghasilkan duration yang nilainya bergantung mesin, sehingga contoh ini sengaja tidak mencetak angkanya.
  3. Baris 20: yang bisa kita klaim dari stopwatch hanyalah sifat monotoniknya — time point kedua tidak akan lebih kecil dari yang pertama, jadi program selalu mencetak true.
  4. Baris 24-27: sys_days adalah time point system_clock berpresisi hari. Pengurangan dua time point menghasilkan duration bertipe days: 15 April 2026 berjarak tepat 20558 hari dari epoch Unix.

Kalender C++20: year_month_day dan weekday #

Sebelum C++20, menghitung tanggal mengharuskan kita bekerja dengan angka hari sejak epoch. C++20 menambahkan keluarga tipe kalender pada <chrono>: std::chrono::year, month, day, dan gabungan year_month_day. Operator / merangkai ketiganya secara natural — 2026y / April / 15 — di mana literal y berasal dari std::chrono_literals dan April adalah konstanta std::chrono::month. Kombinasi tanggal yang tidak sah (misalnya 30 Februari) tetap bisa dibuat, tetapi anggota ok() melaporkannya false; sedangkan weekday menerima tanggal yang sah dan memberi hari dalam seminggu.

cpp
#include <chrono>   // std::chrono: tipe kalender C++20
#include <iostream> // std::cout

int main() {
    using namespace std::chrono_literals;
    namespace ch = std::chrono;
    std::cout << std::boolalpha;

    // Membentuk tanggal dari year, month, dan day lewat operator /
    ch::year_month_day rilis = 2026y / ch::April / 15;
    std::cout << "tanggal rilis : " << rilis << "\n";
    std::cout << "komponen      : " << rilis.year() << " "
              << rilis.month() << " " << rilis.day() << "\n";

    // weekday: nama hari dari tanggal yang sah
    std::cout << "hari          : " << ch::weekday{rilis} << "\n";

    // Validasi: 30 Februari 2024 tidak pernah ada
    ch::year_month_day salah = 2024y / ch::February / 30;
    std::cout << "30 Feb 2024   : " << salah << "\n";
    std::cout << "sah?          : " << salah.ok() << "\n";

    // Hari terakhir Februari 2026 lewat year_month_day_last
    ch::year_month_day_last ujung = 2026y / ch::February / ch::last;
    std::cout << "akhir Feb     : " << ch::year_month_day{ujung} << "\n";

    return 0;
}

Output yang Dihasilkan:

text
tanggal rilis : 2026-04-15
komponen      : 2026 Apr 15
hari          : Wed
30 Feb 2024   : 2024-02-30 is not a valid date
sah?          : false
akhir Feb     : 2026-02-28

Mari kita bedah:

  1. Baris 10 (ch::year_month_day rilis = 2026y / ch::April / 15;): 2026y bertipe year, April bertipe month, dan 15 menjadi day; rangkaian operator / membentuk tanggal lengkap.
  2. Baris 12-13: anggota year(), month(), dan day() mengembalikan komponennya, tercetak 2026 Apr 15; format operator<< untuk tanggal lengkap adalah ISO: 2026-04-15.
  3. Baris 16: ch::weekday{rilis} menghitung hari dalam seminggu; 15 April 2026 tercetak singkatan Wed.
  4. Baris 19-21: 30 Februari 2024 sah menurut tiap komponen, tetapi kombinasi tanggalnya tidak: operator<< menandainya is not a valid date dan ok() mengembalikan false — pakai pemeriksaan ini untuk tanggal dari input pengguna.
  5. Baris 24-25: year_month_day_last mewakili “hari terakhir dalam bulan” lewat penanda ch::last, sehingga kita tidak perlu menghafal 28/29/30/31; hasilnya 28 Februari 2026 (2026 bukan tahun kabisat).

Pengantar Time Zone dengan zoned_time #

Satu titik waktu sebenarnya global, tetapi tampilannya bergantung zona: saat UTC menunjukkan pukul 08.30, Jakarta menunjukkan 15.30. C++20 memodelkan ini dengan dua sudut pandang — sys_time (titik waktu absolut versi system_clock) dan local_time (waktu kalender yang belum terikat zona) — lalu menyambungnya lewat std::chrono::zoned_time. Objek zoned_time menyimpan nama zona bersama titik waktunya; saat dicetak, ia menampilkan waktu lokal beserta singkatan zona, dan get_local_time() mengembalikan local_time siap dipakai dengan tipe kalender. Zona ditulis dengan nama IANA seperti "Asia/Jakarta" atau "Europe/London".

cpp
#include <chrono>   // std::chrono: zoned_time dan tipe kalender
#include <iostream> // std::cout

int main() {
    using namespace std::chrono_literals;
    namespace ch = std::chrono;

    // Titik waktu UTC yang tetap: 15 April 2026, 08:30 pagi
    ch::sys_days hari = 2026y / ch::April / 15;
    ch::sys_seconds titikUtc = hari + 8h + 30min;
    std::cout << "UTC           : " << titikUtc << "\n";

    // zoned_time memandang titik waktu tersebut lewat zona tertentu
    ch::zoned_time jakarta{"Asia/Jakarta", titikUtc};
    std::cout << "Asia/Jakarta  : " << jakarta << "\n";

    ch::zoned_time london{"Europe/London", titikUtc};
    std::cout << "Europe/London : " << london << "\n";

    // Mengambil waktu lokal versi zona Jakarta
    ch::local_seconds lokal = jakarta.get_local_time();
    std::cout << "lokal Jakarta : " << lokal << "\n";

    return 0;
}

Output yang Dihasilkan:

text
UTC           : 2026-04-15 08:30:00
Asia/Jakarta  : 2026-04-15 15:30:00 WIB
Europe/London : 2026-04-15 09:30:00 BST
lokal Jakarta : 2026-04-15 15:30:00

Mari kita bedah:

  1. Baris 9-10: hari bertipe sys_days; menambahkan 8h + 30min menghasilkan sys_seconds — presisi naik otomatis tanpa memotong informasi, dan titik waktunya absolut di UTC.
  2. Baris 14-15: ch::zoned_time jakarta{"Asia/Jakarta", titikUtc} memandang titik UTC yang sama lewat zona Jakarta (+07:00, tanpa daylight saving), tercetak 2026-04-15 15:30:00 WIB.
  3. Baris 17-18: London pada pertengahan April sedang berlaku daylight saving (BST, +01:00), sehingga titik UTC yang sama tercetak 09.30 — perbedaan ini dihitung dari basis data zona, bukan konstanta yang kita tulis.
  4. Baris 21-22: get_local_time() mengembalikan local_seconds, yaitu waktu kalender versi Jakarta yang bisa dipecah lagi dengan tipe kalender sebelumnya.

Waktu kini tercakup utuh: dari nanodetik di stopwatch hingga tanggal berzona waktu. Ada satu utilitas kumpulan lagi yang sering dipakai saat kita bekerja pada level bit — std::bitset, himpunan bit berukuran tetap untuk flag dan operasi bitwise.

Rujukan resmi: cppreference — Date and time utilities , cppreference — std::chrono::duration , cppreference — std::chrono::year_month_day .