Typically, calendar eras represent long time periods. In the Gregorian calendar, for example, the current era spans (as of this year) 2,018 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, 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.
.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.
Two calendar classes, JapaneseCalendar and JapaneseLunisolarCalendar, are affected by the introduction of a new Japanese era. These calendars use the same months and days of the month as the Gregorian calendar. They 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 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:
- Culture-specific date and time operations with cultures that support the JapaneseCalendar, when the JapaneseCalendar is the current calendar for the culture.
- Calls to standalone JapaneseCalendar and JapaneseLunisolarCalendar methods, such as GetDaysInYear, IsLeapYear, or ToDateTime.
- Formatting using the “g” or “gg” custom format specifier.
- Year formatting with the Japanese calendar classes, which will change to provide special formatting for the first year of an era. For more information, see The first year of an era later in this blog post.
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.
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:
yyyy mm dd Value:
Since the new era name has not been announced, you can use question marks as a placeholder. For the native full and abbreviated name, you can use the FULLWIDTH QUESTION MARK (U+FF1F), and for the English full and abbreviated name, you can use the QUESTION MARK (U+003F). For example:
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\Calendars\Japanese\Eras] "2019 05 01"="？？_？_??????_?"
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:
Note that the new era will begin on May 1, 2019, and the Japanese government is expected to announce the official name of the new era on about April 1, 2019. A window of approximately 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.
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 will be released in the near future.
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.An update to Windows will add the new era value to the registry once the era name and abbreviated era name are known. .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.
Updates will be released as soon as possible after the new era name is announced.
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:
- .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
- .NET Core: You can add the following to the .netcore.runtimeconfig.json config file:
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 will adopt this convention. However, parsing operations will successfully handle 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. As the output from the example illustrates, the .NET formatting routine converts year 1 to Gannen only if the year is followed by the 年 symbol.
The change in Japanese eras poses a number of issues. The following list addresses some of these and proposes workarounds.
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.
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).
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.
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.