Open12

std::chronoのformatについて

koilekoile

2024年9月21日現在のcpprefjpのstd::chronoのformatについての記述においてこのように書かれている

%EC では "令和" (元号)

しかし、VS2022(Version 17.11.2)において以下の出力は「20」で2024を100で割った値になっている。

        std::locale loc{ "ja_JP" };
        std::cout << std::format(loc, "{:L%EC}\n", now); // 20
koilekoile

cppreferenceでの記述

The modified command %EC writes the locale's alternative representation of the century.

もちろん和暦に関して書いているわけもなく・・・

koilekoile

たぶんこれがドラフトの文章?
https://eel.is/c++draft/time.format
cpprefjpの文章はここを素直に翻訳したように見える。
「例」の列が独自で足されていて、そこがVS2022の出力結果と乖離している。

というか%ECが「representation of the century」というのであれば英語ロケールだと20じゃなくて21を返すべきじゃない?

koilekoile

%ECが英語ロケールだと「21(世紀)」で(理想の)日本語ロケールだと「令和6年」になるの、粒度がかみ合ってないけどいいのか?

Akira TakahashiAkira Takahashi

GCC, Clang, MSVCでstrftimeの動作確認を改めてやったら20と出力されました。。。私が書きましたが「令和」は出所不明ですね…

koilekoile

ページの処理系の確認が全て❌️になっていたので動作確認していないものかと思っていました。
各ロケールで何が出力されるべきなのか分からないので難しいですね…

koilekoile

https://gcc.gnu.org/onlinedocs/gcc-13.1.0/libstdc++/api/a00611_source.html
GCCの実装コメントにeraと書かれてる!

// %EC Locale's alternative preresentation of the century (era name).

それなら令和と書かれていてもおかしくない

          if (__mod == 'E')
            {
              // TODO: %EC, %Ey or %EY
              // return __out;
            }

って%ECとかがTODOにされとる!
GCCだとEがつかない表記と同じ表示になっているのかな。
世界の誰もこのあたりの紀年法表記について気にしてない説。

koilekoile

https://gcc.gnu.org/onlinedocs/gcc-14.2.0/libstdc++/api/a00527_source.html
現状の最新GCCバージョン(gcc-14.2.0)っぽいURLに移動するとTODOの文字が消えていた。
こんな紀年法表記を気にしている人がいたのね。

          if (__mod) [[unlikely]]
            {
              struct tm __tm{};
              __tm.tm_year = (int)__y - 1900;
              return _M_locale_fmt(std::move(__out), _M_locale(__ctx), __tm,
                                   __conv, __mod);
            }
// ...
      // Use the formatting locale's std::time_put facet to produce
      // a locale-specific representation.
      template<typename _Iter>
        _Iter
        _M_locale_fmt(_Iter __out, const locale& __loc, const struct tm& __tm,
                      char __fmt, char __mod) const
        {
          basic_ostringstream<_CharT> __os;
          const auto& __tp = use_facet<time_put<_CharT>>(__loc);
          __tp.put(__os, __os, _S_space, &__tm, __fmt, __mod);
          if (__os)
            __out = __format::__write(std::move(__out), __os.view());
          return __out;
        }
  • (std::)use_facetってなに?
    • 各種言語でどう表すかを統一的にまとめたもの?
    • 日付にかかわらず数字やお金などのカテゴリがありそう
      • 例えばtolower()のロケール版はstd::use_facet<std::ctype<charT>>(loc).tolower(c)を返すらしい
koilekoile

話を最初に戻すと%ECはVS2022では未実装の可能性があるので何とも言えない。(英語ロケールでは21を返すべきではないかという気はするが)

ただ、cpprefjpの%Cでは「100で切り下げ除算した年 (世紀)」として例が「21」と表記されているが%C 自体は世紀を表すものではなく、単に100の切り下げ除算なので「20」と表記するのが正しそう。

koilekoile

自分の解釈があっているか不安だったのでC++20 ライブラリ機能 1%Cについて確認してみたら「100 で切り上げた年(2 桁の世紀)」で出力例が「20」で???となった。
ここは切り捨てのような気がするし、切り上げなら出力例は「21」になるはず。