Handling a new era in the Japanese calendar in .NET

Ronald

April 2nd, 2019

Typically, calendar eras represent long time periods. In the Gregorian calendar, for example, the current era spans (as of this year) 2,019 years. In the Japanese calendar, however, a new era begins with the reign of a new emperor. On April 30, 2019, Emperor Akihito is expected to abdicate, which will bring to an end the Heisei era. On the following day, when his successor becomes emperor, the Reiwa era, a new era in the Japanese calendar, will begin. It is the first transition from one era to another in the history of .NET, and the first change of eras in the Japanese calendar since Emperor Akihito’s accession in January 1989. In this blog post, I’ll discuss how eras work in general in .NET, how you can determine whether your application is affected by the era change, and what you as a developer have to doto make sure your application handles the upcoming Japanese era changes successfully.

Calendars in .NET

.NET supports a number of calendar classes, all of which are derived from the base Calendar class. Calendars can be used in either of two ways in .NET. A supported calendar is a calendar that can be used by a specific culture and that defines the formatting of dates and times for that culture. One supported calendar is the default calendar of a particular culture; it is automatically used as that culture’s calendar for culture-aware operations. Standalone calendars are used apart from a specific culture by calling members of that Calendar class directly. All calendars can be used as standalone calendars. Not all calendars can be used as supported calendars, however.

Each CultureInfo object, which represents a particular culture, has a default calendar, defined by its Calendar property. The OptionalCalendars property defines the set of calendars supported by the culture. Any member of this collection can become the current calendar for the culture by assigning it to the CultureInfo.DateTimeFormat.Calendar property.

Each calendar has a minimum supported date and a maximum supported date. The calendar classes also support eras, which divide the overall time interval supported by the calendar into two or more more periods. Most .NET calendars support a single era. The DateTime constructors that create a date using a specific calendar assume that that dates belong to the current era. You can instantiate a date in an era other than the current era by calling an overload of the Calendar.ToDateTime method.

The JapaneseCalendar and JapaneseLunisolarCalendar classes

Two calendar classes, JapaneseCalendar and JapaneseLunisolarCalendar, are affected by the introduction of a new Japanese era. The JapaneseCalendar uses the same months and days of the month as the Gregorian calendar. The two Japanese calendars differ in how they calculate years; the reign of a new emperor marks the beginning of a new era, which begins with year 1.

The JapaneseCalendar and JapaneseLunisolarCalendar are currently the only two calendar classes in .NET that recognize more than one era. Neither is the default calendar of any culture. The JapaneseCalendar class is an optional calendar supported by the Japanese-Japan (ja-JP) culture and is used in some official and cultural contexts. The JapaneseLunisolarCalendar class is a standalone calendar; it cannot be the current calendar of any culture. That neither is the default calendar of the ja-JP culture minimizes the impact that results from the introduction of a new Japanese calendar era. The introduction of a new era in the Japanese calendar affects only:

Note that, with the exception of the “g” or “gg” custom format specifier, any unintended side effects from the change in Japanese eras occur only if you use a Japanese calendar class as a standalone calendar, or if you use the JapaneseCalendar as the current calendar of the ja-JP culture.

Testing era changes on Windows

The best way to determine whether your applications are affected by the new era is to test them in advance with the new era in place. You can do this immediately for .NET Framework 4.x apps and for .NET Core apps running on Windows systems. For .NET Core apps on other platforms, you’ll have to wait until the ICU globalization library is updated; see the Updating data sources section for more information.

For .NET Framework 4.x apps and for .NET Core apps on Windows systems, era information for the Japanese calendars is stored as a set of REG_SZ values in the HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\Calendars\Japanese\Eras key of the system registry. For example, the following figure shows the definition of the Heisei era in the Japanese calendar.

You can use the Registry Editor (regedit.exe) to add a definition for the new era. The name defines the era start date, and its value defines the native era name, native abbreviated era name, English era name, and English abbreviated era name, as follows:

Name: yyyy mm dd Value: <native-full>_<native-abbreviated>_<English-full>_<English-abbreviated>

Adding the new Reiwa era to the list of eras requires that you add the following named value to the Eras registry key:

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

Once the new era information is in place on any system running .NET, you can use code like the following to identify instances in which the current string representation of a date and time in a Japanese calendar will differ from its string representation after the introduction of the new era:

Only one month separates the beginning of the Reiwa era on May 1, 2019, and the Japanese government’s announcement of its official name on April 1, 2019. A window of one month leaves very little time to test, detect bugs, troubleshoot, and address bugs. It is important that applications be adequately tested well in advance of the beginning of the new era.

.NET changes to support the new era

To ensure that the transition to a new Japanese calendar era is as seamless as possible, the following changes will be introduced in .NET before the formal introduction of the new Japanese calendar era. These changes either have already been released will be released in the near future in Windows updates. For more information, see Summary of new Japanese Era updates for .NET Framework.

Updating data sources

Currently, the way in which calendar era information is stored differs across .NET implementations:

For .NET Framework 4.0 and later, as well as for .NET Core running on Windows, calendar era information is provided by the Windows operating system and retrieved from the system registry. Once the Windows registry is updated to include the new era information, .NET on Windows will automatically reflect this update.

For .NET Framework 3.5 on Windows, calendar era information is maintained as hard-coded data by the .NET Framework itself. An update to .NET Framework 3.5 will change its source for calendar data from private hard-coded data to the registry. Once this happens, .NET Framework 3.5 will automatically reflect the eras defined in the Windows registry.

For .NET Core on non-Windows platforms, calendar information is provided by International Components for Unicode (ICU), an open source globalization library. ICU libraries will be updated once the era name and abbreviated era name are known. Because they do not depend on ICU cultural data, applications that use the globalization invariant mode are not affected by this change.

Relaxed era range checks

In the past, date and time methods that depend on calendar eras threw an ArgumentOutOfRangeException when a date and time was outside the range of a specified era. The following example attempts to instantiate a date in the 65th year of the Showa era, which began on December 25, 1926 and ended on January 7, 1989. This date corresponds to January 9, 1990, which is outside the range of the Showa era in the JapaneseCalendar. As a result, an ArgumentOutOfRangeException results.

To accommodate the era change, .NET by default will use relaxed range enforcement rules. A date in a particular era can “overflow” into the following era, and no exception is thrown. The following example instantiates a date in the third quarter of year 31 of the Heisei era, which is more than two months after the Heisei era has ended.

If this behavior is undesirable, you can restore strict era range checks as follows:

.NET Framework 4.6 or later : You can set the following AppContextSwitchOverrides element switch:

: You can set the following AppContextSwitchOverrides element switch: .NET Framework 4.5.2 or earlier : You can set the following registry value: Key HKEY_LOCALMACHINE\SOFTWARE\Microsoft.NETFramework\AppContext Name Switch.System.Globalization.EnforceJapaneseEraYearRanges Type REG_SZ Value 1

: You can set the following registry value: .NET Core: You can add the following to the .netcore.runtimeconfig.json config file:

The first year of an era

Traditionally, the first year of a new Japanese calendar era is called Gannen (元年). For example, instead of Heisei 1, the first year of the Heisei era can be described as Heisei Gannen.

As part of its enhanced support for Japanese calendar eras, .NET by default adopts this convention in formatting operations. In parsing operations, .NET successfully handles strings that include “1” or “Gannen” as the year component.

The following example displays a date in the first year of the Heisei era. The output from the example illustrates the difference between the current and future handling of the first year of an era by .NET. When run after the servicing update is released, the .NET formatting routine converts year 1 to Gannen only if the custom date and time format string includes “y年” or “y’年'”, as the output from the example illustrates.

If this behavior is undesirable in formatting operations, you can restore the previous behavior, which always represents the year as “1” rather than “Gannen”, by doing the following:

.NET Framework 4.6 or later : You can set the following AppContextSwitchOverrides element switch:

: You can set the following AppContextSwitchOverrides element switch: .NET Framework 4.5.2 or earlier : You can set the following registry value: Key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\AppContext Name Switch.System.Globalization.FormatJapaneseFirstYearAsANumber Type REG_SZ Value 1

: You can set the following registry value: .NET Core: You can add the following to the .netcore.runtimeconfig.json config file:

Although there rarely should be a need to do this, you can also restore .NET’s previous behavior in parsing operations. This recognizes only “1” as the first year of an era, and does not recognize “Gannen”. You can do this as follows for both .NET Framework and .NET Core:

.NET Framework 4.6 or later : You can set the following AppContextSwitchOverrides element switch:

: You can set the following AppContextSwitchOverrides element switch: .NET Framework 4.5.2 or earlier : You can set the following registry value: Key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\AppContext Name Switch.System.Globalization.EnforceLegacyJapaneseDateParsing Type REG_SZ Value 1

: You can set the following registry value: .NET Core: You can add the following to the .netcore.runtimeconfig.json config file:

Handling Japanese calendar eras effectively

The change in Japanese eras poses a number of issues. The following list addresses some of these and proposes workarounds.

Specify an era when instantiating dates

You can instantiate a date using the date values of the Japanese calendar in any of three ways:

By calling a DateTime constructor that includes a parameter of type Calendar.

By calling a DateTimeOffset constructor that includes a parameter of type Calendar.

By calling the Calendar.ToDateTime method of a specific calendar type.

The .NET calendar classes include a CurrentEra property, which indicates the current (or default) era used in interpreting dates expressed in a specific calendar. Its value is the constant 0. It is an index into the Eras property, which orders eras in reverse chronological order. In other words, the most recent era is always the default era.

When eras can change unexpectedly, calling a date and time instantiation method that relies on the default era can produce an ambiguous date. In the next example, the call to the JapaneseCalendar.ToDateTime method that uses the default era returns different dates depending on whether or not the new era has been defined in the registry. Note that the output for this and the following example uses the sortable date/time pattern.

You can do either of two things to avoid potential ambiguity:

Call the Calendar.ToDateTime overload that specifies an era. This overload always produces an unambiguous date:

Instantiate dates in the Gregorian calendar. Use the Japanese calendar or the Japanese Lunisolar calendar only for the string representation of dates.

Use relaxed era range checks

A basic problem of calendars that can add new eras is that you can’t be certain that a future date will always belong to the current era. If strict range checking is enabled, future dates that are valid before an era change may become invalid after the era change. For this reason, leave relaxed era range checking on (the default value).

Use the era in formatting and parsing operations

Because dates can be ambiguous, you should always format a date value with its era. This is the default behavior of the standard date and time format strings. If you are using a custom date and time format string, be sure to include the “g” or “gg” custom format specifier. Conventionally, the era precedes the other date components in the string representation of a Japanese calendar date.

For parsing operations, also ensure that an era is present unless you want all dates and times to default to the current era.

A call to action

The introduction of a new era in the Japanese calendar poses challenges for any application that uses either the JapaneseCalendar or the JapaneseLunisolarCalendar. We’ve discussed how eras work with calendars and dates and times in .NET, how .NET applications will be updated to use the new era, how .NET APIs are changing to help you handle the Japanese era change, and what you can do as a developer to test your application and minimize the effect of future era changes. Above all, we recommend that you:

Determine whether your applications are affected by the Japanese era change. All applications that use the JapaneseCalendar and the JapaneseLunisolarCalendar classes may be affected.

Test your application to determine whether it can handle all dates, and particularly dates that exceed the range of the current Japanese calendar era.

Adopt the practices outlined in the Handling Japanese calendar eras effectively section to ensure that you can handle era changes effectively.

See also

The Japanese Calendar’s Y2K Moment Testing for New Japanese Era Japanese calendar Japanese era name List of Japanese era names Working with Calendars