Java - Mengulik class java.util.Date
java.util.Date
java.util.Date merupakan class Java awal yang merepresentasikan data Tanggal dan Waktu.
Class ini tidak didesain secara bagus dari awal dan kurang merepresentasikan kerumitan dalam perhitungan penanggalan.
Padahal penanggalan sebenarnya mempunyai banyak komponen dan perhitungan yang cukup rumit. Misalnya tahun kabisat, daylight saving time di Eropa, perhitungan jumlah hari diantara 2 tanggal, jumlah bulan diantara 2 tanggal, dll.
Awalnya sepertinya class ini ditujukan sebagai class utama dalam merepresentasikan penanggalan, tetapi mereka membuatnya dengan struktur data yang sederhana, dan tidak memperhitungkan kerumitan kalkulasinya nanti.
Walaupun namanya adalah Date (artinya asumsinya tidak ada Time/Waktu di dalamnya), akan tetapi kenyataannya class java.util.Date merepresentasikan data Date/Tanggal dan Time/Waktu dan juga TimeZone dari JVM yang mengeksekusi proses java tersebut.
Apa yang ada di dalam class java.util.Date ?
java.util.Date sebenarnya menyimpan data dalam bentuk tipe data long berupa jumlah milisecond semenjak 01 Januari 1970 jam 00:00 tengah malam waktu GMT/UTC / Greenwich.
Misalnya :
- Rabu 2 Juni 2021, jam 20:20:24 , disimpan dalam object Date dalam bentuk long : 1622524588000. Ini adalah jumlah milisecond sejak 1 Jan 1970 itu.
Kalau kita lihat source code dari java.util.Date, sbb :
1package java.util;
2
3import sun.util.calendar.BaseCalendar;
4import sun.util.calendar.CalendarSystem;
5
6public class Date implements java.io.Serializable, Cloneable, Comparable<Date>
7{
8 private static final BaseCalendar gcal = CalendarSystem.getGregorianCalendar();
9 private static BaseCalendar jcal;
10 private transient long fastTime;
11 private transient BaseCalendar.Date cdate;
12 private static int defaultCenturyStart;
13 .
14 .
15 .
16 public Date() {
17 this(System.currentTimeMillis());
18 }
19
20 public Date(long date) {
21 fastTime = date;
22 }
23}
private transient long fastTime adalah nilai akhir dari nilai sebuah java.util.Date.
Semua kalkulasi terhadap java.util.Date, ujung-ujungnya akan disimpan ke variable long fastTime.
Kalkulasi, constructor dengan inputan tahun, bulan, dan hari, akan diproses/dinormalisasi/dihitung lalu akan disimpan ke variable fastTime tersebut.
Ketika nilai object java.util.Date ini diprint, maka class java.util.Date ini mengoverride fungsi toString() dengan melakukan kalkulasi tahun, tanggal, waktu, dan timezone dari JVM yang mengeksekusi proses tersebut, lalu menampilkannya di console atau sebagai nilai kembalian.
Dalam format : <Hari> <Tanggal> <Bulan> <Tanggal> <Jam>:<Menit>:<Detik> <ZoneId> <Tahun>
Contoh : Wed May 25 12:59:57 ICT 2021
misalkan coba kita eksekusi di code :
import java.util.Date;
.
.
Date now = new Date();
System.out.println("Tanggal Sekarang : " + now);
hasilnya :
Tanggal Sekarang : Wed May 25 12:59:57 ICT 2021
Dengan struktur data long seperti itu, maka akan menyulitkan dalam melakukan operasi rumit penanggalan. Mungkin ide awalnya bagus, yaitu membuat data Date ini menjadi terpusat ke satu variable fastDate saja, lalu dari variable tersebut bisa dilakukan kalkulasi terhadap penanggalan.
Akan tetapi ternyata sebenarnya masalah penanggalan bukan masalah sederhana, yang tidak bisa direpresentasikan dengan satu struktur data saja.
Dengan struktur data long seperti itu, maka praktis class java.util.Date sebenarnya tidak memiliki secara ekspilit/jelas komponen berikut :
- timezone
- format Tanggal
- sistem Kalendar seperti tahun kabisat, extra hour di negara tertentu, dll.
Apakah ada lagi kekurangannya ?
Tentu saja ada , kalau dikategorikan kekurangannya bisa dikelompokkan dalam kategori :
Desainnya
- tidak merepresentasikan Date/Tanggal itu sendiri, yang mestinya hanya Tanggal-Bulan-Tahun. Akan tetapi lebih merepresentasikan Instant yaitu waktu sekarang yang tergantung kepada Tanggal, waktu, dan juga TimeZone.
- penamaan class nya yang tidak representative. Date tetapi didalamnya ada juga Time.
- type data ini mutable, dan bisa diubah setelah dibuat. Akibatnya harus dipastikan bahwa kita melakukan clone dahulu sebelum mengubahnya apabila tidak ingin mengubah nilai yang sudah ada.
Fungsi yang aneh dan tidak intuitive/tidak natural
- Kalau kita menggunakan constructor new Date(tahun, bulan, tanggal), maka tahunnya dianggap dimulai dari 1900.
contoh code :
Date now = new Date(2021,4,25);
System.out.println("Tanggal Sekarang : " + now);
hasilnya:
Tanggal Sekarang : Wed May 25 12:59:57 ICT 3921
- bulan dimulai dari 0 (Januari - 0 s/d Desember 11). Membingungkan bagi developer pemula dan tidak intuitive dengan asumsi penanggalan bulan yang sehari-hari kita pakai.
- constructornya secara default adalah lenient atau fleksibel. Sehingga walaupun kita memasukkan nilai tanggal, atau bulan yang salah, tetap akan diterima dan dikalkulasi sendiri oleh programnya. Kita bisa membuat sebuah object dengan cara misalnya :
Date now = new Date(2021,4,32);
System.out.println("Tanggal Sekarang : " + now);
hasilnya:
Tanggal Sekarang : Wed Juni 1 12:59:57 ICT 3921
Walaupun kita men-set Tanggalnya 32, tetapi tetap saja parameternya diterima dan dikalkulasi sehingga menjadi tanggal 1. Ini menjadi membingungkan dan membuat constraint untuk penanggalan menjadi aneh.