diff options
Diffstat (limited to 'src/System.Private.CoreLib/shared/System/Globalization/GregorianCalendarHelper.cs')
-rw-r--r-- | src/System.Private.CoreLib/shared/System/Globalization/GregorianCalendarHelper.cs | 129 |
1 files changed, 78 insertions, 51 deletions
diff --git a/src/System.Private.CoreLib/shared/System/Globalization/GregorianCalendarHelper.cs b/src/System.Private.CoreLib/shared/System/Globalization/GregorianCalendarHelper.cs index 2842bd3a1..34206b380 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/GregorianCalendarHelper.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/GregorianCalendarHelper.cs @@ -19,9 +19,9 @@ namespace System.Globalization // be affected by the DateTime.MinValue; internal int maxEraYear; // Max year value in this era. (== the year length of the era + 1) - internal String eraName; // The era name - internal String abbrevEraName; // Abbreviated Era Name - internal String englishEraName; // English era name + internal string eraName; // The era name + internal string abbrevEraName; // Abbreviated Era Name + internal string englishEraName; // English era name internal EraInfo(int era, int startYear, int startMonth, int startDay, int yearOffset, int minEraYear, int maxEraYear) { @@ -33,7 +33,7 @@ namespace System.Globalization } internal EraInfo(int era, int startYear, int startMonth, int startDay, int yearOffset, int minEraYear, int maxEraYear, - String eraName, String abbrevEraName, String englishEraName) + string eraName, string abbrevEraName, string englishEraName) { this.era = era; this.yearOffset = yearOffset; @@ -47,8 +47,8 @@ namespace System.Globalization } // This calendar recognizes two era values: - // 0 CurrentEra (AD) - // 1 BeforeCurrentEra (BC) + // 0 CurrentEra (AD) + // 1 BeforeCurrentEra (BC) internal class GregorianCalendarHelper { // 1 tick = 100ns = 10E-7 second @@ -87,7 +87,7 @@ namespace System.Globalization // // This is the max Gregorian year can be represented by DateTime class. The limitation // is derived from DateTime class. - // + // internal int MaxYear { get @@ -123,22 +123,19 @@ namespace System.Globalization m_minYear = m_EraInfo[0].minEraYear; ; } - /*=================================GetGregorianYear========================== - **Action: Get the Gregorian year value for the specified year in an era. - **Returns: The Gregorian year value. - **Arguments: - ** year the year value in Japanese calendar - ** era the Japanese emperor era value. - **Exceptions: - ** ArgumentOutOfRangeException if year value is invalid or era value is invalid. - ============================================================================*/ - - internal int GetGregorianYear(int year, int era) + // EraInfo.yearOffset: The offset to Gregorian year when the era starts. Gregorian Year = Era Year + yearOffset + // Era Year = Gregorian Year - yearOffset + // EraInfo.minEraYear: Min year value in this era. Generally, this value is 1, but this may be affected by the DateTime.MinValue; + // EraInfo.maxEraYear: Max year value in this era. (== the year length of the era + 1) + private int GetYearOffset(int year, int era, bool throwOnError) { if (year < 0) { - throw new ArgumentOutOfRangeException(nameof(year), - SR.ArgumentOutOfRange_NeedNonNegNum); + if (throwOnError) + { + throw new ArgumentOutOfRangeException(nameof(year), SR.ArgumentOutOfRange_NeedNonNegNum); + } + return -1; } if (era == Calendar.CurrentEra) @@ -150,48 +147,78 @@ namespace System.Globalization { if (era == m_EraInfo[i].era) { - if (year < m_EraInfo[i].minEraYear || year > m_EraInfo[i].maxEraYear) + if (year >= m_EraInfo[i].minEraYear) + { + if (year <= m_EraInfo[i].maxEraYear) + { + return m_EraInfo[i].yearOffset; + } + else if (!AppContextSwitches.EnforceJapaneseEraYearRanges) + { + // If we got the year number exceeding the era max year number, this still possible be valid as the date can be created before + // introducing new eras after the era we are checking. we'll loop on the eras after the era we have and ensure the year + // can exist in one of these eras. otherwise, we'll throw. + // Note, we always return the offset associated with the requested era. + // + // Here is some example: + // if we are getting the era number 4 (Heisei) and getting the year number 32. if the era 4 has year range from 1 to 31 + // then year 32 exceeded the range of era 4 and we'll try to find out if the years difference (32 - 31 = 1) would lay in + // the subsequent eras (e.g era 5 and up) + + int remainingYears = year - m_EraInfo[i].maxEraYear; + + for (int j = i - 1; j >= 0; j--) + { + if (remainingYears <= m_EraInfo[j].maxEraYear) + { + return m_EraInfo[i].yearOffset; + } + remainingYears -= m_EraInfo[j].maxEraYear; + } + } + } + + if (throwOnError) { throw new ArgumentOutOfRangeException( nameof(year), - String.Format( + string.Format( CultureInfo.CurrentCulture, SR.ArgumentOutOfRange_Range, m_EraInfo[i].minEraYear, m_EraInfo[i].maxEraYear)); } - return (m_EraInfo[i].yearOffset + year); + + break; // no need to iterate more on eras. } } - throw new ArgumentOutOfRangeException(nameof(era), SR.ArgumentOutOfRange_InvalidEraValue); - } - internal bool IsValidYear(int year, int era) - { - if (year < 0) + if (throwOnError) { - return false; + throw new ArgumentOutOfRangeException(nameof(era), SR.ArgumentOutOfRange_InvalidEraValue); } + return -1; + } - if (era == Calendar.CurrentEra) - { - era = m_Cal.CurrentEraValue; - } + /*=================================GetGregorianYear========================== + **Action: Get the Gregorian year value for the specified year in an era. + **Returns: The Gregorian year value. + **Arguments: + ** year the year value in Japanese calendar + ** era the Japanese emperor era value. + **Exceptions: + ** ArgumentOutOfRangeException if year value is invalid or era value is invalid. + ============================================================================*/ - for (int i = 0; i < m_EraInfo.Length; i++) - { - if (era == m_EraInfo[i].era) - { - if (year < m_EraInfo[i].minEraYear || year > m_EraInfo[i].maxEraYear) - { - return false; - } - return true; - } - } - return false; + internal int GetGregorianYear(int year, int era) + { + return GetYearOffset(year, era, throwOnError: true) + year; } + internal bool IsValidYear(int year, int era) + { + return GetYearOffset(year, era, throwOnError: false) >= 0; + } // Returns a given date part of this DateTime. This method is used // to compute the year, day-of-year, month, or day part. @@ -297,7 +324,7 @@ namespace System.Globalization { throw new ArgumentOutOfRangeException( nameof(millisecond), - String.Format( + string.Format( CultureInfo.CurrentCulture, SR.ArgumentOutOfRange_Range, 0, @@ -315,7 +342,7 @@ namespace System.Globalization { throw new ArgumentOutOfRangeException( "time", - String.Format( + string.Format( CultureInfo.InvariantCulture, SR.ArgumentOutOfRange_CalendarRange, m_Cal.MinSupportedDateTime, @@ -346,7 +373,7 @@ namespace System.Globalization { throw new ArgumentOutOfRangeException( nameof(months), - String.Format( + string.Format( CultureInfo.CurrentCulture, SR.ArgumentOutOfRange_Range, -120000, @@ -544,7 +571,7 @@ namespace System.Globalization { throw new ArgumentOutOfRangeException( nameof(day), - String.Format( + string.Format( CultureInfo.CurrentCulture, SR.ArgumentOutOfRange_Range, 1, @@ -583,7 +610,7 @@ namespace System.Globalization { throw new ArgumentOutOfRangeException( nameof(month), - String.Format( + string.Format( CultureInfo.CurrentCulture, SR.ArgumentOutOfRange_Range, 1, @@ -638,7 +665,7 @@ namespace System.Globalization { throw new ArgumentOutOfRangeException( nameof(year), - String.Format( + string.Format( CultureInfo.CurrentCulture, SR.ArgumentOutOfRange_Range, m_minYear, m_maxYear)); } |