ADT time
Latihan membuat instruksi pembelajaran untuk Abstract Data Type (ADT) time, dengan implementasi bahasa pemrograman Rust.
Mengenal dan mengimplementasikan Abstract Data Type (ADT) Time
(jam:menit:detik) menggunakan Rust sebagai modul terpisah, lalu memakai modul itu dari program utama. Fokusnya: enkapsulasi data (field private), konstruktor, validator, pembacaan dari pengguna, tampilan (display
), konversi ke detik (time_to_seconds
) dan kebalikan (seconds_to_time
).
Tujuan Pembelajaran
Setelah mempelajari modul ini Anda akan mampu:
Menjelaskan apa itu ADT dan mengapa enkapsulasi berguna.
Mengimplementasikan
struct Time
di Rust dengan API publik (metode).Menulis fungsi validasi rentang jam, menit, dan detik.
Membaca input pengguna (loop sampai valid) dan menampilkan waktu dengan format
HH:MM:SS
.Mengonversi
Time
⇄ detik dengan konsistensi (24 jam wrap-around).Menangani input invalid secara sederhana dan menjelaskan edge cases terkait representasi waktu.
Prasyarat
Dasar Rust:
struct
,impl
,mod
,use
,fn main()
.Membaca dari stdin (
std::io::stdin
) dan parsing string ke integer.Pemahaman ringkas tentang integer dan operasi modulo.
Desain API Time
secara ringkas
Time::new(h, m, s) -> Time
— konstruktor (menganggap input valid).Time::is_valid(h, m, s) -> bool
— validator rentang.Time::read_from_stdin() -> Time
— baca berulang sampai valid.Time::display(&self)
— cetakHH:MM:SS
.Time::to_seconds(&self) -> i32
— konversi ke detik dari 00:00:00.Time::from_seconds(n: i32) -> Time
— konversi detik ke Time (wrap di 24 jam).
Field hours
, minutes
, seconds
dibuat private agar hanya bisa diubah lewat metode — sesuai prinsip ADT (enkapsulasi).
Kode versi yang mudah dipahami
Buat project Rust (jika belum):
cargo new time_adtdemo
cd time_adtdemo
Buat file src/time.rs
dengan isi berikut:
// src/time.rs
// Modul Time: ADT sederhana untuk jam:menit:detik.
// Ditulis dengan gaya mudah dimengerti untuk pemula.
use std::io::{self, Write};
/// Tipe Time: fields private agar enkapsulasi terjaga.
#[derive(Debug, Clone, Copy)]
pub struct Time {
hours: i32, // 0..23
minutes: i32, // 0..59
seconds: i32, // 0..59
}
impl Time {
/// Konstruktor: asumsi input valid (gunakan is_valid sebelum memanggil jika perlu)
pub fn new(h: i32, m: i32, s: i32) -> Self {
Time { hours: h, minutes: m, seconds: s }
}
/// Validator: periksa rentang jam, menit, detik
pub fn is_valid(h: i32, m: i32, s: i32) -> bool {
(0..=23).contains(&h) && (0..=59).contains(&m) && (0..=59).contains(&s)
}
/// Baca Time dari stdin, ulangi sampai input valid.
/// Input dipisah spasi atau enter: misal "13 5 9" atau input interaktif.
pub fn read_from_stdin() -> Self {
loop {
print!("Masukkan jam menit detik (misal 13 05 09): ");
let _ = io::stdout().flush();
let mut line = String::new();
if io::stdin().read_line(&mut line).is_err() {
eprintln!("Gagal membaca input. Coba lagi.");
continue;
}
let parts: Vec<&str> = line.split_whitespace().collect();
if parts.len() < 3 {
eprintln!("Mohon masukkan tiga nilai: jam menit detik.");
continue;
}
// parsing sederhana; jika gagal, minta ulang
let h = parts[0].parse::<i32>();
let m = parts[1].parse::<i32>();
let s = parts[2].parse::<i32>();
match (h, m, s) {
(Ok(h), Ok(m), Ok(s)) => {
if Time::is_valid(h, m, s) {
return Time::new(h, m, s);
} else {
eprintln!("Nilai tidak valid. Jam 0-23, menit 0-59, detik 0-59.");
}
}
_ => {
eprintln!("Parsing gagal. Pastikan Anda memasukkan angka bulat.");
}
}
}
}
/// Cetak Time format HH:MM:SS (dua digit tiap komponen)
pub fn display(&self) {
println!("{:02}:{:02}:{:02}", self.hours, self.minutes, self.seconds);
}
/// Konversi Time ke total detik sejak 00:00:00
pub fn to_seconds(&self) -> i32 {
self.hours * 3600 + self.minutes * 60 + self.seconds
}
/// Konversi detik ke Time, dengan pembungkusan modulo 86400 (24 jam)
pub fn from_seconds(mut n: i32) -> Self {
const SECONDS_PER_DAY: i32 = 24 * 3600;
// pastikan n di rentang 0..86399; dukung n negatif juga dengan modulo sifatnya
n = ((n % SECONDS_PER_DAY) + SECONDS_PER_DAY) % SECONDS_PER_DAY;
let h = n / 3600;
let rem = n % 3600;
let m = rem / 60;
let s = rem % 60;
Time::new(h, m, s)
}
/// Getter sederhana (jika diperlukan)
pub fn hours(&self) -> i32 { self.hours }
pub fn minutes(&self) -> i32 { self.minutes }
pub fn seconds(&self) -> i32 { self.seconds }
}
Lalu buat file src/main.rs
:
// src/main.rs
mod time;
use time::Time;
fn main() {
// Baca time dari pengguna
let t1 = Time::read_from_stdin();
print!("Time yang dibaca: ");
t1.display();
// Konversi ke detik
let secs = t1.to_seconds();
println!("Konversi menjadi detik: {}", secs);
// Contoh dari detik -> time (misalnya 5000 detik)
let t2 = Time::from_seconds(5000);
print!("5000 detik sama dengan time: ");
t2.display();
// Contoh lain: handling nilai negatif dan lebih dari sehari
let t3 = Time::from_seconds(-1); // -1 => 23:59:59
print!("Contoh dari -1 detik => ");
t3.display();
let t4 = Time::from_seconds(90_000); // 90000 mod 86400 = 3600 => 01:00:00
print!("Contoh dari 90000 detik => ");
t4.display();
}
Penjelasan singkat kode:
Time::read_from_stdin()
membaca sebuah baris, mem-parsing tiga angka (jam menit detik). Jika input tidak valid, meminta ulang. Ini mudah bagi pemula (tidak menggunakan errorResult
yang lebih advanced).to_seconds()
mengubah jam-menit-detik menjadi jumlah detik sejak tengah malam.from_seconds()
melakukann % 86400
sehingga nilai detik dilipatkan ke rentang 0..86399—berguna bila input detik negatif atau melebihi 24 jam.Field
hours
,minutes
,seconds
diset private (tidakpub
) sehingga pengguna hanya mengakses melalui metode, menjaga invariants ADT.
Penjelasan Konsep ADT & Keputusan Desain
Enkapsulasi: Field dibuat private untuk mencegah pengguna melakukan injeksi nilai invalid tanpa melewati
is_valid
. ADT memberikan API publik yang menjaga invariants.Metode
read_from_stdin()
disederhanakan agar pemula tidak perlu memahamiResult
/error handling kompleks; di aplikasi produksi lebih baik mengembalikanResult<Time, Error>
.from_seconds
menggunakan modulo sehingga waktu selalu berada dalam satu hari (24 jam). Ini sesuai definisi ADT di contoh aslinya (C) yang membatasi jam 0..23.
Edge Cases yang perlu diketahui
Input non-angka atau format berbeda: program menolak dan meminta ulang. Untuk format yang berbeda (mis.
13:05:09
) perlu parsing tambahan.Nilai di luar rentang:
is_valid
akan menganggap tidak valid (mis. jam 25). Program akan meminta masukan ulang.Detik negatif:
from_seconds(-1)
dipetakan ke23:59:59
(menggunakan modulo ringkas yang mendukung negatif). Hal ini berguna bila menghitung selisih waktu.Overflow integer: dengan
i32
batasnya ±2 miliar (~68 tahun detik); untuk penggunaan praktis durasi pendek aman. Untuk aplikasi dengan rentang besar gunakani64
.Leap seconds: ADT ini tidak menangani detik tambahan (leap second). Jika lingkungan memerlukan akurasi astronomis, desain ADT harus diperluas.
Timezone / DST: ADT ini pure local clock; tidak mempertimbangkan zona waktu atau daylight saving time (DST). Untuk aplikasi dunia nyata, gunakan library waktu yang lengkap (chrono, time crate).
I/O locale: parsing angka mengharapkan pemisah spasi dan titik desimal tidak relevan karena integer; untuk pengguna memasukkan
13,05,09
parsing gagal.
Latihan Singkat untuk pembelajaran
Ubah
read_from_stdin
agar juga menerima formatHH:MM:SS
(mis.09:05:03
). Clue: pakaisplit(':')
selainsplit_whitespace()
.Tambahkan metode
add_seconds(&mut self, n: i32)
yang menambahkann
detik ke Time (mengupdate self). Clue: ubahto_seconds()
, tambahkann
, lalufrom_seconds
dan set fields.Buat fungsi
duration_between(t1: Time, t2: Time) -> i32
yang mengembalikan selisih detik t2 - t1 (bisa negatif). Clue: gunakanto_seconds()
lalu selisih.
Pertanyaan Refleksi beserta petunjuk jawaban singkat
Mengapa field
hours
/minutes
/seconds
lebih baik dibuat private? Clue / jawaban singkat: agar hanya lewat metode kita bisa memastikan nilai valid; ini menjaga invariant ADT.Apa yang terjadi bila kita langsung membuat
Time { hours: 25, ... }
jika field public? Clue / jawaban singkat: nilai invalid bisa tercipta—mengakibatkan perilaku tak terduga ketika mengkonversi ke detik.Kenapa
from_seconds
memakai modulo 86400? Clue / jawaban singkat: untuk memetakannya ke satu hari (24 jam), sehingga detik berlebih atau negatif tetap menghasilkan jam yang valid.Kapan ADT ini tidak cukup untuk aplikasi nyata? Clue / jawaban singkat: jika butuh zona waktu, leap seconds, kalender, atau dukungan waktu mutakhir—gunakan library waktu yang matang (mis.
chrono
crate).
Referensi
Materi dan struktur ADT
Time
ini mengikuti contoh dan konsep pengajaran ADT pada materi perkuliahan: Sekolah Teknik Elektro dan Informatika, Institut Teknologi Bandung. Contoh ADT Sederhana — ADT time (materi perkuliahan).Untuk pembaca yang ingin memperdalam implementasi waktu nyata/kompleks pada Rust, pertimbangkan dokumentasi crate waktu (mis.
chrono
,time
) dan buku resmi Rust: The Rust Programming Language.