Panduan untuk SimpleDateFormat

1. Perkenalan

Dalam tutorial ini, kita akan melakukan tur mendalam tentang kelas SimpleDateFormat .

Kita akan melihat contoh sederhana dan gaya pemformatan serta metode berguna yang diekspos kelas untuk menangani lokal dan zona waktu .

2. Instansiasi Sederhana

Pertama, mari kita lihat cara membuat instance objek SimpleDateFormat baru .

Ada 4 kemungkinan konstruktor - tetapi sesuai dengan namanya, mari kita buat semuanya tetap sederhana. Yang kita butuhkan untuk memulai adalah representasi String dari pola tanggal yang kita inginkan .

Mari kita mulai dengan pola tanggal yang dipisahkan tanda hubung seperti ini:

"dd-MM-yyyy"

Ini akan memformat tanggal dengan benar dimulai dengan hari saat ini pada bulan tersebut, bulan saat ini dalam setahun, dan terakhir tahun saat ini. Kami dapat menguji formatter baru kami dengan pengujian unit sederhana. Kami akan membuat instance objek SimpleDateFormat baru , dan meneruskan tanggal yang diketahui:

SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy"); assertEquals("24-05-1977", formatter.format(new Date(233345223232L))); 

Dalam kode di atas, pemformat mengubah milidetik sebagai l ong menjadi tanggal yang dapat dibaca manusia - 24 Mei 1977.

2.1. Metode Pabrik

Meskipun SimpleDateFormat adalah kelas yang berguna untuk membuat formatter tanggal dengan cepat, kami didorong untuk menggunakan metode pabrik pada kelas DateFormat getDateFormat () , getDateTimeFormat () , getTimeFormat () .

Contoh di atas terlihat sedikit berbeda saat menggunakan metode pabrik ini:

DateFormat formatter = DateFormat.getDateInstance(DateFormat.SHORT); assertEquals("5/24/77", formatter.format(new Date(233345223232L)));

Seperti yang dapat kita ketahui dari atas, jumlah opsi pemformatan ditentukan sebelumnya oleh bidang di kelas DateFormat . Ini sebagian besar membatasi opsi pemformatan kami yang tersedia, itulah sebabnya kami akan tetap menggunakan SimpleDateFormat di artikel ini.

2.2. Keamanan Benang

JavaDoc untuk SimpleDateFormat secara eksplisit menyatakan:

Format tanggal tidak disinkronkan. Direkomendasikan untuk membuat contoh format terpisah untuk setiap utas. Jika beberapa utas mengakses format secara bersamaan, itu harus disinkronkan secara eksternal.

Jadi instance SimpleDateFormat tidak aman untuk thread , dan kita harus menggunakannya dengan hati-hati di lingkungan yang bersamaan.

Pendekatan terbaik untuk mengatasi masalah iniadalah menggunakannya dalam kombinasi dengan ThreadLocal . Dengan cara ini, setiap utas berakhir dengan instance SimpleDateFormat -nya sendiri , dan kurangnya berbagi membuat program aman untuk utas:

private final ThreadLocal formatter = ThreadLocal .withInitial(() -> new SimpleDateFormat("dd-MM-yyyy"));

Argumen untuk metode withInitial adalah pemasok instance SimpleDateFormat . Setiap kali ThreadLocal perlu membuat sebuah instance, ia akan menggunakan pemasok ini.

Kemudian kita dapat menggunakan formatter melalui instance ThreadLocal :

formatter.get().format(date)

Metode ThreadLocal.get () menginisialisasi SimpleDateFormat untuk thread saat ini terlebih dahulu, kemudian menggunakan kembali instance tersebut.

Kami menyebutnya teknik thread confinement karena kami membatasi penggunaan setiap instance ke satu thread tertentu.

Ada dua pendekatan lain untuk mengatasi masalah yang sama:

  • Menggunakan blok tersinkronisasi atau ReentrantLock s
  • Membuat instance SimpleDateFormat sesuai permintaan

Kedua pendekatan ini tidak disarankan: Pendekatan pertama menghasilkan kinerja yang signifikan saat pertentangannya tinggi, dan yang kedua membuat banyak objek, memberi tekanan pada pengumpulan sampah.

Perlu disebutkan bahwa, sejak Java 8, kelas DateTimeFormatter baru telah diperkenalkan . Kelas DateTimeFormatter yang baru tidak dapat diubah dan aman untuk thread. Jika kita bekerja dengan Java 8 atau yang lebih baru, disarankan untuk menggunakan kelas DateTimeFormatter baru .

3. Tanggal Parsing

SimpleDateFormat dan DateFormat tidak hanya memungkinkan kita untuk memformat tanggal - tetapi kita juga dapat membalikkan operasi. Dengan menggunakan metode parse , kita dapat memasukkan representasi String dari sebuah tanggal dan mengembalikan objek Date yang setara:

SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy"); Date myDate = new Date(233276400000L); Date parsedDate = formatter.parse("24-05-1977"); assertEquals(myDate.getTime(), parsedDate.getTime());

It's important to note here that the pattern supplied in the constructor should be in the same format as the date parsed using the parse method.

4. Date-Time Patterns

SimpleDateFormat supplies a vast array of different options when formatting dates. While the full list is available in the JavaDocs, let's explore some of the more commonly used options:

Letter Date Component Example
M Month 12; Dec
y year 94
d day 23; Mon
H hour 03
m minute 57

The output returned by the date component also depends heavily on the number of characters used within the String. For example, let's take the month of June. If we define the date string as:

"MM"

Then our result will appear as the number code – 06. However, if we add another M to our date string:

"MMM"

Then our resulting formatted date appears as the word Jun.

5. Applying Locales

The SimpleDateFormat class also supports a wide range of locales which is set when the constructor is called.

Let's put this into practice by formatting a date in French. We'll instantiate a SimpleDateFormat object whilst supplying Locale.FRANCE to the constructor.

SimpleDateFormat franceDateFormatter = new SimpleDateFormat("EEEEE dd-MMMMMMM-yyyy", Locale.FRANCE); Date myWednesday = new Date(1539341312904L); assertTrue(franceDateFormatter.format(myWednesday).startsWith("vendredi"));

By supplying a given date, a Wednesday afternoon, we can assert that our franceDateFormatter has correctly formatted the date. The new date correctly starts with Vendredi -French for Wednesday!

It's worth noting a little gotcha in the Locale version of the constructor – whilst many locales are supported, full coverage is not guaranteed. Oracle recommends using the factory methods on DateFormat class to ensure locale coverage.

6. Changing Time Zones

Since SimpleDateFormat extends the DateFormat class, we can also manipulate the time zone using the setTimeZone method. Let's take a look at this in action:

Date now = new Date(); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("EEEE dd-MMM-yy HH:mm:ssZ"); simpleDateFormat.setTimeZone(TimeZone.getTimeZone("Europe/London")); logger.info(simpleDateFormat.format(now)); simpleDateFormat.setTimeZone(TimeZone.getTimeZone("America/New_York")); logger.info(simpleDateFormat.format(now));

In the above example, we supply the same Date to two different time zones on the same SimpleDateFormat object. We've also added the ‘Z' character to the end of the pattern String to indicate the time zone differences. The output from the format method is then logged for the user.

Hitting run, we can see the current times relative to the two time zones:

INFO: Friday 12-Oct-18 12:46:14+0100 INFO: Friday 12-Oct-18 07:46:14-0400

7. Summary

In this tutorial, we've taken a deep dive into the intricacies of SimpleDateFormat.

We've looked at how to instantiate SimpleDateFormat as well as how the pattern String impacts how the date is formatted.

Kami bermain-main dengan mengubah lokal dari output String sebelum akhirnya bereksperimen dengan menggunakan zona waktu .

Seperti biasa, kode sumber lengkap dapat ditemukan di GitHub.