ええ?イェーイ!

Nov 17, 2024 pm 02:51 PM

Java の日付パターンの「Y」文字と「y」文字の違いは何かご存知ですか?この記事では、間違った日付形式がどのようにエラーを引き起こす可能性があるかを見ていきます。また、突然のタイムトラベルからあなたを守る、Java 用の新しい V6122 診断ルールも紹介します。

YYYY? yyyy!

導入

大きな TODO ノートのほこりを払った後、特に興味深いケースを見つけました。この記事のコメント投稿者は、潜在的な問題を強調しました。

コメント
ところで、ここにアイデアがあります。Java の SimpleDateFormat は、新年のサプライズを演出できます。小文字で書かれた年は、大文字で書かれた年と同じではありません。 2021.12.27 ~ 2021.12.31 の日付の「YYYY」は 2022 年であり、一部の人が予想しているような 2021 年ではないため、今年の最後の週に突然自分が未来にいることに気づくかもしれません。

この問題の真相を見ていきましょう。

問題分析

日付の形式

SimpleDateFormat が何であるかを忘れてしまった場合は、ここで知識を磨き直すことができます。

日付を保存して表示するには、日付が特定のパターンに従う必要があることがよくあります。 SimpleDateFormat は、指定されたパターンに従って日付を簡単にフォーマットできるようにするクラスです。 SimpleDateFormat は、書式設定に加えて、文字列を解析して日付オブジェクトに変換することもできます。

Java が提供できるのはそれだけですか? SimpleDateFormat に加えて、DateTimeFormatter クラスも日付をフォーマットできます。

これら 2 つのクラスの使用例を示します。

SimpleDateFormat で日付をフォーマットする場合:

public static void main(String[] args) {
    Date date = new Date("2024/12/31");
    var dateFormatter = new SimpleDateFormat("dd-MM-yyyy");
    System.out.println(dateFormatter.format(date));
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

コンソールには次の内容が表示されます:

2024 年 12 月 31 日

ここで何が起こったのですか?

日付があり、それを特定の形式で保存/表示したいと考えています。これを実現するには、パターン文字列をコンストラクターに渡して SimpleDateFormat オブジェクトを作成します。日付はこのパターンに従って正確にフォーマットされます。 format メソッドは、フォーマットされた日付の文字列表現を返します。これはまさに私たちが望んでいたものです。

これも同じですが、DateTimeFormatter:
を使用します。

public static void main(String[] args) {
    LocalDate date = LocalDate.of(2024, 12, 31);
    var formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy");
    System.out.println(formatter.format(date));
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

コンソールには次の内容が表示されます:

2024 年 12 月 31 日

同じ手順と結果ですが、わずかな違いがあります。DateTimeFormatter を使用すると、TemporalAccessor インターフェイスを実装するクラスによって表される日付のみをフォーマットできます。たとえば、LocalDateLocalDateTime が含まれます。 SimpleDateFormat は、Date クラスのオブジェクトのみをフォーマットします。

コメントに戻りましょう。日付パターンで「y」の代わりに「Y」を使用すると、結果は本当に変わりますか?

コードを見てみましょう:

public static void main(String[] args) {
    Date date = new Date("2024/12/31");
    var dateFormatter = new SimpleDateFormat("dd-MM-yyyy");
    System.out.println(dateFormatter.format(date));
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

コンソールには次の内容が表示されます:

2025 年 12 月 31 日

おっと。 DateTimeFormatter に関しても同じですか?

コードは次のとおりです:

public static void main(String[] args) {
    LocalDate date = LocalDate.of(2024, 12, 31);
    var formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy");
    System.out.println(formatter.format(date));
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

コンソールには次の内容が表示されます:

2025 年 12 月 31 日

私たちは一年後の未来に旅行しました。何が起こっているかを見る時が来ました。

問題の本質

私の最初のステップは、SimpleDateFormat クラスのドキュメントを調べることでした。以下は、日付パターンが関心のあるアルファベット文字をどのように解釈するかを説明する表の一部です。

Letter Date or Time Component Presentation Examples
y Year Year 1996; 96
Y Week year Year 2009; 09

一年で一週間?説明しましょう。

週年は、その年の週番号に基づく年です。それは何を意味し、なぜ重要ですか?

特定のタスクでは、その年の週のシーケンス番号が重要です。週のシーケンス番号を決定するには、どの週を最初に考慮するかを決定する必要があります。これは、ある年から別の年への移行では、多くの場合、両方の年にまたがる数週間が生じるためです。では、今週が何年に属するかをどうやって判断できるのでしょうか? ISO-8601 標準はこれを規制しています。

この基準によれば、年の最初の週は次の条件を満たさなければなりません:

  • 週の最初の日は月曜日です;
  • 1 年の 1 週間の最小日数は 4 日です。

これから、簡単なルールを導き出すことができます。木曜日が 1 月に該当する場合、その週はその年の最初とみなされます。

実際の例でこれをさらに明確にできます。

例から、2024 年 12 月 31 日という日付を取り上げてみましょう。以下は、日付 (2024 年 12 月から 2025 年 1 月) を含む週のカレンダーの抜粋です:

Mo Tu We Th Fr Sa Su
30 31 1 2 3 4 5

今週は上記の条件を満たすため (1 月が 5 日ある)、2025 年の最初の週とみなされます。したがって、「Y」指定子を使用すると、2025 年が取得されます。

ご想像のとおり、DateTimeFormatter の場合もまったく同じです。

私たちは未来だけでなく過去にも旅行できることに注意することが重要です。

別の日付、2027 年 1 月 1 日を考えてみましょう。

2027 年の第 1 週には 1 月 1 日が含まれますか?もう一度、カレンダーを見てみましょう。

以下は、日付 (2026 年 12 月から 2027 年 1 月) を含む週のカレンダーの抜粋です。

Mo Tu We Th Fr Sa Su
28 29 30 31 1 2 3

今週は 1 月の日が 3 日しかないため (要件によると最初の週は 4 日になるはずです)、2026 年の最後の週としてカウントされます。つまり、「Y」を使用してフォーマットされた日付です。キャラクターは、2026 年を見せてくれます。

これが証拠です。コードを見てください:

public static void main(String[] args) {
    Date date = new Date("2024/12/31");
    var dateFormatter = new SimpleDateFormat("dd-MM-yyyy");
    System.out.println(dateFormatter.format(date));
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

コンソールには次の内容が表示されます:

2026 年 1 月 1 日

さて、問題を詳しく分析しました。また、PVS-Studio Java アナライザーに専用の診断ルールを追加するのは非常に興味深いことであることがわかりました。

実際のプロジェクトでのエラー

診断ルールが記述されたので、それをテストします。

アナライザーの開発中、テスト段階の 1 つに回帰テストの実行が含まれます。このプロセスに関する記事があります。つまり、新しい診断ルールを追加すると、オープンソース プロジェクトの大規模なプールが分析され、新しいレポートと参照レポートが比較されます。

この診断ルールの場合、アナライザーはいくつかのプロジェクトに対して新しい警告を発行しました。それらを見てみましょう。

弾む城

このプロジェクトでは、診断ルールが指すコード フラグメントは同一であるため、そのうちの 1 つだけを示します。

コードを見てみましょう:

public static void main(String[] args) {
    LocalDate date = LocalDate.of(2024, 12, 31);
    var formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy");
    System.out.println(formatter.format(date));
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

PVS-Studio の警告:

V6122 'Y' (週年) パターンの使用が検出されました: おそらく 'y' (年) を使用することが意図されていました。 SkeinParameters.java 246

まず、GitHub を見てみました。それが本当にバグで、開発者がすでにそれを発見して修正をコミットしていたとしたらどうなるでしょうか?まさにそれが起こったのです。ここにコミットへのリンクがありますので、確認してください。パターン内のすべての「Y」(週年) 文字は「y」(年) に置き換えられました。

なぜコミットが比較的昔に行われたのか不思議に思うかもしれません。説明しましょう。私たちの回帰テストは、特定のオープンソース プロジェクトの品質を継続的に管理することを目的としたものではありません。タスクは、新しい診断ルールが追加されたときにレポートがどのように変化するかを確認することです。アナライザーに問題があることを示すため、古い警告が消えたり、新しいエラーが表示されたりすることはありません。したがって、チェックされたコードは同じである必要があります。

オープングロク

次に、診断ルールがトリガーされた 2 番目のプロジェクトを見てみましょう。

PVS-Studio の警告:

V6122 'Y' (週年) パターンの使用が検出されました: おそらく 'y' (年) を使用することが意図されていました。リポジトリ情報.java 77

コード:

public static void main(String[] args) {
    Date date = new Date("2024/12/31");
    var dateFormatter = new SimpleDateFormat("dd-MM-YYYY");
    System.out.println(dateFormatter.format(date));
}
ログイン後にコピー

前のプロジェクトと同様に、何が起こっているのかを確認するために急いでコミットにアクセスしました。まず、リファクタリングの結果、フィールドが派生クラス Repository に移動したことは注目に値します (コミットへのリンクはここにあります)。さらに検索すると、修正を含むコミットが見つかりました。日付パターンの「Y」文字は「y」に置き換えられました:

public static void main(String[] args) {
    LocalDate date = LocalDate.of(2024, 12, 31);
    var formatter = DateTimeFormatter.ofPattern("dd-MM-YYYY");
    System.out.println(formatter.format(date));
}
ログイン後にコピー

つまり、ここでもエラーでした。

結論

PVS-Studio では、コミュニティからのフィードバックを歓迎します。 Habr ユーザーからのコメントに対処した後、いくつかの有用な診断ルールを追加して Java アナライザーを強化しました。共有したいご意見がございましたら、この記事のコメント欄でお待ちしております。

ところで、診断ルールは 10 月の 7.33 リリースで導入されました。したがって、当社のアナライザーを試してみたい場合は、このリンクを使用してください。

それだけです。ここで話を終わらせましょう。一年前(または逆)の突然の旅行に驚かないことを願っています。

以上がええ?イェーイ!の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

会社のセキュリティソフトウェアはアプリケーションの実行に失敗していますか?それをトラブルシューティングと解決する方法は? 会社のセキュリティソフトウェアはアプリケーションの実行に失敗していますか?それをトラブルシューティングと解決する方法は? Apr 19, 2025 pm 04:51 PM

一部のアプリケーションが適切に機能しないようにする会社のセキュリティソフトウェアのトラブルシューティングとソリューション。多くの企業は、内部ネットワークセキュリティを確保するためにセキュリティソフトウェアを展開します。 ...

MapsTructを使用したシステムドッキングのフィールドマッピングの問題を簡素化する方法は? MapsTructを使用したシステムドッキングのフィールドマッピングの問題を簡素化する方法は? Apr 19, 2025 pm 06:21 PM

システムドッキングでのフィールドマッピング処理は、システムドッキングを実行する際に難しい問題に遭遇することがよくあります。システムのインターフェイスフィールドを効果的にマッピングする方法A ...

エンティティクラス変数名をエレガントに取得して、データベースクエリ条件を構築する方法は? エンティティクラス変数名をエレガントに取得して、データベースクエリ条件を構築する方法は? Apr 19, 2025 pm 11:42 PM

データベース操作にMyBatis-Plusまたはその他のORMフレームワークを使用する場合、エンティティクラスの属性名に基づいてクエリ条件を構築する必要があることがよくあります。あなたが毎回手動で...

名前を数値に変換してソートを実装し、グループの一貫性を維持するにはどうすればよいですか? 名前を数値に変換してソートを実装し、グループの一貫性を維持するにはどうすればよいですか? Apr 19, 2025 pm 11:30 PM

多くのアプリケーションシナリオでソートを実装するために名前を数値に変換するソリューションでは、ユーザーはグループ、特に1つでソートする必要がある場合があります...

Intellijのアイデアは、ログを出力せずにSpring Bootプロジェクトのポート番号をどのように識別しますか? Intellijのアイデアは、ログを出力せずにSpring Bootプロジェクトのポート番号をどのように識別しますか? Apr 19, 2025 pm 11:45 PM

intellijideaultimatiateバージョンを使用してスプリングを開始します...

Javaオブジェクトを配列に安全に変換する方法は? Javaオブジェクトを配列に安全に変換する方法は? Apr 19, 2025 pm 11:33 PM

Javaオブジェクトと配列の変換:リスクの詳細な議論と鋳造タイプ変換の正しい方法多くのJava初心者は、オブジェクトのアレイへの変換に遭遇します...

eコマースプラットフォームSKUおよびSPUデータベースデザイン:ユーザー定義の属性と原因のない製品の両方を考慮する方法は? eコマースプラットフォームSKUおよびSPUデータベースデザイン:ユーザー定義の属性と原因のない製品の両方を考慮する方法は? Apr 19, 2025 pm 11:27 PM

eコマースプラットフォーム上のSKUおよびSPUテーブルの設計の詳細な説明この記事では、eコマースプラットフォームでのSKUとSPUのデータベース設計の問題、特にユーザー定義の販売を扱う方法について説明します。

データベースクエリにTKMYBATISを使用するときに、エンティティクラスの変数名の構築クエリ条件をエレガントに取得する方法は? データベースクエリにTKMYBATISを使用するときに、エンティティクラスの変数名の構築クエリ条件をエレガントに取得する方法は? Apr 19, 2025 pm 09:51 PM

データベースクエリにTKMYBATISを使用する場合、クエリ条件を構築するためにエンティティクラスの変数名を優雅に取得する方法は一般的な問題です。この記事はピン留めします...

See all articles