< Summary

Line coverage
0%
Covered lines: 0
Uncovered lines: 133
Coverable lines: 133
Total lines: 355
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 82
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.cctor()100%110%
.ctor()100%110%
CheckEraRange(...)0%440%
CheckYearEraRange(...)0%440%
CheckMonthRange(...)0%440%
CheckDayRange(...)0%12120%
GetDatePart(...)0%12120%
DateToTicks(...)0%220%
AddMonths(...)0%14140%
AddYears(...)100%110%
GetDayOfMonth(...)100%110%
GetDayOfWeek(...)100%110%
GetDayOfYear(...)100%110%
GetDaysInMonth(...)0%220%
GetDaysInYear(...)0%220%
GetEra(...)100%110%
GetMonth(...)100%110%
GetMonthsInYear(...)100%110%
GetYear(...)100%110%
IsLeapDay(...)0%440%
GetLeapMonth(...)100%110%
IsLeapMonth(...)100%110%
IsLeapYear(...)100%110%
ToDateTime(...)0%16160%
ToFourDigitYear(...)0%220%

File(s)

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/src/libraries/System.Private.CoreLib/src/System/Globalization/JulianCalendar.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    /// <summary>
 7    /// This class implements the Julian calendar. In 48 B.C. Julius Caesar
 8    /// ordered a calendar reform, and this calendar is called Julian calendar.
 9    /// It consisted of a solar year of twelve months and of 365 days with an
 10    /// extra day every fourth year.
 11    /// </summary>
 12    /// <remarks>
 13    /// Calendar support range:
 14    ///     Calendar    Minimum     Maximum
 15    ///     ==========  ==========  ==========
 16    ///     Gregorian   0001/01/01   9999/12/31
 17    ///     Julia       0001/01/03   9999/10/19
 18    /// </remarks>
 19    public class JulianCalendar : Calendar
 20    {
 021        public static readonly int JulianEra = 1;
 22
 23        private const int DatePartYear = 0;
 24        private const int DatePartDayOfYear = 1;
 25        private const int DatePartMonth = 2;
 26        private const int DatePartDay = 3;
 27
 28        // Number of days in a non-leap year
 29        private const int JulianDaysPerYear = 365;
 30
 31        // Number of days in 4 years
 32        private const int JulianDaysPer4Years = JulianDaysPerYear * 4 + 1;
 33
 34        // Gregorian Calendar 9999/12/31 = Julian Calendar 9999/10/19
 35        // keep it as variable field for serialization compat.
 036        internal int MaxYear = 9999;
 37
 038        public override DateTime MinSupportedDateTime => DateTime.MinValue;
 39
 040        public override DateTime MaxSupportedDateTime => DateTime.MaxValue;
 41
 042        public override CalendarAlgorithmType AlgorithmType => CalendarAlgorithmType.SolarCalendar;
 43
 044        public JulianCalendar()
 45        {
 46            // There is no system setting of TwoDigitYear max, so set the value here.
 047            _twoDigitYearMax = 2049;
 048        }
 49
 050        internal override CalendarId ID => CalendarId.JULIAN;
 51
 52        internal static void CheckEraRange(int era)
 53        {
 054            if (era != CurrentEra && era != JulianEra)
 55            {
 056                throw new ArgumentOutOfRangeException(nameof(era), era, SR.ArgumentOutOfRange_InvalidEraValue);
 57            }
 058        }
 59
 60        internal void CheckYearEraRange(int year, int era)
 61        {
 062            CheckEraRange(era);
 063            if (year <= 0 || year > MaxYear)
 64            {
 065                throw new ArgumentOutOfRangeException(
 066                    nameof(year),
 067                    year,
 068                    SR.Format(SR.ArgumentOutOfRange_Range, 1, MaxYear));
 69            }
 070        }
 71
 72        internal static void CheckMonthRange(int month)
 73        {
 074            if (month < 1 || month > 12)
 75            {
 076                ThrowHelper.ThrowArgumentOutOfRange_Month(month);
 77            }
 078        }
 79
 80        /// <summary>
 81        /// Check for if the day value is valid.
 82        /// </summary>
 83        /// <remarks>
 84        /// Before calling this method, call CheckYearEraRange()/CheckMonthRange() to make
 85        /// sure year/month values are correct.
 86        /// </remarks>
 87        internal static void CheckDayRange(int year, int month, int day)
 88        {
 089            if (year == 1 && month == 1)
 90            {
 91                // The minimum supported Julia date is Julian 0001/01/03.
 092                if (day < 3)
 93                {
 094                    throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadYearMonthDay);
 95                }
 96            }
 97
 098            bool isLeapYear = (year % 4) == 0;
 099            ReadOnlySpan<int> days = isLeapYear ? GregorianCalendar.DaysToMonth366 : GregorianCalendar.DaysToMonth365;
 0100            int monthDays = days[month] - days[month - 1];
 0101            if (day < 1 || day > monthDays)
 102            {
 0103                throw new ArgumentOutOfRangeException(
 0104                    nameof(day),
 0105                    day,
 0106                    SR.Format(SR.ArgumentOutOfRange_Range, 1, monthDays));
 107            }
 0108        }
 109
 110        /// <summary>
 111        /// Returns a given date part of this DateTime. This method is used
 112        /// to compute the year, day-of-year, month, or day part.
 113        /// </summary>
 114        private static int GetDatePart(long ticks, int part)
 115        {
 116            // Gregorian 1/1/0001 is Julian 1/3/0001. Remember DateTime(0) is referred to Gregorian 1/1/0001.
 117            // The following line convert Gregorian ticks to Julian ticks.
 0118            long julianTicks = ticks + TimeSpan.TicksPerDay * 2;
 119            // n = number of days since 1/1/0001
 0120            int n = (int)(julianTicks / TimeSpan.TicksPerDay);
 121            // y4 = number of whole 4-year periods within 100-year period
 0122            int y4 = n / JulianDaysPer4Years;
 123            // n = day number within 4-year period
 0124            n -= y4 * JulianDaysPer4Years;
 125            // y1 = number of whole years within 4-year period
 0126            int y1 = n / JulianDaysPerYear;
 127            // Last year has an extra day, so decrement result if 4
 0128            if (y1 == 4) y1 = 3;
 129            // If year was requested, compute and return it
 0130            if (part == DatePartYear)
 131            {
 0132                return y4 * 4 + y1 + 1;
 133            }
 134
 135            // n = day number within year
 0136            n -= y1 * JulianDaysPerYear;
 137            // If day-of-year was requested, return it
 0138            if (part == DatePartDayOfYear)
 139            {
 0140                return n + 1;
 141            }
 142
 143            // Leap year calculation looks different from IsLeapYear since y1, y4,
 144            // and y100 are relative to year 1, not year 0
 0145            bool leapYear = (y1 == 3);
 0146            ReadOnlySpan<int> days = leapYear ? GregorianCalendar.DaysToMonth366 : GregorianCalendar.DaysToMonth365;
 147            // All months have less than 32 days, so n >> 5 is a good conservative
 148            // estimate for the month
 0149            int m = (n >> 5) + 1;
 150            // m = 1-based month number
 0151            while (n >= days[m])
 152            {
 0153                m++;
 154            }
 155
 156            // If month was requested, return it
 0157            if (part == DatePartMonth)
 158            {
 0159                return m;
 160            }
 161
 162            // Return 1-based day-of-month
 0163            return n - days[m - 1] + 1;
 164        }
 165
 166        /// <summary>
 167        /// Returns the tick count corresponding to the given year, month, and day.
 168        /// </summary>
 169        internal static long DateToTicks(int year, int month, int day)
 170        {
 0171            ReadOnlySpan<int> days = (year % 4 == 0) ? GregorianCalendar.DaysToMonth366 : GregorianCalendar.DaysToMonth3
 0172            int y = year - 1;
 0173            int n = y * 365 + y / 4 + days[month - 1] + day - 1;
 174            // Gregorian 1/1/0001 is Julian 1/3/0001. n * TicksPerDay is the ticks in JulianCalendar.
 175            // Therefore, we subtract two days in the following to convert the ticks in JulianCalendar
 176            // to ticks in Gregorian calendar.
 0177            return (n - 2) * TimeSpan.TicksPerDay;
 178        }
 179
 180        public override DateTime AddMonths(DateTime time, int months)
 181        {
 0182            if (months < -120000 || months > 120000)
 183            {
 0184                throw new ArgumentOutOfRangeException(
 0185                    nameof(months),
 0186                    months,
 0187                    SR.Format(SR.ArgumentOutOfRange_Range, -120000, 120000));
 188            }
 189
 0190            int y = GetDatePart(time.Ticks, DatePartYear);
 0191            int m = GetDatePart(time.Ticks, DatePartMonth);
 0192            int d = GetDatePart(time.Ticks, DatePartDay);
 0193            int i = m - 1 + months;
 0194            if (i >= 0)
 195            {
 0196                m = i % 12 + 1;
 0197                y += i / 12;
 198            }
 199            else
 200            {
 0201                m = 12 + (i + 1) % 12;
 0202                y += (i - 11) / 12;
 203            }
 204
 0205            ReadOnlySpan<int> daysArray = (y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) ? GregorianCalendar.DaysToMonth
 0206            int days = daysArray[m] - daysArray[m - 1];
 0207            if (d > days)
 208            {
 0209                d = days;
 210            }
 211
 0212            long ticks = DateToTicks(y, m, d) + time.Ticks % TimeSpan.TicksPerDay;
 0213            CheckAddResult(ticks, MinSupportedDateTime, MaxSupportedDateTime);
 0214            return new DateTime(ticks);
 215        }
 216
 217        public override DateTime AddYears(DateTime time, int years)
 218        {
 0219            return AddMonths(time, years * 12);
 220        }
 221
 222        public override int GetDayOfMonth(DateTime time)
 223        {
 0224            return GetDatePart(time.Ticks, DatePartDay);
 225        }
 226
 0227        public override DayOfWeek GetDayOfWeek(DateTime time) => time.DayOfWeek;
 228
 229        public override int GetDayOfYear(DateTime time)
 230        {
 0231            return GetDatePart(time.Ticks, DatePartDayOfYear);
 232        }
 233
 234        public override int GetDaysInMonth(int year, int month, int era)
 235        {
 0236            CheckYearEraRange(year, era);
 0237            CheckMonthRange(month);
 0238            ReadOnlySpan<int> days = (year % 4 == 0) ? GregorianCalendar.DaysToMonth366 : GregorianCalendar.DaysToMonth3
 0239            return days[month] - days[month - 1];
 240        }
 241
 242        public override int GetDaysInYear(int year, int era)
 243        {
 244            // Year/Era range is done in IsLeapYear().
 0245            return IsLeapYear(year, era) ? 366 : 365;
 246        }
 247
 0248        public override int GetEra(DateTime time) => JulianEra;
 249
 250        public override int GetMonth(DateTime time)
 251        {
 0252            return GetDatePart(time.Ticks, DatePartMonth);
 253        }
 254
 0255        public override int[] Eras => [JulianEra];
 256
 257        public override int GetMonthsInYear(int year, int era)
 258        {
 0259            CheckYearEraRange(year, era);
 0260            return 12;
 261        }
 262
 263        public override int GetYear(DateTime time)
 264        {
 0265            return GetDatePart(time.Ticks, DatePartYear);
 266        }
 267
 268        public override bool IsLeapDay(int year, int month, int day, int era)
 269        {
 0270            CheckMonthRange(month);
 271            // Year/Era range check is done in IsLeapYear().
 0272            if (IsLeapYear(year, era))
 273            {
 0274                CheckDayRange(year, month, day);
 0275                return month == 2 && day == 29;
 276            }
 277
 0278            CheckDayRange(year, month, day);
 0279            return false;
 280        }
 281
 282        public override int GetLeapMonth(int year, int era)
 283        {
 0284            CheckYearEraRange(year, era);
 0285            return 0;
 286        }
 287
 288        public override bool IsLeapMonth(int year, int month, int era)
 289        {
 0290            CheckYearEraRange(year, era);
 0291            CheckMonthRange(month);
 0292            return false;
 293        }
 294
 295        public override bool IsLeapYear(int year, int era)
 296        {
 0297            CheckYearEraRange(year, era);
 0298            return year % 4 == 0;
 299        }
 300
 301        public override DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisec
 302        {
 0303            CheckYearEraRange(year, era);
 0304            CheckMonthRange(month);
 0305            CheckDayRange(year, month, day);
 0306            if (millisecond < 0 || millisecond >= TimeSpan.MillisecondsPerSecond)
 307            {
 0308                throw new ArgumentOutOfRangeException(
 0309                    nameof(millisecond),
 0310                    millisecond,
 0311                    SR.Format(SR.ArgumentOutOfRange_Range, 0, TimeSpan.MillisecondsPerSecond - 1));
 312            }
 313
 0314            if (hour < 0 || hour >= 24 || minute < 0 || minute >= 60 || second < 0 || second >= 60)
 315            {
 0316                throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadHourMinuteSecond);
 317            }
 318
 0319            return new DateTime(DateToTicks(year, month, day) + (new TimeSpan(0, hour, minute, second, millisecond)).Tic
 320        }
 321
 322        public override int TwoDigitYearMax
 323        {
 0324            get => _twoDigitYearMax;
 325            set
 326            {
 0327                VerifyWritable();
 0328                if (value < 99 || value > MaxYear)
 329                {
 0330                    throw new ArgumentOutOfRangeException(
 0331                        nameof(value),
 0332                        value,
 0333                        SR.Format(SR.ArgumentOutOfRange_Range, 99, MaxYear));
 334                }
 335
 0336                _twoDigitYearMax = value;
 0337            }
 338        }
 339
 340        public override int ToFourDigitYear(int year)
 341        {
 0342            ArgumentOutOfRangeException.ThrowIfNegative(year);
 0343            if (year > MaxYear)
 344            {
 0345                throw new ArgumentOutOfRangeException(
 0346                    nameof(year),
 0347                    year,
 0348                    SR.Format(SR.ArgumentOutOfRange_Bounds_Lower_Upper, 1, MaxYear));
 349            }
 350
 0351            return base.ToFourDigitYear(year);
 352        }
 353    }
 354}
 355