Rumah  >  Artikel  >  Java  >  Mari lakukan tarikh dengan betul

Mari lakukan tarikh dengan betul

王林
王林asal
2024-08-05 20:17:301104semak imbas

Lets do dates properly

Sebagai seorang pemula, salah satu topik paling menarik yang akan anda pelajari ialah Dates. Walaupun ia mungkin kedengaran agak membosankan, ia adalah salah satu perkara penting yang mungkin anda ketahui; daripada Pangkalan Data anda, API, GUI dan banyak lagi mempelajari cara menangani tarikh dengan betul adalah faktor utama dalam menulis aplikasi yang baik.

Sebelum kita mulakan

Perincian penting yang anda mesti ingat ialah Java telah disegerakan untuk web, oleh itu anda mempunyai banyak cara yang aneh dan agak bodoh untuk melakukan sesuatu. Matlamat panduan ini adalah untuk mengajar anda cara menggunakan API Java terkini untuk menulis kod baik yang cekap. Saya akan berhasrat untuk mengajar anda cara untuk tidak mengekodkan apa-apa yang sukar dan sebaliknya menggunakan ISO piawai untuk aplikasi berskala.

Bagaimana untuk bekerja dengan Dates

API Tarikh

Sehingga Java 8 SE dengan keluaran Kelas Tarikh ditakrifkan sebagai:

Tarikh kelas mewakili sesaat tertentu dalam masa, dengan ketepatan milisaat.

Selain itu, kami mempunyai penambahan Kelas Kalender Abstrak (dengan peningkatan ketara dengan JDK 1.1) yang ditakrifkan sebagai:

Kelas Kalendar ialah kelas abstrak yang menyediakan kaedah untuk menukar antara sesaat tertentu dalam masa dan satu set medan kalendar seperti YEAR, MONTH, DAY_OF_MONTH, HOUR dan sebagainya, dan untuk memanipulasi medan kalendar, seperti mendapat tarikh minggu hadapan. Sesaat dalam masa boleh diwakili oleh nilai milisaat yang merupakan offset daripada Epoch, 1 Januari 1970 00:00:00.000 GMT (Gregorian).

Seperti yang dinyatakan oleh dokumen Oracle, sebabnya ialah kekurangan kebolehan pengantarabangsaan.

Adalah baik untuk ambil perhatian bahawa dokumentasi yang sama yang dipautkan di atas menerangkan dengan lebih terperinci tentang masanya jika ia menarik minat anda.

API LocalDate

Juga dengan Java 8 SE datang Kelas LocalDate yang dirujuk kepada:

Tarikh tanpa zon waktu dalam sistem kalendar ISO-8601, seperti 2007-12-03.
LocalDate ialah objek tarikh-masa tidak boleh diubah yang mewakili tarikh, sering dilihat sebagai tahun-bulan-hari. Medan tarikh lain, seperti hari-dalam-tahun, hari-dalam-minggu dan minggu-dalam-tahun, juga boleh diakses. Contohnya, nilai "2hb Oktober 2007" boleh disimpan dalam LocalDate.

Spesifikasi penting yang perlu diambil perhatian ialah:

Kelas ini tidak menyimpan atau mewakili masa atau zon waktu. Sebaliknya, ia adalah perihalan tarikh, seperti yang digunakan untuk hari lahir. Ia tidak boleh mewakili sesaat pada garis masa tanpa maklumat tambahan seperti offset atau zon waktu.

Perbezaan & Mana satu untuk digunakan

Isu dengan API Tarikh/Masa

Membaca kelas LocalDate selanjutnya akan membawa anda ke "Kelas ini tidak boleh diubah dan selamat untuk thread." Ini membawa kita kepada masalah pertama kita.

  • Kedua-dua Tarikh dan Kalender tidak selamat untuk benang. Jika anda agak keliru tentang maksudnya - Benang ialah cara untuk melaksanakan keselarasan dengan aplikasi komputer ini membolehkan berbilang tugasan dijalankan secara serentak dan bukannya secara berurutan (Jika anda mempunyai latar belakang pengaturcaraan, anda boleh melihat ini sebagai async) .
  • Isu lain dengan API Tarikh/Kalender ialah reka bentuknya yang lemah. Kemudian, ia telah dirombak untuk menjadi ISO-centric (Jika anda agak tersesat tentang apa keseluruhan ISO ini; secara ringkasnya ISO bermaksud "Organisasi Antarabangsa untuk Standardisasi") Dan kita akan melihat faedah tambahan ini kemudian.
  • Dan akhir sekali, kembali kepada kekurangan pengantarabangsaan ialah pembangun dikehendaki menulis logik mereka untuk mengendalikan zon waktu yang berbeza yang boleh mengakibatkan banyak kesilapan sebagai miss-match.

Perbezaan sebenar

Perbezaan terbesar ialah walaupun nama Date akan menyimpan kedua-dua masa dan tarikh (seperti yang dinyatakan oleh dokumen dengan mengimbangi milisaat sejak zaman - kita akan bercakap tentang zaman kemudian). Dengan API yang lebih baharu, kami mendapat akses kepada Pemformatan/Penghuraian/Manipulasi Tarikh yang lebih mudah.

Bagaimana jika saya mahu menyimpan masa juga?

Baik Java telah anda bincangkan di sana juga dengan Kelas LocalDateTime mereka

Masa tarikh tanpa zon waktu dalam sistem kalendar ISO-8601, seperti 2007-12-03T10:15:30.
LocalDateTime ialah objek tarikh-masa tidak berubah yang mewakili tarikh-masa, sering dilihat sebagai tahun-bulan-hari-jam-minit-saat. Medan tarikh dan masa lain, seperti hari-dalam-tahun, hari-dalam-minggu dan minggu-dalam-tahun, juga boleh diakses. Masa diwakili oleh ketepatan nanosaat. Sebagai contoh, nilai "2 Oktober 2007 pada 13:45.30.123456789" boleh disimpan dalam LocalDateTime.

Jika anda ingin hanya mahu menyimpan masa maka anda boleh menggunakan Kelas Masa Setempat

Imbas ringkas dan kes penggunaan pantas

Name Should Use Use Case Example
LocalDate Interprating Dates 2021-02-28
LocalTime Interprating Time 19:32:25.457826
LocalDateTime Interprating Time/Date 2021-02-28T19:32:25.457826.
Date prefer not Represents Time Tue Jul 12 18:35:37 IST 2016

LocalDate

Sekarang kita mempunyai pemahaman yang baik tentang latar belakangnya dan perkara yang boleh kita lakukan dengannya, mari kita terokai kaedah kelas LocalDate.

ISO 8601

Sistem kalendar ISO-8601 ialah sistem kalendar sivil moden yang digunakan hari ini di kebanyakan dunia. Ia bersamaan dengan sistem kalendar Gregorian proleptik, di mana peraturan hari ini untuk tahun lompat digunakan untuk sepanjang masa. Untuk kebanyakan aplikasi yang ditulis hari ini, peraturan ISO-8601 adalah sesuai sepenuhnya. Walau bagaimanapun, mana-mana aplikasi yang menggunakan tarikh bersejarah, dan memerlukannya tepat akan mendapati pendekatan ISO-8601 tidak sesuai.

Ini ialah Java standard yang akan digunakan untuk memformat tarikh kami dengan betul.

Temporal

Sebelum kami melakukan penyelaman mendalam, saya ingin memperkenalkan anda kepada objek Temporal yang semua API Tarikh baharu dilaksanakan (LocalDate, LocalTime, LocalDateTime) ia ditakrifkan sebagai:

Ini ialah jenis antara muka asas untuk tarikh, masa dan objek mengimbangi yang cukup lengkap untuk dimanipulasi menggunakan tambah dan tolak. Ia dilaksanakan oleh kelas yang boleh menyediakan dan memanipulasi maklumat sebagai medan atau pertanyaan. Lihat TemporalAccessor untuk versi baca sahaja antara muka ini.

Tidak mendalami perkara ini hanya mahu anda semua memahami perkara ini jika anda menghadapinya.

Kaedah

Format untuk ini akan mengikut urutan - Nama kaedah, perihalan pulangan yang ditentukan dan ringkasan pantas tentang perkara yang dilakukan/atau penyelaman mendalam. Jika anda mahu mengikutinya, saya akan menggunakan jshell hanya import java.time.LocalDate dan salin kaedah yang sama.

LocalDate.now(): > tarikh semasa menggunakan jam sistem dan zon masa lalai, bukan nol

Seperti yang dinyatakan oleh huraian, ia akan mengembalikan format tarikh semasa berdasarkan zon waktu sebagai contoh bagi saya ia memberikan 2024-07-10 namun format mungkin berubah berdasarkan masa setempat anda bergantung pada format ISO 8601 yang diberikan untuk negara anda (cth. mungkin pada 2024.07.10 atau 24/7/10 ini adalah standard yang akan digunakan oleh negara anda)

Kaedah LocalDate.now() boleh mengambil hujah. Untuk menggunakan ini, kami akan mengimport java.time.ZoneId.

Apakah ZoneId?

ZoneId Dikeluarkan dengan Java 8SE ditakrifkan sebagai:

ZoneId digunakan untuk mengenal pasti peraturan yang digunakan untuk menukar antara Instant dan LocalDateTime. Terdapat dua jenis ID yang berbeza:

  • Offset tetap - offset diselesaikan sepenuhnya daripada UTC/Greenwich, yang menggunakan ofset yang sama untuk semua tarikh-masa tempatan
  • Wilayah geografi - kawasan di mana set peraturan khusus untuk mencari offset daripada UTC/Greenwich dikenakan

Secara ringkasnya, ini menyelesaikan isu pengantarabangsaan yang kami hadapi dengan API Date lama. Selepas mengimport java.time.ZoneId kita boleh melihat beberapa kaedah yang ditawarkannya.

  • ZoneId.getAvailableZoneIds() Menunjukkan kepada kita semua zon yang tersedia di sini adalah beberapa contohnya: Eropah/Istanbul, Amerika/Eirunepe, Dll/GMT-4, America/Miquelon (Ingat setiap satu daripada ini adalah unik dan kami mempunyai dua jenis ID unik yang disenaraikan di atas).
  • ZoneId.systemDefault() Kaedah ditakrifkan sebagai "Jika zon masa lalai sistem diubah, maka hasil kaedah ini juga akan berubah." Yang jelas.
  • ZoneId.of("") Kami menggunakan ini untuk mentakrifkan set tersuai ZoneId daripada senarai .getAvailableZoneIds(). Ingat kedua-dua UTC dan Eropah/Istanbul yang digunakan sebagai contoh di sini boleh digunakan.
  • ZoneId.from() Ingat temporal yang kita bincangkan sebelum ini? Di sini kita akan luluskan sebagai hujah. Jika anda tidak pasti sepenuhnya perkara ini lakukan, memandangkan ==TemporalAccessor yang mewakili set maklumat tarikh dan masa sewenang-wenangnya, kami akan mendapat ZoneId. Jika anda masih kurang faham, anda boleh mengimport java.time.ZoneId dan menggunakan ZonedDateTime.now() yang akan memberi anda masa/tarikh yang tepat yang kemudian anda boleh menghuraikan ke ZoneId. Pada asasnya ZoneId.from(ZonedDateTime.now())

Terdapat juga hujah Jam yang anda boleh luluskan, tetapi saya tidak nampak apa-apa kegunaannya apabila anda hanya boleh menggunakan ZoneID tetapi jangan ragu untuk menerokanya

Sekarang kita mengetahuinya - Mari dapatkan tarikh semasa di Paris!

LocalDate.now(ZoneId.of("Europe/Paris")) // 2024-07-10
LocalDate.of(year, month, day of month): > Mendapatkan kejadian LocalDate dari tahun, bulan dan hari.

Ingat LocalDate mewakili Tarikh. Dalam kes ini, kita boleh menetapkan tarikh itu kepada mana-mana tahun, bulan dan hari yang kita mahu!

LocalDate.ofYearDay(year, dayOfYear): >

Dalam banyak kes, anda mungkin hanya mempunyai setahun dan sehari. Fungsi ini menukarnya kepada format Tahun-Bulan-Hari. Berikut ialah contoh LocalDate.ofYearDay(2023, 234) akan menjadi 2023-08-22. Tahun lompat juga akan diambil kira.

LocalDate.parse(text) : > Obtains an instance of LocalDate from a text string using a specific format.

Basically, if we generate a String Date format like 2023-08-22 this will convert it into a LocalDate format

Epoch

There’s one last method I would like to talk about and even though it might not be that useful, it's a good thing to know.
Epoch in simple terms is a date set to the start. Virtually means it's “The start of time”. For example UNIX epoch is set to 1970/1/1 This is when all Unix time is calculated. Now this is not standardized between all computers. Most programming languages will use the UNIX epoch but not between all devices. For example NTP epoch is 1900/1/1. Now you might be asking why. And the simple answer is I don’t know. Unix was developed in 1969 and released in 71 but I guess the developers found 70 easier to work with and now that’s what we use!

LocalDate.ofEpochDay(epochDay) : >

Just going based on the description I gave about the output of this would be X days from 1970/1/1. Given epochDay is 1 => 1970-01-02 and so on.

~
~
~

By now I think you guys are all bored of all this nerdy talk and most likely lost interest completely but we are going to make it way more interesting in just a bit.
LocalDate methods have a ton of subsets to modify dates as we talked about above. Explaining all of these is just a waste of time. The best thing is for you guys to check ’em out and play around a bit, they are all very simple to understand.

Locale

The main idea of this whole article was to teach you internationalization and we are going to start that now.
If you recall above I talked about how LocalDate.now() might show different numbers/punctuations and this is standardized by Locale Class

A Locale object represents a specific geographical, political, or cultural region. An operation that requires a Locale to perform its task is called locale-sensitive and uses the Locale to tailor information for the user. For example, displaying a number is a locale-sensitive operation— the number should be formatted according to the customs and conventions of the user's native country, region, or culture.

Again the Locale class uses pre-defined ISO standards that Oracle has included.

As I said - In the early days of the web Java was rushed and we can really see that here.

Locale Constant & Why not to use

If you import java.util.Locale you can see that we have a few constants. Locale.CANADA as an example. If you're wondering what these are and why they were picked, it's quite simple. Due to the reason mentioned above, the Java devs just picked some Locale constants to support and you should not use them. Now if you look closely we have a Locale.French
and a Locale.France and you might be confused, what is this?? I’ll talk about it in a second

Now how do we go about using these Locales? By using Locale.availableLocales() you will see a large subset of available locales that you can use. you might see it in the format of en_US and you might get confused. Following up on the question listed above Java has accounted for different language subsets used in different countries. In this France/French example, We can refer to Canadian French versus French used in France. They are not entirely the same. Now a country like Iran will use Persian no matter the place, so you could just use Locale.of(language) to specify the Locale, But for French you could rather use Locale.of(language, country). Remember if you split what you got from Locale.availableLocales() by the _ you can just format it like that. An example would be Locale.of("en", "US") for en_US

Now let's implement this into our time for our different users around the globe.

System.out.println(
LocalDate.now().format(

DateTimeFormatter

.ofLocalizedDate(FormatStyle.SHORT)

.localizedBy(Locale.GERMAN)));

Now don’t mind the extra code, and even me using Locale.GERMAN cause honestly I was looking for a different output and the easiest way was to use Javas constants. I landed on Locale.GERMAN which outputs 10.07.24 as opposed to what Japan uses (2024/07/10).

Why not use Locale.of()

Now it might sound weird, but first of all i tell you not to use constants and prefer Locale.of(), then I tell you not to use Locale.of() an important factor to consider is Locale.of() was introduced with Java 19 which goes against supporting Java 8 SE to combat that from now on we will use

new Locale.Builder()
            .setLanguage("language")
            .setRegion("country").build();

Now another thing you could use is Locale.setDefault(language, country) which will work as well.

DateTimeFormatter

Now looking at the code above you might recall seeing DateTimeFormatter defined by docs as:

Formatter for printing and parsing date-time objects.

LocalDate.format()

As I mentioned above, one of the key features of Date/Time Local* APIs was formatting. And this is how we are going to format our dates. Looking at the code above - everything should make sense apart from the .ofLocalizedDate() method. The easiest way to show what it does is with an example.

LocalDate anotherSummerDay = LocalDate.of(2016, 8, 23);
System.out.println(DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL).format(anotherSummerDay));
System.out.println(DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG).format(anotherSummerDay));
System.out.println(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).format(anotherSummerDay));
System.out.println(DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT).format(anotherSummerDay));

will output the following in order:

Tuesday, August 23, 2016
August 23, 2016
Aug 23, 2016
8/23/16

Now sometimes you might want to have your own pattern which you can easily do with

System.out.println(

LocalDate.now().format(

DateTimeFormatter

.ofPattern("dd-uuuu-MMM")));

Now I’ll quickly go over what these symbols mean:
dd => It's a representation of the day field, now you could also use d and the difference would be that d would not have a fixed character limit since it represents 1 digit from 0-9 and 2 from 10-31. if you're lost it basically means dd would show 01; however d would show 1. However, going into two digits it's the same
uuuu/yyyy => Is the field for years. And you could also do yy which would show only the last two digits of the year. ex. 24 rather than 2024
MMM => The last field as you might have guessed is for the month - MMM tells Java that we want a String representation rather than a number. If you want a number use MM

So by now, you should’ve guessed that the output would be:

10-2024-Jul

Instants

Now that you have a firm grip on Dates. I want to introduce you to Instants defined as:

An instantaneous point on the timeline.

Basically, this refers to Instants showing a specific moment.
By now you might have assumed that LocalDateTime has a timezone, but it doesn’t as the docs mentioned they are just a representation of date/time. However a ZoneId is in fact a representation of a time zone. Also, note that Instants don’t provide methods for altering our dates and times.

Instants capture the current moment in UTC with the Instant.now() . Now based on this, you realize that Local* really doesn’t have a meaning unless it's applied, that’s the reason why you would actually refrain from using it in a business-level application. So prefer using ZonedDateTime and Insant. As a general rule of thumb use Locale When it's a specific point on a timeline rather than a moment in time. A moment would be like the moment I publish this, or the moment you read this, or the moment the world explodes, however a point in a timeline would be like an appointment there’s no moment for an appointment. If you're going on a vacation it's a specific time on a timeline, not a moment.

Whats ZonedDateTime?

Quite simple. It's just an Instant with a ZoneId and this is why we say Insant has a timezone. No matter what you do it's not going to represent a time but rather be a specific moment.

Aigh’t well that was quite the thing, wasn’t it? phew
have a nice one >#

Atas ialah kandungan terperinci Mari lakukan tarikh dengan betul. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn