Skip to content

Commit

Permalink
Fix Japanese Abbreviated Era Names (dotnet#40300)
Browse files Browse the repository at this point in the history
  • Loading branch information
tarekgh authored and Jacksondr5 committed Aug 10, 2020
1 parent c4e8692 commit e16d180
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -187,5 +187,27 @@ public void TestFirstYearOfJapaneseEra()
$"Parsing '{formattedDateWithGannen}' result should match if '{formattedDate}' has Gan-nen symbol"
);
}

[Fact]
public void JapaneseAbbreviatedEnglishEraNamesTest()
{
string [] eraNames = { "M", "T", "S", "H", "R" };

var ci = new CultureInfo("ja-JP") { DateTimeFormat = { Calendar = new JapaneseCalendar() }};

int eraNumber = ci.DateTimeFormat.GetEra("Q");
if (eraNumber == 4 || eraNumber == 5)
{
// Skip the test on Windows versions which have wrong Japanese Era information.
// Windows at some point used "Q" as fake era name before getting the official name.
return;
}

int numberOfErasToTest = Math.Min(eraNames.Length, ci.DateTimeFormat.Calendar.Eras.Length);
for (int i = 0; i < numberOfErasToTest; i++)
{
Assert.Equal(i + 1, ci.DateTimeFormat.GetEra(eraNames[i]));
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public class GregorianCalendar : Calendar
public override CalendarAlgorithmType AlgorithmType => CalendarAlgorithmType.SolarCalendar;

/// <summary>
/// Internal method to provide a default intance of GregorianCalendar.
/// Internal method to provide a default instance of GregorianCalendar.
/// Used by NLS+ implementation
/// </summary>
internal static Calendar GetDefaultInstance() => s_defaultInstance ??= new GregorianCalendar();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ namespace System.Globalization
{
public partial class JapaneseCalendar : Calendar
{
private static readonly string [] s_abbreviatedEnglishEraNames = { "M", "T", "S", "H", "R" };

private static EraInfo[]? IcuGetJapaneseEras()
{
if (GlobalizationMode.Invariant)
Expand All @@ -23,16 +25,11 @@ public partial class JapaneseCalendar : Calendar
return null;
}

string[]? abbrevEnglishEraNames;
if (!CalendarData.EnumCalendarInfo("en", CalendarId.JAPAN, CalendarDataType.AbbrevEraNames, out abbrevEnglishEraNames))
{
return null;
}

List<EraInfo> eras = new List<EraInfo>();
int lastMaxYear = GregorianCalendar.MaxYear;

int latestEra = Interop.Globalization.GetLatestJapaneseEra();

for (int i = latestEra; i >= 0; i--)
{
DateTime dt;
Expand All @@ -47,16 +44,40 @@ public partial class JapaneseCalendar : Calendar
break;
}

eras.Add(new EraInfo(i, dt.Year, dt.Month, dt.Day, dt.Year - 1, 1, lastMaxYear - dt.Year + 1,
eraNames![i], GetAbbreviatedEraName(eraNames, i), abbrevEnglishEraNames![i]));
eras.Add(new EraInfo(i, dt.Year, dt.Month, dt.Day, dt.Year - 1, 1, lastMaxYear - dt.Year + 1, eraNames![i], GetAbbreviatedEraName(eraNames, i), ""));

lastMaxYear = dt.Year;
}

string[] abbrevEnglishEraNames;
if (!CalendarData.EnumCalendarInfo("ja", CalendarId.JAPAN, CalendarDataType.AbbrevEraNames, out abbrevEnglishEraNames!))
{
// Failed to get English names. fallback to hardcoded data.
abbrevEnglishEraNames = s_abbreviatedEnglishEraNames;
}

// Check if we are getting the English Name at the end of the returned list.
// ICU usually return long list including all Era names written in Japanese characters except the recent eras which actually we support will be returned in English.
// We have the following check as older ICU versions doesn't carry the English names (e.g. ICU version 50).
if (abbrevEnglishEraNames[abbrevEnglishEraNames.Length - 1].Length == 0 || abbrevEnglishEraNames[abbrevEnglishEraNames.Length - 1][0] > '\u007F')
{
// Couldn't get English names.
abbrevEnglishEraNames = s_abbreviatedEnglishEraNames;
}

int startIndex = abbrevEnglishEraNames == s_abbreviatedEnglishEraNames ? eras.Count - 1 : abbrevEnglishEraNames.Length - 1;

Debug.Assert(abbrevEnglishEraNames == s_abbreviatedEnglishEraNames || eras.Count <= abbrevEnglishEraNames.Length);

// remap the Era numbers, now that we know how many there will be
for (int i = 0; i < eras.Count; i++)
{
eras[i].era = eras.Count - i;
if (startIndex < abbrevEnglishEraNames.Length)
{
eras[i].englishEraName = abbrevEnglishEraNames[startIndex];
}
startIndex--;
}

return eras.ToArray();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@ namespace System.Globalization
{
/// <summary>
/// JapaneseCalendar is based on Gregorian calendar. The month and day values are the same as
/// Gregorian calendar. However, the year value is an offset to the Gregorian
/// Gregorian calendar. However, the year value is an offset to the Gregorian
/// year based on the era.
///
/// This system is adopted by Emperor Meiji in 1868. The year value is counted based on the reign of an emperor,
/// and the era begins on the day an emperor ascends the throne and continues until his death.
/// The era changes at 12:00AM.
///
/// For example, the current era is Reiwa. It started on 2019/5/1 A.D. Therefore, Gregorian year 2019 is also Reiwa 1st.
/// For example, the current era is Reiwa. It started on 2019/5/1 A.D. Therefore, Gregorian year 2019 is also Reiwa 1st.
/// 2019/5/1 A.D. is also Reiwa 1st 5/1.
///
/// Any date in the year during which era is changed can be reckoned in either era. For example,
/// Any date in the year during which era is changed can be reckoned in either era. For example,
/// 2019/1/1 can be 1/1 Reiwa 1st year or 1/1 Heisei 31st year.
///
/// Note:
Expand Down Expand Up @@ -50,7 +50,7 @@ public partial class JapaneseCalendar : Calendar
//
// We know about 4 built-in eras, however users may add additional era(s) from the
// registry, by adding values to HKLM\SYSTEM\CurrentControlSet\Control\Nls\Calendars\Japanese\Eras
// we don't read the registry and instead we call WinRT to get the needed informatio
// we don't read the registry and instead we call WinRT to get the needed information
//
// Registry values look like:
// yyyy.mm.dd=era_abbrev_english_englishabbrev
Expand Down

0 comments on commit e16d180

Please sign in to comment.