Edited at

【令和】Microsoft の元号対応が迷走している件


はじめに

私は Delphi 使いです。なので、新元号対応は Win32 API に依存していることになります。

Delphi の FormatDateTime() / DateTimeToString() は元号レジストリを参照するので、レジストリに新しい元号が追加されれば新元号対応できる...はずでした。


事の始まり

4/10 の井之上@エンバカデロさんのツイートが発端でした。


試してみる (元号レジストリ)

4/10 よりも前かつ元号レジストリで令和を追加している場合、次のコードは 令和01年05月01日 を表示していました。

program EraTest;

{$APPTYPE CONSOLE}

uses
System.SysUtils;

var
s: string;
begin
DateTimeToString(s, 'ggee年mm月dd日', Encodedate(2019, 05, 01));
Writeln(s);
Readln;
end.

ところが...

4/10 のアップデートを適用すると元号レジストリを追加していても新元号が表示されなくなってしまいました。

システム日付を 2019/05/01 以降に変更すれば新元号が使えるようになります。つまり、2019/05/01 になるまで新元号が使えない事になります。

これはバグなんですかね?仕様なんですかね?

いずれにせよ一度リリースされてしまった以上、何らかの対策をするしかありません。


Windows は?

Windows 自体は未来の日付の和暦を扱えます。Windows 7 SP1 以降で新元号に対応します。

image.png

元号のレジストリキーは [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\Calendars\Japanese\Eras] です。ここに 令和 の値を書き込んでやれば新元号が使えるようになります。


SerNewEra.reg

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\Calendars\Japanese\Eras]
"2019 05 01"="令和_令_Reiwa_R"


2019/4/14 時点では、Windows Update を最新の状態にしてもこのレジストリエントリは追加されません。

追記: 2019/04/26

Windows 10 (1809) 以外に修正モジュールが公開されました。

Windows 8.1 以前用の修正モジュールはオプション扱いなので自動更新されませんが、Windows 10 は Windows Update の画面で[更新プログラムのチェック]ボタンを押すと更新されてしまいますので、ご注意ください。

Windows
モジュール
モジュール
(SO)

Windows 10 (1809)
KB4495667

Windows 10 (1803)
KB4493437

Windows 10 (1709)
KB4493440

Windows 10 (1703)
KB4493436

Windows 10 (1607)
Windows Server 2016
KB4493473

Windows 10 (RTM)
KB4498375

Windows 8.1
Windows Server 2012 R2
KB4493443
KB4496878

Windows Server 2012
KB4493462
KB4496877

Windows 7 SP1
Windows Server 2008 R2 SP1
KB4493453
KB4496880

Windows Server 2008 SP2
KB4493460
KB4496879

これらの修正モジュールをインストールすると元号レジストリに 令和 が追加されます。元年レジストリは更新されません。

image.png

日本語フォントに U+32FF の 令和 が追加されます。

追記: 2019/05/02

Windows 10 (1809) 用の修正モジュール KB4501835 が公開されました...が、Windows Update の [更新プログラムのチェック] で出てくるようになるまで時間が掛かるかもしれません。WSUS で管理されていない PC は "Microsoft Update カタログ" から修正モジュールをダウンロードしてインストールする必要があります。

image.png

追記: 2019/05/04

Windows 10 (1809) 用の修正モジュール KB4495667 が公開されました。Windows Update の [更新プログラムのチェック] でインストール可能です。KB4501835 をインストールしていてもインストールされます。


Win32 API は?

先述の通り、Windows Update により一部の Win32 API が 2019/05/01 になるまで元号レジストリを見なくなります。Delphi だと FormatDateTime() や DateTimeToString() が Win32 API を利用しています。

image.png

Microsoft の Visual C++ ももちろん影響を受けます。

image.png

image.png


OLE は?

あえて分けますが、Win32 API と OLE (Automation) の新元号対応状況は次のようになっています。

4/10 のアップデート前:

Win32 API
OLE

レジストリ
参照
参照しない

未来の和暦

×

4/10 のアップデート後:

Win32 API
OLE

レジストリ
参照
参照

未来の和暦
×

OLE は 4/10 のアップデート前まで元号レジストリを見ていなかったので 令和に対応できていませんでした。アップデート後は新元号と未来の日付の和暦を扱えるようになります。

Delphi だと VarToDateTime() が OLE を利用しています。Visual Basic 6.0 の和暦対応ルーチンの一部も OLE を利用していると思われます。


.NET は?

.NET (.NET Framework / .NET Core) は未来の日付の和暦を扱えます。サポートされているのは .NET Framework 3.5 以降です。

.NET Framework 3.5 は元号がハードコードされていましたが、Windows 7 以降であれば Windows Update を適用する事により、元号レジストリを参照するようになります。

image.png

image.png

VB6 の互換関数は元年問題が出そうですが...

image.png

image.png

※ VB6.Format() 関数は元年レジストリで元年 / 1年表記が切り替わります。


Office は?

Office は元号レジストリを参照し、未来の日付の和暦を扱えます。サポートされているのは Office 2010 以降です。

image.png

...でもちょっと待ってくださいよ。少なくとも 4/11 の時点ではこうアナウンスしてましたよね?

ちょっと前:

image.png


Windows 上で実行されている Office 製品は 2019 年 5 月 1 日に新元号が開始されるまで、新元号を表示しませんのでご注意ください。


どうして今は変わってるのです?

現状:

image.png


元号開始時に、お客様に可能な限り最適なエクスペリエンスをご体験いただけるよう、 5 月 1 日に新元号が開始される前に、一部の Office 製品で新元号が表示されるようになります。


※ VBA に関しては基本的に OLE 準拠だと思われます。


元年

元年の件でも Microsoft は文言の修正を行っています。

ちょっと前:

image.png


元年表記をデフォルトに変更 (1 年表記にも変更可能)


現状:

image.png


元年表記も選択できるよう変更



Windows

元年のレジストリは Windows 10 Insider Preview で元年デフォルト、それ以外の Windows 10 では 1年デフォルトになっているようです。つまり、次のリリースが 2019/05 と言われている新しいビルドでも元年のレジストリは元年デフォルトになると思われます。

元年のレジストリは [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\Calendars\Japanese] にある InitialEraYear です。


FirstYear.reg

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\Calendars\Japanese]
"InitialEraYear"="元年"


...ただ、Windows での元年の扱いは 2019/04/10 時点ではバラバラのようです。

image.png

image.png

「新元号への対応について」 の文言変更を信じるならば、新しいビルドでも 1809 同様、1年デフォルトになる事もあり得ると思います。

追記: 2019/06/06

5/22 に Windows 10 May 2019 Update (1903) が一般公開されました。

image.png

紆余曲折ありアップデートが降ってこない機種もあったようですが、6 月に入ってから順次アップデートが降ってくるようになったようです。

この 1903 へアップデートを行うと元年レジストリが元年に設定されます。


Win32 API

GetDateFormat() や GetDateFormatEx() は元年レジストリを参照するようです。


FirstEraYearTest.cpp

#include <iostream>

#include <windows.h>
#include <datetimeapi.h>
#include <winnls.h>

int main()
{
WCHAR Buffer[256];
SYSTEMTIME st;
std::wcout.imbue(std::locale("JPN_JPN"));

GetLocalTime(&st);

GetDateFormatW(GetThreadLocale(), NULL, &st, L"yyyy/MM/dd", Buffer, _countof(Buffer));
std::wcout << Buffer << std::endl;

st.wYear = 2019;
st.wMonth = 5;
st.wDay = 1;

GetDateFormatW(GetThreadLocale(), DATE_USE_ALT_CALENDAR, &st, L"ggy年M月d日", Buffer, _countof(Buffer));
std::wcout << Buffer << std::endl;
GetDateFormatW(GetThreadLocale(), DATE_USE_ALT_CALENDAR, &st, L"ggy'年'M月d日", Buffer, _countof(Buffer));
std::wcout << Buffer << std::endl;

GetDateFormatEx(LOCALE_NAME_USER_DEFAULT, DATE_USE_ALT_CALENDAR, &st, L"ggy年M月d日", Buffer, _countof(Buffer), NULL);
std::wcout << Buffer << std::endl;
GetDateFormatEx(LOCALE_NAME_USER_DEFAULT, DATE_USE_ALT_CALENDAR, &st, L"ggy'年'M月d日", Buffer, _countof(Buffer), NULL);
std::wcout << Buffer << std::endl;
}


image.png

のクォーテーション関係なしに元年表示するようです。また、2019/05/01 を待たずとも元年レジストリが元年になっていれば平成等は元年表示されます。テストは平成元年でやればよさそうですね。

image.png

元年レジストリを参照しない設定で元年表示対応させたければ力業となります。1年 とか 01年元年 に置換すれば OK です。

釈迦に説法だとは思いますが、日付書式文字列をパースしてから置換する必要があります。単純置換してはいけません。


OLE

OLE は元年レジストリを参照するようです。


.NET

.NET は Windows の元年レジストリを参照しません。

.NETFramework 4.52 以前は以下のレジストリを参照します。Switch.System.Globalization.FormatJapaneseFirstYearAsANumber の値が 1 だと1年表記になります。


FormatJapaneseFirstYearAsANumber_x86_x64.reg

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\AppContext]
"Switch.System.Globalization.FormatJapaneseFirstYearAsANumber"=dword:00000001



FormatJapaneseFirstYearAsANumber_x64_WOW64.reg

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\AppContext]
"Switch.System.Globalization.FormatJapaneseFirstYearAsANumber"=dword:00000001


.NET Framework 4.6 以降や .NET Core での元年対応 (1年表記) 方法はまた異なりますので、このレジストリは見なかった事にした方が混乱しなくていいかと思います。

また、.NET Framework は、KB4489192 がインストールされると元年の扱いが変わってしまうようです。


書式パターンに "年" の文字を囲む半角の引用符が含まれているかいないかに関係なく、1 年目の日付の書式が変更されている日本の元号の元年の文字を出力できます。


2019/04/14 時点では、まだ Windows Update に降ってきていませんが...KB4489192 がいきなりリリースされたら怖いですね。

なお、KB4489192 は Windows 10 (1809) 用のモジュールであり、他のバージョンでは対応モジュールが異なります

Windows 10
(1809)
 Windows 10
(1803)
Windows 8.1
Windows 7
SP1

.NET Franework
3.5
KB4489192
KB4489894
KB4488663
KB4488662

.NET Franework
4.5.2

KB4488667
KB4488669

.NET Franework
4.6 以降
KB4489192
KB4489894
KB4488665
KB4488666

「新元号への対応について」 の文言変更を信じるならば、これらのモジュールが Windows Update でリリースされない事もあり得ると思います。

追記: 2019/04/30

@CodeOne さんの記事を読みました。


Windows 10 Version 1803 に今回のパッチをあてたところ、シングルクォーテーションなしの書式 "y年" で「元年」と出力される変更も適用されていることが確認できました。


ぇ?

慌てて確認。検証コードは次の通り (対象フレームワーク: 4.5.2) で、これを EXE にし、4/26 の修正モジュールを適用した Windows 7 / 8.1 / 10 (1803) で実行してみました。

using System;

using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp2
{
class Program
{
static void Main(string[] args)
{
var CultureInfo = new System.Globalization.CultureInfo("ja-JP", false);
CultureInfo.DateTimeFormat.Calendar = new System.Globalization.JapaneseCalendar();

Console.WriteLine(System.DateTime.Now.ToString("yyyy/MM/dd"));

DateTime dt = new DateTime(2019, 5, 1);
Console.WriteLine(dt.ToString("ggy'年'M'月'd'日'", CultureInfo));
Console.WriteLine(dt.ToString("ggy年M月d日", CultureInfo));
Console.ReadKey();
}
}
}

まずは Windows 7 (SP)。シングルクォーテーションで括られていなければ 1年 表記でした。

image.png

次に Windows 8.1。こちらもシングルクォーテーションで括られていなければ 1年 表記でした。

image.png

そして Windows 10 (1803)。こちらはシングルクォーテーションに関係なく 元年 表記でした。

image.png

どういう事なの?.NET の挙動は .NET の修正モジュールで変更になるんじゃなかったの?

image.png

追記: 2019/05/02

Windows 10 (1809) 用の新元号対応モジュール KB4501835 の場合、シングルクォーテーションで括られていなければ 1年 表記でした。Windows 10 (1803) 用の新元号対応モジュール KB4493437 と挙動が違う...

image.png

またややこしい事に。

Windows 10
1809
Windows 10
1803
Windows 8.1
Windows 7

新元号対応
モジュール未適用
1年
1年
1年
1年

新元号対応
モジュール適用
1年
元年
1年
1年

追記: 2019/05/04

Windows 10 (1809) 用の新元号対応モジュール KB4495667 も、シングルクォーテーションで括られていなければ 1年 表記でした。

image.png

追記: 2019/06/06

どの段階何のモジュールか不明ですが (2019/05 のマンスリーロールアップ?)、Windows 10 (1809) や Windows 8.1, Windows 7 もシングルクォーテーションに関係なく 元年 表記されるようになりました。

image.png

Windows 10
1903
Windows 10
1809
Windows 10
1803
Windows 8.1
Windows 7

元年
元年
元年
元年
元年


Office

Excel や Access は元年レジストリを参照しないようです。Excel や Access は常に 1年 表示です。

勝手に 01 -> となる事はないのでトラブルは少ないと思いますが、元年表示対応は力業となります。


[種類] テキスト ボックスに以下の文字列をコピーして貼り付けます。

[<=43585][$-ja-JP]ggge"年"m"月"d"日";[>=43831]ggge"年"m"月"d"日";ggg"元年"m"月"d"日"


Microsoft の Excel での元年対応例は令和のみの対応なのでこのやり方は評価しません。もう少しマトモな手段を提示すべきです。

image.png

Access は VBA を使うでしょうから、テーブルでの和暦表示以外はどうとでもなると思います。

image.png

Word や Power Point の日付挿入 (日付と時刻) は元年レジストリを参照するようです。

image.png

image.png

Excel と Access が 1年 表記な理由ですが、

image.png


互換性の観点から Excel, Access などにおいて 2019 年 4 月時点では「1年」を使用している。


へ、へぇ~...。

※ VBA に関しては基本的に OLE 準拠だと思われます。


おわりに

つまり 2019/04/14 の時点ではこういう事になります。

Win32 API
OLE
.NET
Office

元号レジストリ
参照
参照
参照
参照

未来の和暦
×


元年レジストリ
参照
参照
参照しない
Excel や Access
は参照しない

Win32 API で、未来の和暦 (新元号) を使うのなら、2019/05/01 までは次のアップデータを適用しないようにするしかありません。

OS
KB

Windows 10
KB4493509

Windows 8.1
KB4493446

Windows 7
KB4493472

または Win32 API を使わずに独自実装するかです。

2019/05/01 を迎えれば殆どの問題は解決すると思われますが、検証するにも日本では GW 真っ只中なんですよね...。

追記: 2019/5/1, 5/2, 5/4

2019/05/01 を迎えましたので、Win32 API でもすべての API が元号レジストリを参照するようになりました。Windows Update を最新にした状態での時系列は次のようになります。

Win32 API
OLE
.NET
Office

2019/04/09 以前
参照
参照しない
参照
参照

2019/04/10 以降
(マンスリーロールアップ)
時限参照
参照
参照
参照

2019/04/26 以降
(元号レジストリ追加)1

時限参照
参照
参照
参照

2019/05/01 以降
(改元)
参照
参照
参照
参照

2019/05/02 以降
(元号レジストリ追加)2

参照
参照
参照
参照

2019/05/04 以降
(元号レジストリ追加)3

参照
参照
参照
参照


新元号を事前に使う事の是非

経済産業省の資料にはこうあります。


(3)元号法第1項に基づく政令の公布後の取扱い

元号法(昭和 54 年法律第 43 号)第1項に基づく政令の公布日から施行日前までの間において、各府省が作成し公にする文書に元号を用いて改元日以降の年を表示する場合は、「平成」を用いるものとする(注)。


しかしながら、これは官公庁の公文書の話であり、続けて次のような注意書きがあります。


(注)改元日以降に国民からの申請等又は各府省の通知等に用いられる様式の変更、改元に伴う情報システムの改修等、国民に混乱や不便を生じさせない観点から必要な場合、公布等を除き、「令和」を用いて準備のための手続を行うことができる。


つまり、官公庁であれ民間であれ新元号を用いた事前準備は OK なのです。


改元後の初年を元年と表記する意味

元年表記に法的な根拠はありません。あくまで慣習です。経済産業省の資料にはこうあります。


(2)予算

国の予算における会計年度の名称については、原則、改元日以降は、当年度全体を通じて「令和元年度」とし、これに伴い、当年度予算の名称は、各府省が改元日以降に作成する文書においては「令和元年度予算」と表示するものとする。


これは国の会計年度の話であり「改元後の和暦の初年に元年を使わなければならない」という根拠ではありません。

元年 の理屈で言えば、年の最初の日である 1 月 1 日は 元日 であるため、慣習と言うのなら "gggy'年'M'月'd'日'" に 2020/1/1 が渡されたら 令和 2 年元日 と表示しなくてはなりません。

書式指定が yyyy であっても yyy であっても yy であっても y であっても って表示されるというのはおかしな話で、やはりコンピュータの処理としては間違っている気がします。元年を使用するにしても画面表示や帳票出力に留めるべきで、やりとりするデータや入力項目で元年を使うべきではないでしょう。

Win32API の GetDateFormat() や .NET の ToString() は表示用だけでなくデータ生成にも使われているのですから、API やフレームワークの挙動を変更するのは悪手だと思います。Microsoft もその危険性を理解しているからこそ、Excel や Access では元年表記しないようにしているのだと思います。

...とはいえ「日付書式文字列に (という文字) を含めなければ必ず 1 年表記になる」のですから、解っていれば対処は難しくありません。


おまけ

2019/05/01 時点での対応表です。

image.png

<!>注意<!>

Windows 10 (1803) は、4/26 の令和対応モジュール KB4493437 または、.NET の修正モジュール KB4489894 (1809 の KB4489192 に相当) が適用されていると、日付書式文字列内の をシングルクォーテーションで括っていなくても 元年 表記となります。

1803 よりも前の Windows 10 では未確認です。





  1. 新元号対応モジュールがリリースされました。ただし Windows 10 (1809) を除きます。 



  2. Windows 10 (1809) 用の新元号対応モジュール KB4501835 がリリースされました。 



  3. Windows 10 (1809) 用の新元号対応モジュール KB4495667 がリリースされました。