最終更新日時: 2025年10月20日 15時55分32秒 (JST)
Raclamusi が更新

履歴 編集

class
<chrono>

# std::chrono::year_month_day(C++20)

    namespace std::chrono {
      class year_month_day;
    }

## 概要

`year_month_day`は、年、月、日を表すカレンダー表現のためクラスである。

このクラスは、年、および月に関する演算に対応している。ただし、日に関する演算はできない。

このクラスは等値比較および大小比較ができ、EqualityComparableおよびLessThanComparableの要件を満たす。

このクラスは、トリビアルコピー可能で、かつスタンダードレイアウト型である。

## メンバ関数

### 構築／コピー／破棄

名前 | 説明 | 対応バージョン
--- | --- | ---
`(constructor)` | コンストラクタ | C++20
`year_month_day& operator=(const year_month_day&) = default;` `year_month_day& operator=(year_month_day&&) = default;` | 代入演算子 | C++20

### 算術演算

名前 | 説明 | 対応バージョン
--- | --- | ---
`operator+=` | 加算の複合代入 | C++20
`operator-=` | 減算の複合代入 | C++20

### 観測

名前 | 説明 | 対応バージョン
--- | --- | ---
`year` | 年要素を取得する | C++20
`month` | 月要素を取得する | C++20
`day` | 日要素を取得する | C++20

### 変換

名前 | 説明 | 対応バージョン
--- | --- | ---
`operator sys_days` | システム時間の日付への型変換演算子 | C++20
`operator local_days` | ローカル時間の日付への型変換演算子 | C++20

### 検証

名前 | 説明 | 対応バージョン
--- | --- | ---
`ok` | 値が範囲に収まっているか判定する | C++20

## 非メンバ関数

### 算術演算

名前 | 説明 | 対応バージョン
--- | --- | ---
`operator+` | 加算 | C++20
`operator-` | 減算 | C++20

### 比較演算

名前 | 説明 | 対応バージョン
--- | --- | ---
`operator==` | 等値比較を行う | C++20
`bool operator!=(const year_month_day&, const year_month_day&) noexcept;` | 非等値比較を行う (`==`により使用可能) | C++20
`operator<=>` | 三方比較を行う | C++20
`bool operator<(const year_month_day&, const year_month_day&) noexcept;` | 左辺が右辺より小さいかを判定する (`<=>`により使用可能) | C++20
`bool operator<=(const year_month_day&, const year_month_day&) noexcept;` | 左辺が右辺以下を判定する (`<=>`により使用可能) | C++20
`bool operator>(const year_month_day&, const year_month_day&) noexcept;` | 左辺が右辺より大きいかを判定する (`<=>`により使用可能) | C++20
`bool operator>=(const year_month_day&, const year_month_day&) noexcept;` | 左辺が右辺以上を判定する (`<=>`により使用可能) | C++20

### 入出力

名前 | 説明 | 対応バージョン
--- | --- | ---
`operator<<` | 出力ストリームに出力する | C++20
`from_stream` | フォーマット指定して入力ストリームから入力する | C++20

## 文字列フォーマットサポート

名前 | 説明 | 対応バージョン
--- | --- | ---
`formatter` | `std::formatter`クラスの特殊化 | C++20

## ハッシュサポート

名前 | 説明 | 対応バージョン
--- | --- | ---
`template <class T> struct hash;` | `hash`クラスの先行宣言 | C++26
`template<> struct hash<chrono::year_month_day>;` | `hash`クラスの`year_month_day`に対する特殊化 | C++26

## 例

### 基本的な使い方 (C++20)

    #include <iostream>
    #include <chrono>

    namespace chrono = std::chrono;
    using namespace std::chrono_literals;

    int main()
    {
      // すべて2020年3月1日を表す
      chrono::year_month_day date1 = 2020y/3/1;
      chrono::year_month_day date2 = 2020y/chrono::March/1;
      chrono::year_month_day date3 = 2020y/chrono::March/1d;
      chrono::year_month_day date4 = 1d/chrono::March/2020;
      chrono::year_month_day date5 = 1d/3/2020;
      chrono::year_month_day date6 = chrono::March/1/2020;
      chrono::year_month_day date7 = 3/1d/2020;

      // 各カレンダー要素のコンストラクタはexplicitなので、
      // 指定順は年、月、日で決まっているが、int値は指定できない
      chrono::year_month_day date8{2020y, chrono::March, 1d};
      chrono::year_month_day date9{chrono::year{2020}, chrono::month{3}, chrono::day{1}};
      std::cout << date9 << std::endl;

      // 年、月、月の最終日の組み合わせから、年、月、日に変換。
      // 以下はすべて2020年2月29日を表す
      chrono::year_month_day date10 = 2020y/2/chrono::last;
      chrono::year_month_day date11 = 2/chrono::last/2020;
      chrono::year_month_day date12 = chrono::last/2/2020;
      std::cout << date12 << std::endl;

      // 日単位のシステム時間に変換
      chrono::sys_days sd{date9};
      std::cout << sd << std::endl;
      std::cout << sd.time_since_epoch().count() << std::endl; // 1970年1月1日からの経過日
      std::cout <<
        chrono::time_point_cast<chrono::seconds>(sd).time_since_epoch().count()
      << std::endl; // 1970年1月1日からの経過秒

      // 日単位のシステム時間に時・分を加算して、分まで扱えるシステム時間に変換。
      chrono::sys_time sm = chrono::sys_days{2020y/3/1} + 15h + 30min;
      std::cout << sm << std::endl;
    }

#### 出力例

    2020-03-01
    2020-02-29
    2020-03-01
    18322
    1583020800
    2020-03-01 15:30:00

### 前月の末日を求める (C++20)

    #include <cassert>
    #include <chrono>

    namespace chrono = std::chrono;
    using namespace std::chrono_literals;

    int main()
    {
      chrono::year_month_day base_date = 2020y/3/1;

      // year_month_dayオブジェクトに対して直接1日減算はできないので、
      // 前月の末日を表すyear_month_day_lastオブジェクトを作ってから、
      // year_month_dayオブジェクトに変換する
      chrono::year_month_day date{base_date.year()/(base_date.month() - chrono::months{1})/chrono::last};

      assert(date == 2020y/2/29);
    }

#### 出力

### UNIX時間からyear_month_dayオブジェクトに変換する (C++20)

    #include <iostream>
    #include <chrono>

    namespace chrono = std::chrono;

    chrono::year_month_day unix_time_to_ymd(std::time_t unixtime) {
      // システム時間の時間点に変換
      auto tp = chrono::system_clock::from_time_t(unixtime);

      // 時間点を日単位に変換
      chrono::sys_days sd = chrono::floor<chrono::days>(tp);

      // 日付に変換
      return chrono::year_month_day{sd};
    }

    int main()
    {
      // UNIX時間での現在日時を取得
      std::time_t now = std::time(nullptr);
      chrono::year_month_day date = unix_time_to_ymd(now);

      std::cout << date << std::endl;
    }

#### 出力例

    2019-12-20

### 生年月日から年齢を求める (C++20)

    #include <iostream>
    #include <chrono>
    #include <stdexcept>

    int calc_age(const std::chrono::year_month_day& date) {
      if (!date.ok()) {
        throw std::invalid_argument("invalid date");
      }

      namespace chrono = std::chrono;
      chrono::year_month_day now {chrono::floor<chrono::days>(chrono::system_clock::now())};
      int age = (now.year() - date.year()).count();
      if (now.month() < date.month()) {
        return age - 1;
      }
      else if (now.month() == date.month()) {
        if (now.day() < date.day()) {
          return age - 1;
        }
      }
      return age;
    }

    int calc_age(int year, int month, int day) {
      namespace chrono = std::chrono;
      return calc_age(chrono::year_month_day{
               chrono::year{year},
               chrono::month{static_cast<unsigned int>(month)},
               chrono::day{static_cast<unsigned int>(day)}});
    }

    int main()
    {
      using namespace std::chrono_literals;

      std::cout << calc_age(1985y/3/1) << std::endl;
      std::cout << calc_age(1954y/10/30) << std::endl; // 1970年未満も扱える
      std::cout << calc_age(2000, 2, 29) << std::endl; // うるう年
    }

#### 出力例

    34
    65
    19

2020年1月7日に実行した。

## バージョン

### 言語

- C++20

### 処理系

- Clang: 8.0 (入出力ストリームなし) ✅
- GCC: 9.2 ❌, 15.1 ✅
- Visual C++: 2019 Update 3 ❌

## 参照

- P2592R3 Hashing support for `std::chrono` value classes
  - C++26でハッシュサポートが追加された