GetDateFormat with Calendar in Win32 API

この記事は LL/ML Advent Calendar #LLAdventJP の 19 日目です.

ある日ケバブを食べにいったら登録されてしまいました.
世の中何を信じればいいのかわかりません.

Win32 での日付のフォーマット

Windows のネイティブ コードでも日付のフォーマットをしたいと思い作ってみました.

Win32 での日付のフォーマットの現状

Windows のネイティブ コードで日付のフォーマットを行う場合どんな方法があるかというと、

といった方法があります.

しかし,これらの方法はどれもカレンダーを指定できるような形になっていません.

ATL/MFC の CTime::Format は wcsftime や VarFormatDateTime を呼んでいます.C 言語の標準ライブラリの wcsftime は和暦に対応していませんし,最終的には NLS の GetDateFormat を使っています.では肝心の NLS の GetDateFormat / GetDateFormatEx はというとカレンダーの指定ではなく,ユーザーの設定に依存したフォーマットを行うようになっています.また GetCalendarDateFormatEx という期待通りのことをやってくれそうな関数が Vista で追加されていますが,すでに Deprecated です.

結局ロケールやカレンダーを指定した任意の日付のフォーマットはできないのが現状です。

コードとか

github に登録しました.まだ完成してません.

https://github.com/kei10in/GetDateFormatEx

実装

ポイントは,

  • GetCalendarInfoEx を使って各種翻訳の必要なリソースを取得する.
  • グレゴリオ暦以外の計算は自前でやる必要がある.

というところかなと思います.

GetCalendarInfoEx で各種リソースの取得

日付のフォーマットを実装しようと思って一番困るのはリソースかなと思います.アラビア語やタイ語なんて全くわかりません.

マイクロソフト ランゲージポータルで必要な翻訳を集める方法がないわけではないですがなかなかつらいと思います.

そんなときは GetCalendarInfo / GetCalendarInfoEx の出番です.この関数を使うとロケールとカレンダーに対応したカレンダーに関する情報を取得することができます.引数 CalType でどんな情報を取得するかを指定することができます.どんな情報があるかは Calendar Type Information にまとまっています.

例えば lpLocaleName に "ja-JP", Calendar に CAL_GREGORIAN, CalType に CAL_SERASTRING を指定した場合は "西暦" が返ってきます.CalType に CAL_JAPAN を指定すると "平成" が返ってきます."昭和"・"大正"・"明治" といった文字列も取得したい場合は EnumCalendarInfoExEx を使います.EnumCalendarInfoExEx でも GetCalendarInfoEx 同様,CAL_SERASTRING を指定します.

GetCalendarInfoEx は文字列をひとつだけ取得できましたが,EnumCalendarInfoExEx はひとつの Calendar Type Information で複数の文字列が得られる場合に使用する関数です.CAL_SERASTRING の他には CAL_IYEAROFFSETRANGE が複数の値を返します.

グレゴリオ暦以外の計算

日付のフォーマットをする場合グレゴリオ暦から和暦やヒジュラ暦へ変換する必要があります.

しかし,先ほどの GetCaldnerInfoEx, EnumCalendarInfoExEx を使って変換することができません.

例えば CAL_IYEAROFFSETRANGE で西暦に対する平成や昭和のオフセット値を得ることができますが,何月何日からかといった情報は GetCalendarInfoEx や EnumCalendarInfoEx では取得できません.また和暦のオフセットは西暦から減算するのですがタイの仏暦の場合は西暦に加算する必要があり,個別に実装する必要があります.ヒジュラ暦に関しては全く別な計算が必要です.

感想

ただ作るだけだろうと,軽い気持ちではじめてみたら結構つらかったです.

和暦の計算とかをやってくれる関数くらいあるだろー,とか思ってたら自分で実装する必要がありました.

Era Handling for the Japanese Calendar (Windows) にはレジストリに情報がある旨書いてありますが,Windows 7 以降の話です.XP サポートしないといけない間に元号変わったら大変なことになりまね.

他にも XP サポートのためには LocaleName ではなくて LCID を使わないといけないとか色々やらねばならぬことがあります.