< Summary

Line coverage
0%
Covered lines: 0
Uncovered lines: 145
Coverable lines: 145
Total lines: 445
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 140
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
GetDefaultInstance()0%220%
.ctor()100%110%
.ctor(...)0%440%
GetAbsoluteDate(...)0%18180%
DateToTicks(...)100%110%
AddMonths(...)0%14140%
AddYears(...)100%110%
GetDayOfMonth(...)100%110%
GetDayOfWeek(...)100%110%
GetDayOfYear(...)100%110%
GetDaysInMonth(...)0%440%
GetDaysInYear(...)0%660%
GetEra(...)100%110%
GetMonth(...)100%110%
GetMonthsInYear(...)0%880%
GetYear(...)100%110%
IsValidYear(...)0%220%
IsValidDay(...)0%20200%
IsLeapDay(...)0%20200%
GetLeapMonth(...)0%880%
IsLeapMonth(...)0%12120%
IsLeapYear(...)0%440%
ToDateTime(...)0%440%
TryToDateTime(...)0%440%
ToFourDigitYear(...)100%110%

File(s)

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/src/libraries/System.Private.CoreLib/src/System/Globalization/GregorianCalendar.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4namespace System.Globalization
 5{
 6    /// <remarks>
 7    /// This calendar recognizes two era values:
 8    /// 0 CurrentEra (AD)
 9    /// 1 BeforeCurrentEra (BC)
 10    /// </remarks>
 11    public class GregorianCalendar : Calendar
 12    {
 13        public const int ADEra = 1;
 14
 15        // This is the min Gregorian year can be represented by the DateTime class.
 16        // The limitation is derived from the DateTime class.
 17        internal const int MinYear = 1;
 18
 19        // This is the max Gregorian year can be represented by the DateTime class.
 20        // The limitation is derived from the DateTime class.
 21        internal const int MaxYear = 9999;
 22
 23        private GregorianCalendarTypes _type;
 24
 025        internal static ReadOnlySpan<int> DaysToMonth365 => [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365]
 26
 027        internal static ReadOnlySpan<int> DaysToMonth366 => [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366]
 28
 29        private static Calendar? s_defaultInstance;
 30
 031        public override DateTime MinSupportedDateTime => DateTime.MinValue;
 32
 033        public override DateTime MaxSupportedDateTime => DateTime.MaxValue;
 34
 035        public override CalendarAlgorithmType AlgorithmType => CalendarAlgorithmType.SolarCalendar;
 36
 37        /// <summary>
 38        /// Internal method to provide a default instance of GregorianCalendar.
 39        /// Used by NLS+ implementation
 40        /// </summary>
 041        internal static Calendar GetDefaultInstance() => s_defaultInstance ??= new GregorianCalendar();
 42
 043        public GregorianCalendar() : this(GregorianCalendarTypes.Localized)
 44        {
 045        }
 46
 047        public GregorianCalendar(GregorianCalendarTypes type)
 48        {
 049            if (type < GregorianCalendarTypes.Localized || type > GregorianCalendarTypes.TransliteratedFrench)
 50            {
 051                throw new ArgumentOutOfRangeException(
 052                    nameof(type),
 053                    type,
 054                    SR.Format(SR.ArgumentOutOfRange_Range, GregorianCalendarTypes.Localized, GregorianCalendarTypes.Tran
 55            }
 56
 057            _type = type;
 058        }
 59
 60        public virtual GregorianCalendarTypes CalendarType
 61        {
 062            get => _type;
 63            set
 64            {
 065                VerifyWritable();
 066                if (value < GregorianCalendarTypes.Localized || value > GregorianCalendarTypes.TransliteratedFrench)
 67                {
 068                    throw new ArgumentOutOfRangeException(
 069                        nameof(value),
 070                        value,
 071                        SR.Format(SR.ArgumentOutOfRange_Range, GregorianCalendarTypes.Localized, GregorianCalendarTypes.
 72                }
 73
 074                _type = value;
 075            }
 76        }
 77
 78        internal override CalendarId ID =>
 79            // By returning different ID for different variations of GregorianCalendar,
 80            // we can support the Transliterated Gregorian calendar.
 81            // DateTimeFormatInfo will use this ID to get formatting information about
 82            // the calendar.
 083            (CalendarId)_type;
 84
 85        /// <summary>
 86        /// Gets the absolute date for the given Gregorian date. The absolute date means
 87        /// the number of days from January 1st, 1 A.D.
 88        /// </summary>
 89        /// <remarks>
 90        /// This is an internal method used by DateToTicks() and the calculations of Hijri and Hebrew calendars.
 91        /// Number of Days in Prior Years (both common and leap years) +
 92        /// Number of Days in Prior Months of Current Year +
 93        /// Number of Days in Current Month
 94        /// </remarks>
 95        internal static long GetAbsoluteDate(int year, int month, int day)
 96        {
 097            if (year >= 1 && year <= MaxYear && month >= 1 && month <= 12)
 98            {
 099                ReadOnlySpan<int> days = (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ? DaysToMonth366 : Days
 0100                if (day >= 1 && (day <= days[month] - days[month - 1]))
 101                {
 0102                    int y = year - 1;
 0103                    return y * 365 + y / 4 - y / 100 + y / 400 + days[month - 1] + day - 1;
 104                }
 105            }
 106
 0107            throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadYearMonthDay);
 108        }
 109
 110        /// <summary>
 111        /// Returns the tick count corresponding to the given year, month, and day.
 112        /// Will check the if the parameters are valid.
 113        /// </summary>
 114        internal static long DateToTicks(int year, int month, int day)
 115        {
 0116            return GetAbsoluteDate(year, month, day) * TimeSpan.TicksPerDay;
 117        }
 118
 119        /// <summary>
 120        /// Returns the DateTime resulting from adding the given number of
 121        /// months to the specified DateTime. The result is computed by incrementing
 122        /// (or decrementing) the year and month parts of the specified DateTime by
 123        /// value months, and, if required, adjusting the day part of the
 124        /// resulting date downwards to the last day of the resulting month in the
 125        /// resulting year. The time-of-day part of the result is the same as the
 126        /// time-of-day part of the specified DateTime.
 127        ///
 128        /// In more precise terms, considering the specified DateTime to be of the
 129        /// form y / m / d + t, where y is the
 130        /// year, m is the month, d is the day, and t is the
 131        /// time-of-day, the result is y1 / m1 / d1 + t,
 132        /// where y1 and m1 are computed by adding value months
 133        /// to y and m, and d1 is the largest value less than
 134        /// or equal to d that denotes a valid day in month m1 of year
 135        /// y1.
 136        /// </summary>
 137        public override DateTime AddMonths(DateTime time, int months)
 138        {
 0139            if (months < -120000 || months > 120000)
 140            {
 0141                throw new ArgumentOutOfRangeException(
 0142                    nameof(months),
 0143                    months,
 0144                    SR.Format(SR.ArgumentOutOfRange_Range, -120000, 120000));
 145            }
 146
 0147            time.GetDate(out int y, out int m, out int d);
 0148            int i = m - 1 + months;
 0149            if (i >= 0)
 150            {
 0151                m = i % 12 + 1;
 0152                y += i / 12;
 153            }
 154            else
 155            {
 0156                m = 12 + (i + 1) % 12;
 0157                y += (i - 11) / 12;
 158            }
 159
 0160            ReadOnlySpan<int> daysArray = (y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) ? DaysToMonth366 : DaysToMonth3
 0161            int days = (daysArray[m] - daysArray[m - 1]);
 162
 0163            if (d > days)
 164            {
 0165                d = days;
 166            }
 0167            long ticks = DateToTicks(y, m, d) + time.Ticks % TimeSpan.TicksPerDay;
 0168            CheckAddResult(ticks, MinSupportedDateTime, MaxSupportedDateTime);
 169
 0170            return new DateTime(ticks);
 171        }
 172
 173        /// <summary>
 174        /// Returns the DateTime resulting from adding the given number of
 175        /// years to the specified DateTime. The result is computed by incrementing
 176        /// (or decrementing) the year part of the specified DateTime by value
 177        /// years. If the month and day of the specified DateTime is 2/29, and if the
 178        /// resulting year is not a leap year, the month and day of the resulting
 179        /// DateTime becomes 2/28. Otherwise, the month, day, and time-of-day
 180        /// parts of the result are the same as those of the specified DateTime.
 181        /// </summary>
 182        public override DateTime AddYears(DateTime time, int years)
 183        {
 0184            return AddMonths(time, years * 12);
 185        }
 186
 187        /// <summary>
 188        /// Returns the day-of-month part of the specified DateTime. The returned
 189        /// value is an integer between 1 and 31.
 190        /// </summary>
 0191        public override int GetDayOfMonth(DateTime time) => time.Day;
 192
 193        /// <summary>
 194        /// Returns the day-of-week part of the specified DateTime. The returned value
 195        /// is an integer between 0 and 6, where 0 indicates Sunday, 1 indicates
 196        /// Monday, 2 indicates Tuesday, 3 indicates Wednesday, 4 indicates
 197        /// Thursday, 5 indicates Friday, and 6 indicates Saturday.
 198        /// </summary>
 0199        public override DayOfWeek GetDayOfWeek(DateTime time) => time.DayOfWeek;
 200
 201        /// <summary>
 202        /// Returns the day-of-year part of the specified DateTime. The returned value
 203        /// is an integer between 1 and 366.
 204        /// </summary>
 0205        public override int GetDayOfYear(DateTime time) => time.DayOfYear;
 206
 207        /// <summary>
 208        /// Returns the number of days in the month given by the year and
 209        /// month arguments.
 210        /// </summary>
 211        public override int GetDaysInMonth(int year, int month, int era)
 212        {
 0213            if (era != CurrentEra && era != ADEra)
 214            {
 0215                throw new ArgumentOutOfRangeException(nameof(era), era, SR.ArgumentOutOfRange_InvalidEraValue);
 216            }
 0217            return DateTime.DaysInMonth(year, month);
 218        }
 219
 220        /// <summary>
 221        /// Returns the number of days in the year given by the year argument for
 222        /// the current era.
 223        /// </summary>
 224        public override int GetDaysInYear(int year, int era)
 225        {
 0226            if (era != CurrentEra && era != ADEra)
 227            {
 0228                throw new ArgumentOutOfRangeException(nameof(era), era, SR.ArgumentOutOfRange_InvalidEraValue);
 229            }
 0230            return DateTime.IsLeapYear(year) ? 366 : 365;
 231        }
 232
 0233        public override int GetEra(DateTime time) => ADEra;
 234
 0235        public override int[] Eras => [ADEra];
 236
 237        /// <summary>
 238        /// Returns the month part of the specified DateTime.
 239        /// The returned value is an integer between 1 and 12.
 240        /// </summary>
 0241        public override int GetMonth(DateTime time) => time.Month;
 242
 243        /// <summary>
 244        /// Returns the number of months in the specified year and era.
 245        /// </summary>
 246        public override int GetMonthsInYear(int year, int era)
 247        {
 0248            if (era != CurrentEra && era != ADEra)
 249            {
 0250                throw new ArgumentOutOfRangeException(nameof(era), era, SR.ArgumentOutOfRange_InvalidEraValue);
 251            }
 0252            if (year < 1 || year > MaxYear)
 253            {
 0254                throw new ArgumentOutOfRangeException(
 0255                    nameof(year),
 0256                    year,
 0257                    SR.Format(SR.ArgumentOutOfRange_Range, 1, MaxYear));
 258            }
 259
 0260            return 12;
 261        }
 262
 263        /// <summary>
 264        /// Returns the year part of the specified DateTime. The returned value is an
 265        /// integer between 1 and 9999.
 266        /// </summary>
 0267        public override int GetYear(DateTime time) => time.Year;
 268
 0269        internal override bool IsValidYear(int year, int era) => year >= 1 && year <= MaxYear;
 270
 271        internal override bool IsValidDay(int year, int month, int day, int era)
 272        {
 0273            if ((era != CurrentEra && era != ADEra) ||
 0274                year < 1 || year > MaxYear ||
 0275                month < 1 || month > 12 ||
 0276                day < 1)
 277            {
 0278                return false;
 279            }
 280
 0281            ReadOnlySpan<int> days = (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ? DaysToMonth366 : DaysToMo
 0282            return day <= (days[month] - days[month - 1]);
 283        }
 284
 285        /// <summary>
 286        /// Checks whether a given day in the specified era is a leap day. This method returns true if
 287        /// the date is a leap day, or false if not.
 288        /// </summary>
 289        public override bool IsLeapDay(int year, int month, int day, int era)
 290        {
 0291            if (month < 1 || month > 12)
 292            {
 0293                throw new ArgumentOutOfRangeException(
 0294                    nameof(month),
 0295                    month,
 0296                    SR.Format(SR.ArgumentOutOfRange_Range, 1, 12));
 297            }
 298
 0299            if (era != CurrentEra && era != ADEra)
 300            {
 0301                throw new ArgumentOutOfRangeException(nameof(era), era, SR.ArgumentOutOfRange_InvalidEraValue);
 302            }
 0303            if (year < 1 || year > MaxYear)
 304            {
 0305                throw new ArgumentOutOfRangeException(
 0306                    nameof(year),
 0307                    year,
 0308                    SR.Format(SR.ArgumentOutOfRange_Range, 1, MaxYear));
 309            }
 0310            if (day < 1 || day > GetDaysInMonth(year, month))
 311            {
 0312                throw new ArgumentOutOfRangeException(
 0313                    nameof(day),
 0314                    day,
 0315                    SR.Format(SR.ArgumentOutOfRange_Range, 1, GetDaysInMonth(year, month)));
 316            }
 317
 0318            return IsLeapYear(year) && month == 2 && day == 29;
 319        }
 320
 321        /// <summary>
 322        /// Returns the leap month in a calendar year of the specified era.
 323        /// This method returns 0 if this calendar does not have leap month, or
 324        /// this year is not a leap year.
 325        /// </summary>
 326        public override int GetLeapMonth(int year, int era)
 327        {
 0328            if (era != CurrentEra && era != ADEra)
 329            {
 0330                throw new ArgumentOutOfRangeException(nameof(era), era, SR.ArgumentOutOfRange_InvalidEraValue);
 331            }
 0332            if (year < 1 || year > MaxYear)
 333            {
 0334                throw new ArgumentOutOfRangeException(
 0335                    nameof(year),
 0336                    year,
 0337                    SR.Format(SR.ArgumentOutOfRange_Range, 1, MaxYear));
 338            }
 339
 0340            return 0;
 341        }
 342
 343        /// <summary>
 344        /// Checks whether a given month in the specified era is a leap month.
 345        /// This method returns true if month is a leap month, or false if not.
 346        /// </summary>
 347        public override bool IsLeapMonth(int year, int month, int era)
 348        {
 0349            if (era != CurrentEra && era != ADEra)
 350            {
 0351                throw new ArgumentOutOfRangeException(nameof(era), era, SR.ArgumentOutOfRange_InvalidEraValue);
 352            }
 0353            if (year < 1 || year > MaxYear)
 354            {
 0355                throw new ArgumentOutOfRangeException(
 0356                    nameof(year),
 0357                    year,
 0358                    SR.Format(SR.ArgumentOutOfRange_Range, 1, MaxYear));
 359            }
 0360            if (month < 1 || month > 12)
 361            {
 0362                throw new ArgumentOutOfRangeException(
 0363                    nameof(month),
 0364                    month,
 0365                    SR.Format(SR.ArgumentOutOfRange_Range, 1, 12));
 366            }
 367
 0368            return false;
 369        }
 370
 371        /// <summary>
 372        /// Checks whether a given year in the specified era is a leap year. This method returns true if
 373        /// year is a leap year, or false if not.
 374        /// </summary>
 375        public override bool IsLeapYear(int year, int era)
 376        {
 0377            if (era != CurrentEra && era != ADEra)
 378            {
 0379                throw new ArgumentOutOfRangeException(nameof(era), era, SR.ArgumentOutOfRange_InvalidEraValue);
 380            }
 0381            return DateTime.IsLeapYear(year);
 382        }
 383
 384        /// <summary>
 385        /// Returns the date and time converted to a DateTime value.
 386        /// Throws an exception if the n-tuple is invalid.
 387        /// </summary>
 388        public override DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisec
 389        {
 0390            if (era != CurrentEra && era != ADEra)
 391            {
 0392                throw new ArgumentOutOfRangeException(nameof(era), era, SR.ArgumentOutOfRange_InvalidEraValue);
 393            }
 394
 0395            return new DateTime(year, month, day, hour, minute, second, millisecond);
 396        }
 397
 398        internal override bool TryToDateTime(int year, int month, int day, int hour, int minute, int second, int millise
 399        {
 0400            if (era != CurrentEra && era != ADEra)
 401            {
 0402                result = DateTime.MinValue;
 0403                return false;
 404            }
 405
 0406            return DateTime.TryCreate(year, month, day, hour, minute, second, millisecond, out result);
 407        }
 408
 409        private const int DefaultTwoDigitYearMax = 2049;
 410
 411        public override int TwoDigitYearMax
 412        {
 413            get
 414            {
 0415                if (_twoDigitYearMax == -1)
 416                {
 0417                    _twoDigitYearMax = GetSystemTwoDigitYearSetting(ID, DefaultTwoDigitYearMax);
 418                }
 419
 0420                return _twoDigitYearMax;
 421            }
 422            set
 423            {
 0424                VerifyWritable();
 0425                if (value < 99 || value > MaxYear)
 426                {
 0427                    throw new ArgumentOutOfRangeException(
 0428                        nameof(value),
 0429                        value,
 0430                        SR.Format(SR.ArgumentOutOfRange_Range, 99, MaxYear));
 431                }
 0432                _twoDigitYearMax = value;
 0433            }
 434        }
 435
 436        public override int ToFourDigitYear(int year)
 437        {
 0438            ArgumentOutOfRangeException.ThrowIfNegative(year);
 0439            ArgumentOutOfRangeException.ThrowIfGreaterThan(year, MaxYear);
 440
 0441            return base.ToFourDigitYear(year);
 442        }
 443    }
 444}
 445