< Summary

Line coverage
0%
Covered lines: 0
Uncovered lines: 135
Coverable lines: 135
Total lines: 692
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 66
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/src/libraries/System.Private.CoreLib/src/System/Globalization/Calendar.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
 4using System.Diagnostics;
 5using System.Runtime.InteropServices;
 6
 7namespace System.Globalization
 8{
 9    // This abstract class represents a calendar. A calendar reckons time in
 10    // divisions such as weeks, months and years. The number, length and start of
 11    // the divisions vary in each calendar.
 12    //
 13    // Any instant in time can be represented as an n-tuple of numeric values using
 14    // a particular calendar. For example, the next vernal equinox occurs at (0.0, 0
 15    // , 46, 8, 20, 3, 1999) in the Gregorian calendar. An  implementation of
 16    // Calendar can map any DateTime value to such an n-tuple and vice versa. The
 17    // DateTimeFormat class can map between such n-tuples and a textual
 18    // representation such as "8:46 AM March 20th 1999 AD".
 19    //
 20    // Most calendars identify a year which begins the current era. There may be any
 21    // number of previous eras. The Calendar class identifies the eras as enumerated
 22    // integers where the current era (CurrentEra) has the value zero.
 23    //
 24    // For consistency, the first unit in each interval, e.g. the first month, is
 25    // assigned the value one.
 26    // The calculation of hour/minute/second is moved to Calendar from GregorianCalendar,
 27    // since most of the calendars (or all?) have the same way of calculating hour/minute/second.
 28
 29    public abstract class Calendar : ICloneable
 30    {
 31        internal const long MaxMillis = (long)DateTime.DaysTo10000 * TimeSpan.MillisecondsPerDay;
 32
 033        private int _currentEraValue = -1;
 34
 35        private bool _isReadOnly;
 36
 037        public virtual DateTime MinSupportedDateTime => DateTime.MinValue;
 38
 039        public virtual DateTime MaxSupportedDateTime => DateTime.MaxValue;
 40
 041        public virtual CalendarAlgorithmType AlgorithmType => CalendarAlgorithmType.Unknown;
 42
 043        protected Calendar()
 44        {
 045        }
 46
 047        internal virtual CalendarId ID => CalendarId.UNINITIALIZED_VALUE;
 48
 49        // Return the Base calendar ID for calendars that didn't have defined data in calendarData
 050        internal virtual CalendarId BaseCalendarID => ID;
 51
 052        public bool IsReadOnly => _isReadOnly;
 53
 54        public virtual object Clone()
 55        {
 056            object o = MemberwiseClone();
 057            ((Calendar)o).SetReadOnlyState(false);
 058            return o;
 59        }
 60
 61        public static Calendar ReadOnly(Calendar calendar)
 62        {
 063            ArgumentNullException.ThrowIfNull(calendar);
 64
 065            if (calendar.IsReadOnly)
 66            {
 067                return calendar;
 68            }
 69
 070            Calendar clonedCalendar = (Calendar)(calendar.MemberwiseClone());
 071            clonedCalendar.SetReadOnlyState(true);
 072            return clonedCalendar;
 73        }
 74
 75        internal void VerifyWritable()
 76        {
 077            if (_isReadOnly)
 78            {
 079                throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
 80            }
 081        }
 82
 83        internal void SetReadOnlyState(bool readOnly)
 84        {
 085            _isReadOnly = readOnly;
 086        }
 87
 88        /// <summary>
 89        /// This is used to convert CurrentEra(0) to an appropriate era value.
 90        /// </summary>
 91        internal int CurrentEraValue
 92        {
 93            get
 94            {
 95                // The following code assumes that the current era value can not be -1.
 096                if (_currentEraValue == -1)
 97                {
 098                    Debug.Assert(BaseCalendarID != CalendarId.UNINITIALIZED_VALUE, "[Calendar.CurrentEraValue] Expected 
 099                    _currentEraValue = CalendarData.GetCalendarCurrentEra(this);
 100                }
 101
 0102                return _currentEraValue;
 103            }
 104        }
 105
 106        public const int CurrentEra = 0;
 107
 0108        internal int _twoDigitYearMax = -1;
 109
 110        internal static void CheckAddResult(long ticks, DateTime minValue, DateTime maxValue)
 111        {
 0112            if (ticks < minValue.Ticks || ticks > maxValue.Ticks)
 113            {
 0114                throw new ArgumentException(SR.Format(SR.Argument_ResultCalendarRange, minValue, maxValue));
 115            }
 0116        }
 117
 118        internal DateTime Add(DateTime time, double value, int scale)
 119        {
 120            // From ECMA CLI spec, Partition III, section 3.27:
 121            //
 122            // If overflow occurs converting a floating-point type to an integer, or if the floating-point value
 123            // being converted to an integer is a NaN, the value returned is unspecified.
 124            //
 125            // Based upon this, this method should be performing the comparison against the double
 126            // before attempting a cast. Otherwise, the result is undefined.
 0127            double tempMillis = (value * scale + (value >= 0 ? 0.5 : -0.5));
 0128            if (!((tempMillis > -(double)MaxMillis) && (tempMillis < (double)MaxMillis)))
 129            {
 0130                throw new ArgumentOutOfRangeException(nameof(value), value, SR.ArgumentOutOfRange_AddValue);
 131            }
 132
 0133            long millis = (long)tempMillis;
 0134            long ticks = time.Ticks + millis * TimeSpan.TicksPerMillisecond;
 0135            CheckAddResult(ticks, MinSupportedDateTime, MaxSupportedDateTime);
 0136            return new DateTime(ticks);
 137        }
 138
 139        /// <summary>
 140        /// Returns the DateTime resulting from adding the given number of
 141        /// milliseconds to the specified DateTime. The result is computed by rounding
 142        /// the number of milliseconds given by value to the nearest integer,
 143        /// and adding that interval to the specified DateTime. The value
 144        /// argument is permitted to be negative.
 145        /// </summary>
 146        public virtual DateTime AddMilliseconds(DateTime time, double milliseconds)
 147        {
 0148            return Add(time, milliseconds, 1);
 149        }
 150
 151        /// <summary>
 152        /// Returns the DateTime resulting from adding a fractional number of
 153        /// days to the specified DateTime. The result is computed by rounding the
 154        /// fractional number of days given by value to the nearest
 155        /// millisecond, and adding that interval to the specified DateTime. The
 156        /// value argument is permitted to be negative.
 157        /// </summary>
 158        public virtual DateTime AddDays(DateTime time, int days)
 159        {
 0160            return Add(time, days, (int)TimeSpan.MillisecondsPerDay);
 161        }
 162
 163        /// <summary>
 164        /// Returns the DateTime resulting from adding a fractional number of
 165        /// hours to the specified DateTime. The result is computed by rounding the
 166        /// fractional number of hours given by value to the nearest
 167        /// millisecond, and adding that interval to the specified DateTime. The
 168        /// value argument is permitted to be negative.
 169        /// </summary>
 170        public virtual DateTime AddHours(DateTime time, int hours)
 171        {
 0172            return Add(time, hours, (int)TimeSpan.MillisecondsPerHour);
 173        }
 174
 175        /// <summary>
 176        /// Returns the DateTime resulting from adding a fractional number of
 177        /// minutes to the specified DateTime. The result is computed by rounding the
 178        /// fractional number of minutes given by value to the nearest
 179        /// millisecond, and adding that interval to the specified DateTime. The
 180        /// value argument is permitted to be negative.
 181        /// </summary>
 182        public virtual DateTime AddMinutes(DateTime time, int minutes)
 183        {
 0184            return Add(time, minutes, (int)TimeSpan.MillisecondsPerMinute);
 185        }
 186
 187        /// <summary>
 188        /// Returns the DateTime resulting from adding the given number of
 189        /// months to the specified DateTime. The result is computed by incrementing
 190        /// (or decrementing) the year and month parts of the specified DateTime by
 191        /// value months, and, if required, adjusting the day part of the
 192        /// resulting date downwards to the last day of the resulting month in the
 193        /// resulting year. The time-of-day part of the result is the same as the
 194        /// time-of-day part of the specified DateTime.
 195        ///
 196        /// In more precise terms, considering the specified DateTime to be of the
 197        /// form y / m / d + t, where y is the
 198        /// year, m is the month, d is the day, and t is the
 199        /// time-of-day, the result is y1 / m1 / d1 + t,
 200        /// where y1 and m1 are computed by adding value months
 201        /// to y and m, and d1 is the largest value less than
 202        /// or equal to d that denotes a valid day in month m1 of year
 203        /// y1.
 204        /// </summary>
 205        public abstract DateTime AddMonths(DateTime time, int months);
 206
 207        /// <summary>
 208        /// Returns the DateTime resulting from adding a number of
 209        /// seconds to the specified DateTime. The result is computed by rounding the
 210        /// fractional number of seconds given by value to the nearest
 211        /// millisecond, and adding that interval to the specified DateTime. The
 212        /// value argument is permitted to be negative.
 213        /// </summary>
 214        public virtual DateTime AddSeconds(DateTime time, int seconds)
 215        {
 0216            return Add(time, seconds, (int)TimeSpan.MillisecondsPerSecond);
 217        }
 218
 219        // Returns the DateTime resulting from adding a number of
 220        // weeks to the specified DateTime. The
 221        // value argument is permitted to be negative.
 222        public virtual DateTime AddWeeks(DateTime time, int weeks)
 223        {
 0224            return AddDays(time, weeks * 7);
 225        }
 226
 227        /// <summary>
 228        /// Returns the DateTime resulting from adding the given number of
 229        /// years to the specified DateTime. The result is computed by incrementing
 230        /// (or decrementing) the year part of the specified DateTime by value
 231        /// years. If the month and day of the specified DateTime is 2/29, and if the
 232        /// resulting year is not a leap year, the month and day of the resulting
 233        /// DateTime becomes 2/28. Otherwise, the month, day, and time-of-day
 234        /// parts of the result are the same as those of the specified DateTime.
 235        /// </summary>
 236        public abstract DateTime AddYears(DateTime time, int years);
 237
 238        /// <summary>
 239        /// Returns the day-of-month part of the specified DateTime. The returned
 240        /// value is an integer between 1 and 31.
 241        /// </summary>
 242        public abstract int GetDayOfMonth(DateTime time);
 243
 244        /// <summary>
 245        /// Returns the day-of-week part of the specified DateTime. The returned value
 246        /// is an integer between 0 and 6, where 0 indicates Sunday, 1 indicates
 247        /// Monday, 2 indicates Tuesday, 3 indicates Wednesday, 4 indicates
 248        /// Thursday, 5 indicates Friday, and 6 indicates Saturday.
 249        /// </summary>
 250        public abstract DayOfWeek GetDayOfWeek(DateTime time);
 251
 252        /// <summary>
 253        /// Returns the day-of-year part of the specified DateTime. The returned value
 254        /// is an integer between 1 and 366.
 255        /// </summary>
 256        public abstract int GetDayOfYear(DateTime time);
 257
 258        /// <summary>
 259        /// Returns the number of days in the month given by the year and
 260        /// month arguments.
 261        /// </summary>
 262        public virtual int GetDaysInMonth(int year, int month)
 263        {
 0264            return GetDaysInMonth(year, month, CurrentEra);
 265        }
 266
 267        /// <summary>
 268        /// Returns the number of days in the month given by the year and
 269        /// month arguments for the specified era.
 270        /// </summary>
 271        public abstract int GetDaysInMonth(int year, int month, int era);
 272
 273        /// <summary>
 274        /// Returns the number of days in the year given by the year argument
 275        /// for the current era.
 276        /// </summary>
 277        public virtual int GetDaysInYear(int year)
 278        {
 0279            return GetDaysInYear(year, CurrentEra);
 280        }
 281
 282        /// <summary>
 283        /// Returns the number of days in the year given by the year argument
 284        /// for the current era.
 285        /// </summary>
 286        public abstract int GetDaysInYear(int year, int era);
 287
 288        /// <summary>
 289        /// Returns the era for the specified DateTime value.
 290        /// </summary>
 291        public abstract int GetEra(DateTime time);
 292
 293        /// <summary>
 294        /// Get the list of era values.
 295        /// </summary>
 296        /// <returns>The int array of the era names supported in this calendar or null if era is not used.</returns>
 297        public abstract int[] Eras { get; }
 298
 299        // Returns the hour part of the specified DateTime. The returned value is an
 300        // integer between 0 and 23.
 0301        public virtual int GetHour(DateTime time) => time.Hour;
 302
 303        // Returns the millisecond part of the specified DateTime. The returned value
 304        // is an integer between 0 and 999.
 0305        public virtual double GetMilliseconds(DateTime time) => time.Millisecond;
 306
 307        // Returns the minute part of the specified DateTime. The returned value is
 308        // an integer between 0 and 59.
 0309        public virtual int GetMinute(DateTime time) => time.Minute;
 310
 311        // Returns the month part of the specified DateTime. The returned value is an
 312        // integer between 1 and 12.
 313        public abstract int GetMonth(DateTime time);
 314
 315        // Returns the number of months in the specified year in the current era.
 316        public virtual int GetMonthsInYear(int year)
 317        {
 0318            return GetMonthsInYear(year, CurrentEra);
 319        }
 320
 321        // Returns the number of months in the specified year and era.
 322        public abstract int GetMonthsInYear(int year, int era);
 323
 324        // Returns the second part of the specified DateTime. The returned value is
 325        // an integer between 0 and 59.
 0326        public virtual int GetSecond(DateTime time) => time.Second;
 327
 328        /// <summary>
 329        /// Get the week of year using the FirstDay rule.
 330        /// </summary>
 331        /// <remarks>
 332        ///  The CalendarWeekRule.FirstDay rule: Week 1 begins on the first day of the year.
 333        ///  Assume f is the specified firstDayOfWeek,
 334        ///  and n is the day of week for January 1 of the specified year.
 335        ///  Assign offset = n - f;
 336        ///  Case 1: offset = 0
 337        ///      E.g.
 338        ///                     f=1
 339        ///          weekday 0  1  2  3  4  5  6  0  1
 340        ///          date       1/1
 341        ///          week#      1                    2
 342        ///      then week of year = (GetDayOfYear(time) - 1) / 7 + 1
 343        ///
 344        ///  Case 2: offset &lt; 0
 345        ///      e.g.
 346        ///                     n=1   f=3
 347        ///          weekday 0  1  2  3  4  5  6  0
 348        ///          date       1/1
 349        ///          week#      1     2
 350        ///      This means that the first week actually starts 5 days before 1/1.
 351        ///      So week of year = (GetDayOfYear(time) + (7 + offset) - 1) / 7 + 1
 352        ///  Case 3: offset > 0
 353        ///      e.g.
 354        ///                  f=0   n=2
 355        ///          weekday 0  1  2  3  4  5  6  0  1  2
 356        ///          date          1/1
 357        ///          week#         1                    2
 358        ///      This means that the first week actually starts 2 days before 1/1.
 359        ///      So Week of year = (GetDayOfYear(time) + offset - 1) / 7 + 1
 360        /// </remarks>
 361        internal int GetFirstDayWeekOfYear(DateTime time, int firstDayOfWeek)
 362        {
 0363            int dayOfYear = GetDayOfYear(time) - 1;   // Make the day of year to be 0-based, so that 1/1 is day 0.
 364            // Calculate the day of week for the first day of the year.
 365            // dayOfWeek - (dayOfYear % 7) is the day of week for the first day of this year.  Note that
 366            // this value can be less than 0.  It's fine since we are making it positive again in calculating offset.
 0367            int dayForJan1 = (int)GetDayOfWeek(time) - (dayOfYear % 7);
 0368            int offset = (dayForJan1 - firstDayOfWeek + 14) % 7;
 0369            Debug.Assert(offset >= 0, "Calendar.GetFirstDayWeekOfYear(): offset >= 0");
 0370            return (dayOfYear + offset) / 7 + 1;
 371        }
 372
 373        private int GetWeekOfYearFullDays(DateTime time, int firstDayOfWeek, int fullDays)
 374        {
 375            int dayForJan1;
 376            int offset;
 377            int day;
 378
 0379            int dayOfYear = GetDayOfYear(time) - 1; // Make the day of year to be 0-based, so that 1/1 is day 0.
 380
 381            // Calculate the number of days between the first day of year (1/1) and the first day of the week.
 382            // This value will be a positive value from 0 ~ 6.  We call this value as "offset".
 383            //
 384            // If offset is 0, it means that the 1/1 is the start of the first week.
 385            //     Assume the first day of the week is Monday, it will look like this:
 386            //     Sun      Mon     Tue     Wed     Thu     Fri     Sat
 387            //     12/31    1/1     1/2     1/3     1/4     1/5     1/6
 388            //              +--> First week starts here.
 389            //
 390            // If offset is 1, it means that the first day of the week is 1 day ahead of 1/1.
 391            //     Assume the first day of the week is Monday, it will look like this:
 392            //     Sun      Mon     Tue     Wed     Thu     Fri     Sat
 393            //     1/1      1/2     1/3     1/4     1/5     1/6     1/7
 394            //              +--> First week starts here.
 395            //
 396            // If offset is 2, it means that the first day of the week is 2 days ahead of 1/1.
 397            //     Assume the first day of the week is Monday, it will look like this:
 398            //     Sat      Sun     Mon     Tue     Wed     Thu     Fri     Sat
 399            //     1/1      1/2     1/3     1/4     1/5     1/6     1/7     1/8
 400            //                      +--> First week starts here.
 401
 402            // Day of week is 0-based.
 403            // Get the day of week for 1/1.  This can be derived from the day of week of the target day.
 404            // Note that we can get a negative value.  It's ok since we are going to make it a positive value when calcu
 0405            dayForJan1 = (int)GetDayOfWeek(time) - (dayOfYear % 7);
 406
 407            // Now, calculate the offset.  Subtract the first day of week from the dayForJan1.  And make it a positive v
 0408            offset = (firstDayOfWeek - dayForJan1 + 14) % 7;
 0409            if (offset != 0 && offset >= fullDays)
 410            {
 411                // If the offset is greater than the value of fullDays, it means that
 412                // the first week of the year starts on the week where Jan/1 falls on.
 0413                offset -= 7;
 414            }
 415
 416            // Calculate the day of year for specified time by taking offset into account.
 0417            day = dayOfYear - offset;
 0418            if (day >= 0)
 419            {
 420                // If the day of year value is greater than zero, get the week of year.
 0421                return day / 7 + 1;
 422            }
 423
 424            // Otherwise, the specified time falls on the week of previous year.
 425            // Call this method again by passing the last day of previous year.
 426            // the last day of the previous year may "underflow" to no longer be a valid date time for
 427            // this calendar if we just subtract so we need the subclass to provide us with
 428            // that information
 0429            if (time <= MinSupportedDateTime.AddDays(dayOfYear))
 430            {
 0431                return GetWeekOfYearOfMinSupportedDateTime(firstDayOfWeek, fullDays);
 432            }
 433
 0434            return GetWeekOfYearFullDays(time.AddDays(-(dayOfYear + 1)), firstDayOfWeek, fullDays);
 435        }
 436
 437        private int GetWeekOfYearOfMinSupportedDateTime(int firstDayOfWeek, int minimumDaysInFirstWeek)
 438        {
 0439            int dayOfYear = GetDayOfYear(MinSupportedDateTime) - 1;  // Make the day of year to be 0-based, so that 1/1 
 0440            int dayOfWeekOfFirstOfYear = (int)GetDayOfWeek(MinSupportedDateTime) - dayOfYear % 7;
 441
 442            // Calculate the offset (how many days from the start of the year to the start of the week)
 0443            int offset = (firstDayOfWeek + 7 - dayOfWeekOfFirstOfYear) % 7;
 0444            if (offset == 0 || offset >= minimumDaysInFirstWeek)
 445            {
 446                // First of year falls in the first week of the year
 0447                return 1;
 448            }
 449
 0450            int daysInYearBeforeMinSupportedYear = DaysInYearBeforeMinSupportedYear - 1; // Make the day of year to be 0
 0451            int dayOfWeekOfFirstOfPreviousYear = dayOfWeekOfFirstOfYear - 1 - (daysInYearBeforeMinSupportedYear % 7);
 452
 453            // starting from first day of the year, how many days do you have to go forward
 454            // before getting to the first day of the week?
 0455            int daysInInitialPartialWeek = (firstDayOfWeek - dayOfWeekOfFirstOfPreviousYear + 14) % 7;
 0456            int day = daysInYearBeforeMinSupportedYear - daysInInitialPartialWeek;
 0457            if (daysInInitialPartialWeek >= minimumDaysInFirstWeek)
 458            {
 459                // If the offset is greater than the minimum Days in the first week, it means that
 460                // First of year is part of the first week of the year even though it is only a partial week
 461                // add another week
 0462                day += 7;
 463            }
 464
 0465            return day / 7 + 1;
 466        }
 467
 0468        protected virtual int DaysInYearBeforeMinSupportedYear => 365;
 469
 470        /// <summary>
 471        /// Returns the week of year for the specified DateTime. The returned value is an
 472        /// integer between 1 and 53.
 473        /// </summary>
 474        public virtual int GetWeekOfYear(DateTime time, CalendarWeekRule rule, DayOfWeek firstDayOfWeek)
 475        {
 0476            if (firstDayOfWeek < DayOfWeek.Sunday || firstDayOfWeek > DayOfWeek.Saturday)
 477            {
 0478                throw new ArgumentOutOfRangeException(
 0479                    nameof(firstDayOfWeek),
 0480                    firstDayOfWeek,
 0481                    SR.Format(SR.ArgumentOutOfRange_Range, DayOfWeek.Sunday, DayOfWeek.Saturday));
 482            }
 483
 0484            return rule switch
 0485            {
 0486                CalendarWeekRule.FirstDay => GetFirstDayWeekOfYear(time, (int)firstDayOfWeek),
 0487                CalendarWeekRule.FirstFullWeek => GetWeekOfYearFullDays(time, (int)firstDayOfWeek, 7),
 0488                CalendarWeekRule.FirstFourDayWeek => GetWeekOfYearFullDays(time, (int)firstDayOfWeek, 4),
 0489                _ => throw new ArgumentOutOfRangeException(
 0490                        nameof(rule),
 0491                        rule,
 0492                        SR.Format(SR.ArgumentOutOfRange_Range, CalendarWeekRule.FirstDay, CalendarWeekRule.FirstFourDayW
 0493            };
 494        }
 495
 496        /// <summary>
 497        /// Returns the year part of the specified DateTime. The returned value is an
 498        /// integer between 1 and 9999.
 499        /// </summary>
 500        public abstract int GetYear(DateTime time);
 501
 502        /// <summary>
 503        /// Checks whether a given day in the current era is a leap day.
 504        /// This method returns true if the date is a leap day, or false if not.
 505        /// </summary>
 506        public virtual bool IsLeapDay(int year, int month, int day)
 507        {
 0508            return IsLeapDay(year, month, day, CurrentEra);
 509        }
 510
 511        /// <summary>
 512        /// Checks whether a given day in the specified era is a leap day.
 513        /// This method returns true if the date is a leap day, or false if not.
 514        /// </summary>
 515        public abstract bool IsLeapDay(int year, int month, int day, int era);
 516
 517        /// <summary>
 518        /// Checks whether a given month in the current era is a leap month.
 519        /// This method returns true if month is a leap month, or false if not.
 520        /// </summary>
 521        public virtual bool IsLeapMonth(int year, int month)
 522        {
 0523            return IsLeapMonth(year, month, CurrentEra);
 524        }
 525
 526        /// <summary>
 527        /// Checks whether a given month in the specified era is a leap month. This method returns true if
 528        /// month is a leap month, or false if not.
 529        /// </summary>
 530        public abstract bool IsLeapMonth(int year, int month, int era);
 531
 532        /// <summary>
 533        /// Returns  the leap month in a calendar year of the current era.
 534        /// This method returns 0 if this calendar does not have leap month,
 535        /// or this year is not a leap year.
 536        /// </summary>
 537        public virtual int GetLeapMonth(int year)
 538        {
 0539            return GetLeapMonth(year, CurrentEra);
 540        }
 541
 542        /// <summary>
 543        /// Returns  the leap month in a calendar year of the specified era.
 544        /// This method returns 0 if this calendar does not have leap month,
 545        /// or this year is not a leap year.
 546        /// </summary>
 547        public virtual int GetLeapMonth(int year, int era)
 548        {
 0549            if (!IsLeapYear(year, era))
 550            {
 0551                return 0;
 552            }
 553
 0554            int monthsCount = GetMonthsInYear(year, era);
 0555            for (int month = 1; month <= monthsCount; month++)
 556            {
 0557                if (IsLeapMonth(year, month, era))
 558                {
 0559                    return month;
 560                }
 561            }
 562
 0563            return 0;
 564        }
 565
 566        /// <summary>
 567        /// Checks whether a given year in the current era is a leap year.
 568        /// This method returns true if year is a leap year, or false if not.
 569        /// </summary>
 570        public virtual bool IsLeapYear(int year)
 571        {
 0572            return IsLeapYear(year, CurrentEra);
 573        }
 574
 575        /// <summary>
 576        /// Checks whether a given year in the specified era is a leap year.
 577        /// This method returns true if year is a leap year, or false if not.
 578        /// </summary>
 579        public abstract bool IsLeapYear(int year, int era);
 580
 581        /// <summary>
 582        /// Returns the date and time converted to a DateTime value.
 583        /// Throws an exception if the n-tuple is invalid.
 584        /// </summary>
 585        public virtual DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int milliseco
 586        {
 0587            return ToDateTime(year, month, day, hour, minute, second, millisecond, CurrentEra);
 588        }
 589
 590        /// <summary>
 591        /// Returns the date and time converted to a DateTime value.
 592        /// Throws an exception if the n-tuple is invalid.
 593        /// </summary>
 594        public abstract DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisec
 595
 596        internal virtual bool TryToDateTime(int year, int month, int day, int hour, int minute, int second, int millisec
 597        {
 0598            result = DateTime.MinValue;
 599            try
 600            {
 0601                result = ToDateTime(year, month, day, hour, minute, second, millisecond, era);
 0602                return true;
 603            }
 0604            catch (ArgumentException)
 605            {
 0606                return false;
 607            }
 0608        }
 609
 610        internal virtual bool IsValidYear(int year, int era)
 611        {
 0612            return year >= GetYear(MinSupportedDateTime) && year <= GetYear(MaxSupportedDateTime);
 613        }
 614
 615        internal virtual bool IsValidMonth(int year, int month, int era)
 616        {
 0617            return IsValidYear(year, era) && month >= 1 && month <= GetMonthsInYear(year, era);
 618        }
 619
 620        internal virtual bool IsValidDay(int year, int month, int day, int era)
 621        {
 0622            return IsValidMonth(year, month, era) && day >= 1 && day <= GetDaysInMonth(year, month, era);
 623        }
 624
 625        /// <summary>
 626        /// Returns and assigns the maximum value to represent a two digit year.
 627        /// This value is the upper boundary of a 100 year range that allows a
 628        /// two digit year to be properly translated to a four digit year.
 629        /// For example, if 2049 is the upper boundary, then a two digit value of
 630        /// 30 should be interpreted as 1950 while a two digit value of 49 should
 631        /// be interpreted as 2049.  In this example, the 100 year range would be
 632        /// from 1950-2049.  See ToFourDigitYear().
 633        /// </summary>
 634        public virtual int TwoDigitYearMax
 635        {
 0636            get => _twoDigitYearMax;
 637            set
 638            {
 0639                VerifyWritable();
 0640                _twoDigitYearMax = value;
 0641            }
 642        }
 643
 644        /// <summary>
 645        /// Converts the year value to the appropriate century by using the
 646        /// TwoDigitYearMax property.  For example, if the TwoDigitYearMax value is 2049,
 647        /// then a two digit value of 50 will get converted to 1950 while a two digit
 648        /// value of 49 will get converted to 2049.
 649        /// </summary>
 650        public virtual int ToFourDigitYear(int year)
 651        {
 0652            ArgumentOutOfRangeException.ThrowIfNegative(year);
 0653            if (year < 100)
 654            {
 0655                return (TwoDigitYearMax / 100 - (year > TwoDigitYearMax % 100 ? 1 : 0)) * 100 + year;
 656            }
 657
 658            // If the year value is above 100, just return the year value.  Don't have to do
 659            // the TwoDigitYearMax comparison.
 0660            return year;
 661        }
 662
 663        /// <summary>
 664        /// Return the tick count corresponding to the given hour, minute, second.
 665        /// Will check the if the parameters are valid.
 666        /// </summary>
 667        internal static long TimeToTicks(int hour, int minute, int second, int millisecond)
 668        {
 0669            if ((uint)hour >= 24 || (uint)minute >= 60 || (uint)second >= 60)
 670            {
 0671                throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadHourMinuteSecond);
 672            }
 0673            if ((uint)millisecond >= TimeSpan.MillisecondsPerSecond)
 674            {
 0675                throw new ArgumentOutOfRangeException(
 0676                    nameof(millisecond),
 0677                    millisecond,
 0678                    SR.Format(SR.ArgumentOutOfRange_Range, 0, TimeSpan.MillisecondsPerSecond - 1));
 679            }
 680
 0681            int totalSeconds = hour * 3600 + minute * 60 + second;
 0682            return totalSeconds * TimeSpan.TicksPerSecond + millisecond * TimeSpan.TicksPerMillisecond;
 683        }
 684
 685        internal static int GetSystemTwoDigitYearSetting(CalendarId CalID, int defaultYearValue)
 686        {
 0687            int twoDigitYearMax = CalendarData.GetTwoDigitYearMax(CalID);
 0688            return twoDigitYearMax >= 0 ? twoDigitYearMax : defaultYearValue;
 689        }
 690    }
 691}
 692

Methods/Properties

.ctor()
MinSupportedDateTime()
MaxSupportedDateTime()
AlgorithmType()
ID()
BaseCalendarID()
IsReadOnly()
Clone()
ReadOnly(System.Globalization.Calendar)
VerifyWritable()
SetReadOnlyState(System.Boolean)
CurrentEraValue()
CheckAddResult(System.Int64,System.DateTime,System.DateTime)
Add(System.DateTime,System.Double,System.Int32)
AddMilliseconds(System.DateTime,System.Double)
AddDays(System.DateTime,System.Int32)
AddHours(System.DateTime,System.Int32)
AddMinutes(System.DateTime,System.Int32)
AddSeconds(System.DateTime,System.Int32)
AddWeeks(System.DateTime,System.Int32)
GetDaysInMonth(System.Int32,System.Int32)
GetDaysInYear(System.Int32)
GetHour(System.DateTime)
GetMilliseconds(System.DateTime)
GetMinute(System.DateTime)
GetMonthsInYear(System.Int32)
GetSecond(System.DateTime)
GetFirstDayWeekOfYear(System.DateTime,System.Int32)
GetWeekOfYearFullDays(System.DateTime,System.Int32,System.Int32)
GetWeekOfYearOfMinSupportedDateTime(System.Int32,System.Int32)
DaysInYearBeforeMinSupportedYear()
GetWeekOfYear(System.DateTime,System.Globalization.CalendarWeekRule,System.DayOfWeek)
IsLeapDay(System.Int32,System.Int32,System.Int32)
IsLeapMonth(System.Int32,System.Int32)
GetLeapMonth(System.Int32)
GetLeapMonth(System.Int32,System.Int32)
IsLeapYear(System.Int32)
ToDateTime(System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32)
TryToDateTime(System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.DateTime&)
IsValidYear(System.Int32,System.Int32)
IsValidMonth(System.Int32,System.Int32,System.Int32)
IsValidDay(System.Int32,System.Int32,System.Int32,System.Int32)
TwoDigitYearMax()
TwoDigitYearMax(System.Int32)
ToFourDigitYear(System.Int32)
TimeToTicks(System.Int32,System.Int32,System.Int32,System.Int32)
GetSystemTwoDigitYearSetting(System.Globalization.CalendarId,System.Int32)