デートはきちんとしましょう

王林
リリース: 2024-08-05 20:17:30
オリジナル
1067 人が閲覧しました

Lets do dates properly

初心者として学ぶ最も興味深いトピックの 1 つは日付です。少し退屈に聞こえるかもしれませんが、これはあなたが知っている重要なことの 1 つです。データベース、API、GUI などから日付を適切に扱う方法を学ぶことは、優れたアプリケーションを作成するための重要な要素です。

始める前に

覚えておくべき重要な点は、Java は Web 向けに急遽開発されたものであるため、風変わりでやや愚かな実行方法が多数あるということです。このガイドの目的は、最新の Java API を使用して効率的で優れたコードを作成する方法を説明することです。私は、難しいコーディングをせずに、スケーラブルなアプリケーションのために標準化された ISO を使用する方法を教えることを目指しています。

日付の操作方法

日付API

Java 8 SE 以降、Date クラスのリリースでは次のように定義されています。

Date クラスは、ミリ秒の精度で特定の瞬間を表します。

さらに、次のように定義された Abstract Calender クラス (JDK 1.1 による大幅なアップグレードを伴う) が追加されました。

Calendar クラスは、特定の瞬間と YEAR、MONTH、DAY_OF_MONTH、HOUR などのカレンダー フィールドのセットとの間の変換、および次のようなカレンダー フィールドの操作のためのメソッドを提供する抽象クラスです。来週の日付を取得します。瞬間は、エポック、1970 年 1 月 1 日 00:00:00.000 GMT (グレゴリオ暦) からのオフセットであるミリ秒値で表すことができます。

Oracle のドキュメントに記載されているように、その理由は国際化機能の欠如でした。

興味があれば、上にリンクされている同じドキュメントでタイミングについてさらに詳しく説明されていることに注意してください。

LocalDate API

Java 8 SE では、次のように参照される LocalDate クラスも追加されました。

ISO-8601 暦法におけるタイムゾーンのない日付 (2007-12-03 など)。
LocalDate は、日付を表す不変の日付時間オブジェクトであり、多くの場合、年-月-日として表示されます。年間の日付、曜日、週などの他の日付フィールドにもアクセスできます。たとえば、値「2007 年 10 月 2 日」を LocalDate に保存できます。

注意すべき重要な仕様は次のとおりです:

このクラスは、時間やタイムゾーンを保存したり表したりしません。代わりに、誕生日に使用されるような日付の説明です。オフセットやタイムゾーンなどの追加情報がなければ、タイムライン上の瞬間を表すことはできません。

違いとどちらを使用するか

日付/時刻 API の問題

LocalDate クラスをさらに読むと、「このクラスは不変でスレッドセーフである」ということがわかります。これにより、最初の問題が発生します。

  • 日付とカレンダーの両方がスレッドセーフではありませんでした。それが何を意味するのか少し混乱している場合は、スレッドはコンピューター アプリケーションとの同時実行性を実装する方法であり、これにより複数のタスクを順次ではなく同時に実行できるようになります (プログラミングの経験がある場合は、これを非同期として理解できます) 。
  • 日付/カレンダー API のもう 1 つの問題は、設計が不十分であることです。その後、ISO を中心としたものに刷新されました (ISO が何なのかよく分からない方のために説明しておきます。簡単に言えば、ISO は「国際標準化機構」の略です)。そして、この追加の利点については後ほど説明します。
  • そして最後に国際化の欠如に戻りますが、開発者は異なるタイムゾーンを処理するためのロジックを作成する必要があり、これにより不一致として多くのエラーが発生する可能性があります。

実際の違い

最大の違いは、Date という名前にもかかわらず、時間と日付の両方を保存することです (ドキュメントでエポックからのミリ秒オフセットについて述べられているように、エポックについては後で説明します)。新しい API を使用すると、日付の書式設定/解析/操作が簡単になりました。

時間も保存したい場合はどうすればよいですか?

Java では、LocalDateTime クラスを使用してこの問題にも対応できます

2007-12-03T10:15:30 など、ISO-8601 カレンダー システムのタイムゾーンのない日付と時刻。
LocalDateTime は、日時を表す不変の日時オブジェクトであり、多くの場合、年、月、日、時、分、秒として表示されます。年間の日付、曜日、週など、他の日付と時刻のフィールドにもアクセスできます。時間はナノ秒の精度で表されます。たとえば、値「2007 年 10 月 2 日 13:45.30.123456789」は LocalDateTime に保存できます。

時刻のみを保存したい場合は、LocalTime クラスを使用できます

簡単な要約とユースケース

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 クラスのメソッドを調べてみましょう。

ISO8601

ISO-8601 暦法は、現在世界のほとんどの地域で使用されている現代の常法暦法です。これは、現在の閏年の規則が常に適用される、予期的なグレゴリオ暦システムに相当します。現在作成されているほとんどのアプリケーションには、ISO-8601 ルールが完全に適しています。ただし、過去の日付を使用し、その正確性を要求するアプリケーションでは、ISO-8601 のアプローチは不適切であることがわかります。

これは、Java が日付を適切にフォーマットするために使用する標準です。

時間的

詳しく説明する前に、すべての新しい Date API が実装する Temporal オブジェクト (LocalDate、LocalTime、LocalDateTime) について紹介します。このオブジェクトは次のように定義されています。

これは、プラスとマイナスを使用して操作できるほど完全な、日付、時刻、およびオフセット オブジェクトの基本インターフェイス タイプです。これは、情報をフィールドまたはクエリとして提供および操作できるクラスによって実装されます。このインターフェイスの読み取り専用バージョンについては、TemporalAccessor を参照してください。

これについては深く掘り下げませんが、遭遇した場合にこれが何であるかを理解してもらいたかっただけです。

メソッド

この形式は、メソッド名、指定された戻り値の説明、およびその動作の簡単な概要/または詳細な説明です。手順に従っていきたい場合は、jshell を使用して java.time.LocalDate をインポートし、同じメソッドをコピーします。

LocalDate.now(): >;システムクロックとデフォルトのタイムゾーンを使用した現在の日付、null以外

説明で述べたように、タイムゾーンに基づいて現在の日付形式を返します。例としては 2024-07-10 ですが、形式は、国に割り当てられた ISO 8601 形式に応じてロケール時間に基づいて変更される可能性があります。 (例: 2024.07.10 または 24/7/10 になる可能性があります。これはあなたの国で使用される標準です)

LocalDate.now() メソッドは引数を取ることができます。これを使用するには、java.time.ZoneId.

をインポートします。
ゾーンIDとは何ですか?

Java 8SE でリリースされた ZoneId は次のように定義されています:

ZoneId は、Instant と LocalDateTime の間の変換に使用されるルールを識別するために使用されます。 ID には 2 つの異なるタイプがあります:

  • 固定オフセット - すべてのローカル日付/時間に同じオフセットを使用する、UTC/グリニッジからの完全に解決されたオフセット
  • 地理的領域 - UTC/グリニッジからのオフセットを見つけるための特定のルール セットが適用される領域

簡単に言えば、これにより、古い Date API で発生した国際化の問題が解決されます。 java.time.ZoneId をインポートした後、それが提供するメソッドのいくつかを確認できます。

  • ZoneId.getAvailableZoneIds() 利用可能なすべてのゾーンを表示します。例としては、Europe/Istanbul、America/Eirunepe、Etc/GMT-4、America/Miquelon (これらはそれぞれ一意であり、2 種類の一意の ID があることに注意してください)は上にリストされています)。
  • ZoneId.systemDefault() このメソッドは、「システムのデフォルトのタイムゾーンが変更されると、このメソッドの結果も変更されます」と定義されています。これは説明不要です。
  • ZoneId.of("") これを使用して、.getAvailableZoneIds() リストからカスタム セット ZoneId を定義します。ここで例として使用されている UTC とヨーロッパ/イスタンブールの両方を使用できることを覚えておいてください。
  • ZoneId.from() 前に話したテンポラルについて覚えていますか?ここでは引数として渡します。これが何をするのかよくわからない場合は、任意の日時情報のセットを表す ==TemporalAccessor を指定すると、ZoneId が取得されます。まだ少し知識がない場合は、java.time.ZoneId をインポートして ZonedDateTime.now() を使用すると、正確な時刻/日付が得られ、ZoneId に解析できます。基本的に ZoneId.from(ZonedDateTime.now())

Clock 引数も渡すことができますが、ZoneID だけを使用できる場合には使用する必要がありませんが、自由に調べてください

それが分かったので、パリの現在の日付を取得してみましょう!

LocalDate.now(ZoneId.of("Europe/Paris")) // 2024-07-10
ログイン後にコピー
LocalDate.of(年、月、日): >年、月、日から LocalDate のインスタンスを取得します。

LocalDate は日付を表すことに注意してください。この場合、その日付を任意の年、月、日に設定できます!

LocalDate.of YearDay(年, 年の日): >

多くの場合、1 年と 1 日しか持たないかもしれません。この関数はそれを年-月-日形式に変換します。以下に例を示します。 LocalDate.of YearDay(2023, 234) は 2023-08-22 になります。うるう年も考慮されます。

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 >#

以上がデートはきちんとしましょうの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!