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.
| Konsep | Mewakili | Contoh tipe |
|---|---|---|
duration | rentang waktu (angka + satuan) | seconds, milliseconds, hours |
clock | sumber titik waktu | system_clock, steady_clock |
time_point | titik pada sebuah clock | sys_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.
#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:
total : 9045 detik
total : 9045s
tunggu: 250ms
mikro : 500us
nano : 100ns
campur: 90minMari kita bedah:
- Baris 5 (
using namespace std::chrono_literals;): membuka namespace literal sehingga2h,30min,45s,250ms,500us, dan100nsberlaku; tanpa baris ini2hditolak compiler. - 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 siniseconds— hasilnya 9045 detik. - Baris 10-11:
.count()mengembalikan angka tik saja (9045), sedangkanoperator<<yang tersedia sejak C++20 mencetak angka beserta akhiran satuan (9045s). - Baris 14-16: tipe
milliseconds,microseconds, dannanosecondsbertingkat lebih halus dariseconds; satuan menempel pada tipe, bukan pada nama variabel. - Baris 22 (
1h + 30min): tipe bersama untuk jam dan menit adalahminutes, sehingga hasilnya tercetak90min— 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.
#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:
2h = 7200000 ms (implisit)
1500 ms = 1 s (duration_cast)
125 menit = 2 jam, sisa 5 menit
floor: 1 | ceil: 2 | round: 2Mari kita bedah:
- Baris 9-11:
2hdikonversi dua kali secara implisit — kesecondslalu kemilliseconds— hasilnya 7200000 ms; tidak ada langkah yang memotong informasi. - 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. - Baris 19-22: 125 menit dipotong menjadi 2 jam; sisanya dihitung lewat pengurangan
menitKerja - jamKerjayang bertipeminutes— tercetak 5 menit. - Baris 25-27: untuk 1500 ms,
floormembulatkan ke bawah (1),ceilke atas (2), danroundke 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_clock | steady_clock | |
|---|---|---|
| Titik acuan | 1 Januari 1970 UTC (Unix Time, sejak C++20) | tidak ditentukan standar |
| Monotonik | tidak (bisa lompat atau mundur) | ya, dijamin |
| Cocok untuk | tanggal, jam dinding, kalender | mengukur interval dan benchmark |
#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:
system_clock::is_steady: false
steady_clock::is_steady: true
akhir >= mulai: true
hasil loop: 5000050000
hari sejak epoch: 20558Mari kita bedah:
- Baris 10-11:
is_steadyadalah anggota statis konstan milik setiap clock — ditentukan implementasi, tetap sepanjang masa program. Di lingkungan kita,system_clocktidak monotonik dansteady_clockmonotonik. - Baris 14-17: pola stopwatch —
mulaidanakhirbertipe time point hasilsteady_clock::now(), dipisahkan pekerjaan loop. Ekspresiakhir - mulaimenghasilkan duration yang nilainya bergantung mesin, sehingga contoh ini sengaja tidak mencetak angkanya. - 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. - Baris 24-27:
sys_daysadalah time pointsystem_clockberpresisi hari. Pengurangan dua time point menghasilkan duration bertipedays: 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.
#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:
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-28Mari kita bedah:
- Baris 10 (
ch::year_month_day rilis = 2026y / ch::April / 15;):2026ybertipeyear,Aprilbertipemonth, dan15menjadiday; rangkaian operator/membentuk tanggal lengkap. - Baris 12-13: anggota
year(),month(), danday()mengembalikan komponennya, tercetak2026 Apr 15; formatoperator<<untuk tanggal lengkap adalah ISO:2026-04-15. - Baris 16:
ch::weekday{rilis}menghitung hari dalam seminggu; 15 April 2026 tercetak singkatanWed. - Baris 19-21: 30 Februari 2024 sah menurut tiap komponen, tetapi kombinasi tanggalnya tidak:
operator<<menandainyais not a valid datedanok()mengembalikanfalse— pakai pemeriksaan ini untuk tanggal dari input pengguna. - Baris 24-25:
year_month_day_lastmewakili “hari terakhir dalam bulan” lewat penandach::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".
#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:
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:00Mari kita bedah:
- Baris 9-10:
haribertipesys_days; menambahkan8h + 30minmenghasilkansys_seconds— presisi naik otomatis tanpa memotong informasi, dan titik waktunya absolut di UTC. - Baris 14-15:
ch::zoned_time jakarta{"Asia/Jakarta", titikUtc}memandang titik UTC yang sama lewat zona Jakarta (+07:00, tanpa daylight saving), tercetak2026-04-15 15:30:00 WIB. - 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.
- Baris 21-22:
get_local_time()mengembalikanlocal_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 .