C++ Builder / TDateTime > from/to[新しい元号]変換処理 > .NET Framework関連の処理でVarToDateTime()が正常動作しないので自前変換した


動作環境
C++ Builder XE4
Windows 7 pro (32bit)
.NET Framework: v4.5.1を有効化

VarToDateTimeの追加元号への対応について @ Delphi freeml

前準備

レジストリに新しい元号を登録する。
「宇宙_宇_Uchyu_U」とした。

v0.1 > エラー

code

FormatDateTime()とVarToDateTime()で実装。

Unit1.cpp
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    TDateTime startdt = VarToDateTime("2017/01/11 12:30:45");

    String strdt = FormatDateTime(L"ggee年mm月dd日", startdt);
    OutputDebugString(strdt.c_str());
    int nop1=1;

    TDateTime backdt = VarToDateTime(strdt);
    int nop2=1;

    OutputDebugString( DateTimeToStr(backdt).c_str() );
}
//---------------------------------------------------------------------------

実行

FormatDateTime()の部分ではレジストリの情報が使用されている。
VarToDateTime()の部分で以下のエラーとなった。

関連情報

https://social.msdn.microsoft.com/Forums/ja-JP/a93ec79d-69a5-4bb7-ae5d-a8aabfdcb9dd/systemglobalizationcultureinfo?forum=netfxgeneralja
を見ると

と説明されているとおりで、Windows 7以降でのネイティブアプリもしくは.NET 4.0を使用した場合にしか機能しません。手元でレジストリ設定して試してみましたが、Windows 10 + .NET 3.5ではやはり新しい元号は表示されませんでした。(Windows 10 + .NET 4以降では表示されました。)

C++ Builder XE4で実装したものは、.NET Frameworkとは関係ないのかと思っている。
そのため、上記のコメントのように設定したレジストリの文字列は使われていない(か正しく動作しない)のだろう。

v0.2 > 自前変換

Unit1.cpp
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include <DateUtils.hpp>
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------

static const TDate kDate_startNewEra = VarToDateTime("2016/01/01");


void __fastcall TForm1::Button1Click(TObject *Sender)
{
    TDateTime startdt = VarToDateTime("2017/01/11 12:30:45");

    String strdt = FormatDateTime(L"ggee年mm月dd日", startdt);
    OutputDebugString(strdt.c_str());

    TDateTime backdt;
    try {
        backdt = VarToDateTime(strdt);
    } catch (...) {
        // Not (.NET Framework 4 or native)
        String wrk = strdt.SubString(3, MAXINT); // 元号2文字を除去
        int startYear = kDate_startNewEra.FormatString(L"YYYY").ToInt();
        int addYear = startYear - 2000 - 1;
        backdt = VarToDateTime(wrk);
        backdt = IncYear(backdt, addYear);
    }

    OutputDebugString( DateTimeToStr(backdt).c_str() );
}
//---------------------------------------------------------------------------
結果
デバッグ出力: 宇宙02年01月11日 プロセス Project1.exe (3668)
デバッグ出力: 2017/01/11 プロセス Project1.exe (3668)

力技で変換できた。

もっと良い実装は他者にゆずる。