Keadaan saat ini dari waktu ke waktu

Sejak JDBC ditemukan dan antarmukanya distandarisasi, 20 tahun telah berlalu, dan selama ini banyak hal telah berubah.

Pertama, dunia telah menjadi global dan sekarang satu server dapat melayani pengguna dari seluruh dunia. Kecepatan internet naik. Oleh karena itu, tipe data lain ditambahkan ke SQL untuk bekerja dengan waktu. Sekarang tipenya terlihat seperti ini:

  • DATE - menyimpan tanggal: tahun, bulan, hari.
  • WAKTU - menyimpan waktu: jam, menit, detik.
  • TIMESTAMP - menyimpan titik waktu tertentu: tanggal, waktu, dan milidetik.
  • TIMESTAMP WITH TIME ZONE - TIMESTAMP dan zona waktu (nama zona atau offset).

Kedua, Java memperkenalkan API DateTime untuk manajemen waktu global. Ini memiliki kelas-kelas berikut:

  • Tanggal dan waktu :
    • Tanggal Lokal
    • Waktu lokal
  • Momen yang tepat :
    • java.time.Instan
    • java.time.LocalDateTime
    • java.time.OffsetDateTime
    • java.time.ZonedDateTime
  • Waktu dengan zona waktu :
    • java.time.OffsetDateTime
    • java.time.ZonedDateTime

Poin menarik ketiga adalah bahwa banyak klien SQL ingin menerima waktu dari server yang sudah ada di zona lokal mereka . Tentu saja, Anda dapat mengonversi waktu dengan cepat, tetapi tidak nyaman, dan ada kesalahan.

Misalnya, saya ingin mendapatkan semua tugas hari ini dari database. SQL Server memiliki fungsi CURDATE() untuk ini. Hanya di sini servernya ada di AS, dan saya di Jepang. Dan saya ingin dia mengembalikan semua catatan untuk "hari ini", dan bukan "hari ini".

Secara umum, server SQL juga harus dapat bekerja secara cerdas dengan klien di zona waktu yang berbeda.

Masalah modern membutuhkan solusi modern

Pada prinsipnya, tipe baru dari Java DateTime API dan tipe dari SQL dapat dengan mudah dipetakan. Untuk merepresentasikan tipe DATE di Java, Anda perlu menggunakan kelas java.time.LocalDate dari JDK 8 DateTime API.

Jenis TIME dari database dapat diwakili oleh dua jenis dari Java: java.time.LocalTime dan java.time.OffsetTime . Tidak ada yang rumit juga.

Titik waktu tertentu, diwakili oleh tipe TIMESTAMP dalam database, dapat direpresentasikan dalam Java dengan 4 tipe:

  • java.time.Instan
  • java.time.LocalDateTime
  • java.time.OffsetDateTime
  • java.time.ZonedDateTime

Dan terakhir, TIMESTAMP WITH TIME ZONE dapat diwakili oleh dua jenis:

  • java.time.OffsetDateTime
  • java.time.ZonedDateTime

Karena Anda sudah familiar dengan DateTime API, mengingat hal ini tidak akan menyulitkan Anda :)

Saya akan menuliskannya dalam bentuk tabel, agar lebih mudah:

JENIS SQL Tipe Jawa
TANGGAL java.time.LocalDate
WAKTU java.time.LocalTime
java.time.OffsetTime
URUTAN WAKTU java.time.Instant
java.time.LocalDateTime
java.time.OffsetDateTime
java.time.ZonedDateTime
URUTAN WAKTU DENGAN ZONA WAKTU java.time.OffsetDateTime
_

Mendapatkan tanggal

Saya punya kabar baik untuk Anda. Pertama dalam waktu yang lama. Kita bisa mengatasi batasan metode getDate() , yang mengembalikan tipe Date java.sql.

Intinya adalah bahwa objekkumpulan hasilada metode lain yang menarik - getObject() . Metode ini mengambil dua parameter: kolom dan tipe, dan mengembalikan nilai kolom yang dikonversi ke tipe yang diberikan. Bentuk umum dari metode ini adalah sebagai berikut:

ClassName Name = getObject(column, ClassName);

Dan jika Anda ingin mengonversi tipe DATE ke tipe java.time.LocalDate , maka Anda perlu menulis sesuatu seperti:

LocalDate localDate = results.getObject(4, LocalDate.class);

Dan TIMESTAMP apa pun secara umum dapat dikonversi ke banyak jenis:

java.time.Instant instant = results.getObject(9, java.time.Instant.class);
java.time.LocalDateTime local = results.getObject(9, java.time. LocalDateTime.class);
java.time.OffsetDateTime offset = results.getObject(9, java.time. OffsetDateTime.class);
java.time.ZonedDateTime zoned = results.getObject(9, java.time. ZonedDateTime.class);

Penting! Kode ini tidak akan berfungsi jika Anda memiliki Driver MySQL JDBC yang kedaluwarsa . Perhatikan versi "mysql-connector-java" yang ditulis di pom.xml Anda, atau ditambahkan ke Perpustakaan di pengaturan proyek.

Ngomong-ngomong, dengan cara yang sama, Anda bisa mengatasi ketidakmampuan menyimpan null untuk tipe primitif. Jika kolom tabel bertipe INT, maka ada beberapa cara untuk mendapatkan null darinya. Lihat contoh di bawah ini:

Integer id1 = results.getObject(8, Integer.class);    	 // this will work
Integer id2 = results.getObject(8, int.class);                 //this will also work
int id3 = results.getObject(8,  Integer.class);            	//method will return null, JVM will throw NPE
int id4 = results.getObject(8,  int.class);                    	//method will return null, JVM will throw NPE

Pengaturan zona waktu di MySQL

Banyak hal menarik juga terjadi dengan MySQL. Seperti yang Anda ketahui, saat membuat koneksi MySQL, Anda dapat menambahkan berbagai parameter ke dalamnya :
mysql://localhost:3306/db_scheme?Name=meaning&Name=meaning

Jadi, tiga parameter telah ditambahkan untuk bekerja dengan zona waktu di MySQL. Anda dapat melewatkan parameter ini saat membuat koneksi ke server.

Di bawah ini saya akan memberikan tabel dengan mereka:

Parameter Nilai Nilai default
connectionTimeZone LOKAL | SERVER | zona pengguna SERVER
forceConnectionTimeZoneToSession benar | PALSU BENAR
preservedInstant benar | PALSU PALSU

Menggunakan parameter connectionTimeZone , kami memilih zona waktu (zona waktu) di mana semua permintaan akan dieksekusi. Dari sudut pandang klien, server berjalan di zona waktu yang ditentukan.

Parameter forceConnectionTimeZoneToSession menyebabkan variabel time_zone sesi diabaikan dan diganti dengan connectionTimeZone.

Terakhir, parameter protectInstants mengontrol konversi waktu-tepat antara timeZone JVM dan connectionTimeZone.

Konfigurasi yang paling umum adalah:

  • connectionTimeZone=LOCAL & forceConnectionTimeZoneToSession=false - sesuai dengan driver MySQL JDBC lama versi 5.1 dengan useLegacyDatetimeCode=true.

  • connectionTimeZone=LOCAL & forceConnectionTimeZoneToSession=true adalah mode baru yang menyediakan cara paling alami untuk menangani nilai tanggal dan waktu.

  • connectionTimeZone=SERVER & preserveInstants=true - Sesuai dengan driver MySQL JDBC lama versi 5.1 dengan useLegacyDatetimeCode=false.

  • connectionTimeZone=user_defined & preserveInstants=true - Membantu mengatasi situasi di mana zona waktu server tidak dapat dikenali oleh konektor karena diatur sebagai singkatan generik seperti CET/CEST.

Ya, kencan adalah topik yang menarik dan ada banyak masalah dengannya. Seperti kata pepatah: menakutkan, tentu saja, tapi saya juga tidak marah! :)