Updates referencesource to .NET 4.7
[mono-project.git] / mcs / class / referencesource / mscorlib / system / globalization / calendar.cs
blob9b0ca90b55f8861676ca4dfbbdc8919ddcaf38e2
1 // ==++==
2 //
3 // Copyright (c) Microsoft Corporation. All rights reserved.
4 //
5 // ==--==
6 namespace System.Globalization {
7 using System;
8 using System.Runtime.CompilerServices;
9 using System.Globalization;
10 using System.Runtime.Versioning;
11 using System.Diagnostics.Contracts;
13 // This abstract class represents a calendar. A calendar reckons time in
14 // divisions such as weeks, months and years. The number, length and start of
15 // the divisions vary in each calendar.
17 // Any instant in time can be represented as an n-tuple of numeric values using
18 // a particular calendar. For example, the next vernal equinox occurs at (0.0, 0
19 // , 46, 8, 20, 3, 1999) in the Gregorian calendar. An implementation of
20 // Calendar can map any DateTime value to such an n-tuple and vice versa. The
21 // DateTimeFormat class can map between such n-tuples and a textual
22 // representation such as "8:46 AM Microsoft 20th 1999 AD".
24 // Most calendars identify a year which begins the current era. There may be any
25 // number of previous eras. The Calendar class identifies the eras as enumerated
26 // integers where the current era (CurrentEra) has the value zero.
28 // For consistency, the first unit in each interval, e.g. the first month, is
29 // assigned the value one.
30 // The calculation of hour/minute/second is moved to Calendar from GregorianCalendar,
31 // since most of the calendars (or all?) have the same way of calcuating hour/minute/second.
33 [Serializable]
34 [System.Runtime.InteropServices.ComVisible(true)]
35 public abstract class Calendar : ICloneable
38 // Number of 100ns (10E-7 second) ticks per time unit
39 internal const long TicksPerMillisecond = 10000;
40 internal const long TicksPerSecond = TicksPerMillisecond * 1000;
41 internal const long TicksPerMinute = TicksPerSecond * 60;
42 internal const long TicksPerHour = TicksPerMinute * 60;
43 internal const long TicksPerDay = TicksPerHour * 24;
45 // Number of milliseconds per time unit
46 internal const int MillisPerSecond = 1000;
47 internal const int MillisPerMinute = MillisPerSecond * 60;
48 internal const int MillisPerHour = MillisPerMinute * 60;
49 internal const int MillisPerDay = MillisPerHour * 24;
51 // Number of days in a non-leap year
52 internal const int DaysPerYear = 365;
53 // Number of days in 4 years
54 internal const int DaysPer4Years = DaysPerYear * 4 + 1;
55 // Number of days in 100 years
56 internal const int DaysPer100Years = DaysPer4Years * 25 - 1;
57 // Number of days in 400 years
58 internal const int DaysPer400Years = DaysPer100Years * 4 + 1;
60 // Number of days from 1/1/0001 to 1/1/10000
61 internal const int DaysTo10000 = DaysPer400Years * 25 - 366;
63 internal const long MaxMillis = (long)DaysTo10000 * MillisPerDay;
66 // Calendar ID Values. This is used to get data from calendar.nlp.
67 // The order of calendar ID means the order of data items in the table.
70 internal const int CAL_GREGORIAN = 1 ; // Gregorian (localized) calendar
71 internal const int CAL_GREGORIAN_US = 2 ; // Gregorian (U.S.) calendar
72 internal const int CAL_JAPAN = 3 ; // Japanese Emperor Era calendar
73 internal const int CAL_TAIWAN = 4 ; // Taiwan Era calendar
74 internal const int CAL_KOREA = 5 ; // Korean Tangun Era calendar
75 internal const int CAL_HIJRI = 6 ; // Hijri (Arabic Lunar) calendar
76 internal const int CAL_THAI = 7 ; // Thai calendar
77 internal const int CAL_HEBREW = 8 ; // Hebrew (Lunar) calendar
78 internal const int CAL_GREGORIAN_ME_FRENCH = 9 ; // Gregorian Middle East French calendar
79 internal const int CAL_GREGORIAN_ARABIC = 10; // Gregorian Arabic calendar
80 internal const int CAL_GREGORIAN_XLIT_ENGLISH = 11; // Gregorian Transliterated English calendar
81 internal const int CAL_GREGORIAN_XLIT_FRENCH = 12;
82 internal const int CAL_JULIAN = 13;
83 internal const int CAL_JAPANESELUNISOLAR = 14;
84 internal const int CAL_CHINESELUNISOLAR = 15;
85 internal const int CAL_SAKA = 16; // reserved to match Office but not implemented in our code
86 internal const int CAL_LUNAR_ETO_CHN = 17; // reserved to match Office but not implemented in our code
87 internal const int CAL_LUNAR_ETO_KOR = 18; // reserved to match Office but not implemented in our code
88 internal const int CAL_LUNAR_ETO_ROKUYOU = 19; // reserved to match Office but not implemented in our code
89 internal const int CAL_KOREANLUNISOLAR = 20;
90 internal const int CAL_TAIWANLUNISOLAR = 21;
91 internal const int CAL_PERSIAN = 22;
92 internal const int CAL_UMALQURA = 23;
94 internal int m_currentEraValue = -1;
96 [System.Runtime.Serialization.OptionalField(VersionAdded = 2)]
97 private bool m_isReadOnly = false;
99 // The minimum supported DateTime range for the calendar.
101 [System.Runtime.InteropServices.ComVisible(false)]
102 public virtual DateTime MinSupportedDateTime
106 return (DateTime.MinValue);
110 // The maximum supported DateTime range for the calendar.
112 [System.Runtime.InteropServices.ComVisible(false)]
113 public virtual DateTime MaxSupportedDateTime
117 return (DateTime.MaxValue);
124 protected Calendar() {
125 //Do-nothing constructor.
129 // This can not be abstract, otherwise no one can create a subclass of Calendar.
131 internal virtual int ID {
132 get {
133 return (-1);
138 // Return the Base calendar ID for calendars that didn't have defined data in calendarData
141 internal virtual int BaseCalendarID
143 get { return ID; }
146 // Returns the type of the calendar.
148 [System.Runtime.InteropServices.ComVisible(false)]
149 public virtual CalendarAlgorithmType AlgorithmType
153 return CalendarAlgorithmType.Unknown;
157 ////////////////////////////////////////////////////////////////////////
159 // IsReadOnly
161 // Detect if the object is readonly.
163 ////////////////////////////////////////////////////////////////////////
164 [System.Runtime.InteropServices.ComVisible(false)]
165 public bool IsReadOnly
167 get { return (m_isReadOnly); }
170 ////////////////////////////////////////////////////////////////////////
172 // Clone
174 // Is the implementation of IColnable.
176 ////////////////////////////////////////////////////////////////////////
177 [System.Runtime.InteropServices.ComVisible(false)]
178 public virtual Object Clone()
180 object o = MemberwiseClone();
181 ((Calendar) o).SetReadOnlyState(false);
182 return (o);
185 ////////////////////////////////////////////////////////////////////////
187 // ReadOnly
189 // Create a cloned readonly instance or return the input one if it is
190 // readonly.
192 ////////////////////////////////////////////////////////////////////////
193 [System.Runtime.InteropServices.ComVisible(false)]
194 public static Calendar ReadOnly(Calendar calendar)
196 if (calendar == null) { throw new ArgumentNullException("calendar"); }
197 Contract.EndContractBlock();
198 if (calendar.IsReadOnly) { return (calendar); }
200 Calendar clonedCalendar = (Calendar)(calendar.MemberwiseClone());
201 clonedCalendar.SetReadOnlyState(true);
203 return (clonedCalendar);
206 internal void VerifyWritable()
208 if (m_isReadOnly)
210 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ReadOnly"));
214 internal void SetReadOnlyState(bool readOnly)
216 m_isReadOnly = readOnly;
220 /*=================================CurrentEraValue==========================
221 **Action: This is used to convert CurretEra(0) to an appropriate era value.
222 **Returns:
223 **Arguments:
224 **Exceptions:
225 **Notes:
226 ** The value is from calendar.nlp.
227 ============================================================================*/
229 internal virtual int CurrentEraValue {
230 get {
231 // The following code assumes that the current era value can not be -1.
232 if (m_currentEraValue == -1) {
233 Contract.Assert(BaseCalendarID > 0, "[Calendar.CurrentEraValue] Expected ID > 0");
234 m_currentEraValue = CalendarData.GetCalendarData(BaseCalendarID).iCurrentEra;
236 return (m_currentEraValue);
240 // The current era for a calendar.
242 public const int CurrentEra = 0;
244 internal int twoDigitYearMax = -1;
246 internal static void CheckAddResult(long ticks, DateTime minValue, DateTime maxValue) {
247 if (ticks < minValue.Ticks || ticks > maxValue.Ticks) {
248 throw new ArgumentException(
249 String.Format(CultureInfo.InvariantCulture, Environment.GetResourceString("Argument_ResultCalendarRange"),
250 minValue, maxValue));
252 Contract.EndContractBlock();
255 internal DateTime Add(DateTime time, double value, int scale) {
256 // From ECMA CLI spec, Partition III, section 3.27:
258 // If overflow occurs converting a floating-point type to an integer, or if the floating-point value
259 // being converted to an integer is a NaN, the value returned is unspecified.
261 // Based upon this, this method should be performing the comparison against the double
262 // before attempting a cast. Otherwise, the result is undefined.
263 double tempMillis = (value * scale + (value >= 0 ? 0.5 : -0.5));
264 if (!((tempMillis > -(double)MaxMillis) && (tempMillis < (double)MaxMillis)))
266 throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_AddValue"));
269 long millis = (long)tempMillis;
270 long ticks = time.Ticks + millis * TicksPerMillisecond;
271 CheckAddResult(ticks, MinSupportedDateTime, MaxSupportedDateTime);
272 return (new DateTime(ticks));
275 // Returns the DateTime resulting from adding the given number of
276 // milliseconds to the specified DateTime. The result is computed by rounding
277 // the number of milliseconds given by value to the nearest integer,
278 // and adding that interval to the specified DateTime. The value
279 // argument is permitted to be negative.
282 public virtual DateTime AddMilliseconds(DateTime time, double milliseconds) {
283 return (Add(time, milliseconds, 1));
287 // Returns the DateTime resulting from adding a fractional number of
288 // days to the specified DateTime. The result is computed by rounding the
289 // fractional number of days given by value to the nearest
290 // millisecond, and adding that interval to the specified DateTime. The
291 // value argument is permitted to be negative.
294 public virtual DateTime AddDays(DateTime time, int days) {
295 return (Add(time, days, MillisPerDay));
298 // Returns the DateTime resulting from adding a fractional number of
299 // hours to the specified DateTime. The result is computed by rounding the
300 // fractional number of hours given by value to the nearest
301 // millisecond, and adding that interval to the specified DateTime. The
302 // value argument is permitted to be negative.
305 public virtual DateTime AddHours(DateTime time, int hours) {
306 return (Add(time, hours, MillisPerHour));
310 // Returns the DateTime resulting from adding a fractional number of
311 // minutes to the specified DateTime. The result is computed by rounding the
312 // fractional number of minutes given by value to the nearest
313 // millisecond, and adding that interval to the specified DateTime. The
314 // value argument is permitted to be negative.
317 public virtual DateTime AddMinutes(DateTime time, int minutes) {
318 return (Add(time, minutes, MillisPerMinute));
322 // Returns the DateTime resulting from adding the given number of
323 // months to the specified DateTime. The result is computed by incrementing
324 // (or decrementing) the year and month parts of the specified DateTime by
325 // value months, and, if required, adjusting the day part of the
326 // resulting date downwards to the last day of the resulting month in the
327 // resulting year. The time-of-day part of the result is the same as the
328 // time-of-day part of the specified DateTime.
330 // In more precise terms, considering the specified DateTime to be of the
331 // form y / m / d + t, where y is the
332 // year, m is the month, d is the day, and t is the
333 // time-of-day, the result is y1 / m1 / d1 + t,
334 // where y1 and m1 are computed by adding value months
335 // to y and m, and d1 is the largest value less than
336 // or equal to d that denotes a valid day in month m1 of year
337 // y1.
340 public abstract DateTime AddMonths(DateTime time, int months);
342 // Returns the DateTime resulting from adding a number of
343 // seconds to the specified DateTime. The result is computed by rounding the
344 // fractional number of seconds given by value to the nearest
345 // millisecond, and adding that interval to the specified DateTime. The
346 // value argument is permitted to be negative.
349 public virtual DateTime AddSeconds(DateTime time, int seconds) {
350 return Add(time, seconds, MillisPerSecond);
353 // Returns the DateTime resulting from adding a number of
354 // weeks to the specified DateTime. The
355 // value argument is permitted to be negative.
358 public virtual DateTime AddWeeks(DateTime time, int weeks) {
359 return (AddDays(time, weeks * 7));
363 // Returns the DateTime resulting from adding the given number of
364 // years to the specified DateTime. The result is computed by incrementing
365 // (or decrementing) the year part of the specified DateTime by value
366 // years. If the month and day of the specified DateTime is 2/29, and if the
367 // resulting year is not a leap year, the month and day of the resulting
368 // DateTime becomes 2/28. Otherwise, the month, day, and time-of-day
369 // parts of the result are the same as those of the specified DateTime.
372 public abstract DateTime AddYears(DateTime time, int years);
374 // Returns the day-of-month part of the specified DateTime. The returned
375 // value is an integer between 1 and 31.
378 public abstract int GetDayOfMonth(DateTime time);
380 // Returns the day-of-week part of the specified DateTime. The returned value
381 // is an integer between 0 and 6, where 0 indicates Sunday, 1 indicates
382 // Monday, 2 indicates Tuesday, 3 indicates Wednesday, 4 indicates
383 // Thursday, 5 indicates Friday, and 6 indicates Saturday.
386 public abstract DayOfWeek GetDayOfWeek(DateTime time);
388 // Returns the day-of-year part of the specified DateTime. The returned value
389 // is an integer between 1 and 366.
392 public abstract int GetDayOfYear(DateTime time);
394 // Returns the number of days in the month given by the year and
395 // month arguments.
398 public virtual int GetDaysInMonth(int year, int month)
400 return (GetDaysInMonth(year, month, CurrentEra));
403 // Returns the number of days in the month given by the year and
404 // month arguments for the specified era.
407 public abstract int GetDaysInMonth(int year, int month, int era);
409 // Returns the number of days in the year given by the year argument for the current era.
412 public virtual int GetDaysInYear(int year)
414 return (GetDaysInYear(year, CurrentEra));
417 // Returns the number of days in the year given by the year argument for the current era.
420 public abstract int GetDaysInYear(int year, int era);
422 // Returns the era for the specified DateTime value.
424 public abstract int GetEra(DateTime time);
426 /*=================================Eras==========================
427 **Action: Get the list of era values.
428 **Returns: The int array of the era names supported in this calendar.
429 ** null if era is not used.
430 **Arguments: None.
431 **Exceptions: None.
432 ============================================================================*/
435 public abstract int[] Eras {
436 get;
440 // Returns the hour part of the specified DateTime. The returned value is an
441 // integer between 0 and 23.
444 public virtual int GetHour(DateTime time) {
445 return ((int)((time.Ticks / TicksPerHour) % 24));
448 // Returns the millisecond part of the specified DateTime. The returned value
449 // is an integer between 0 and 999.
452 public virtual double GetMilliseconds(DateTime time) {
453 return (double)((time.Ticks / TicksPerMillisecond) % 1000);
456 // Returns the minute part of the specified DateTime. The returned value is
457 // an integer between 0 and 59.
460 public virtual int GetMinute(DateTime time) {
461 return ((int)((time.Ticks / TicksPerMinute) % 60));
464 // Returns the month part of the specified DateTime. The returned value is an
465 // integer between 1 and 12.
468 public abstract int GetMonth(DateTime time);
470 // Returns the number of months in the specified year in the current era.
472 public virtual int GetMonthsInYear(int year)
474 return (GetMonthsInYear(year, CurrentEra));
477 // Returns the number of months in the specified year and era.
479 public abstract int GetMonthsInYear(int year, int era);
481 // Returns the second part of the specified DateTime. The returned value is
482 // an integer between 0 and 59.
485 public virtual int GetSecond(DateTime time) {
486 return ((int)((time.Ticks / TicksPerSecond) % 60));
489 /*=================================GetFirstDayWeekOfYear==========================
490 **Action: Get the week of year using the FirstDay rule.
491 **Returns: the week of year.
492 **Arguments:
493 ** time
494 ** firstDayOfWeek the first day of week (0=Sunday, 1=Monday, ... 6=Saturday)
495 **Notes:
496 ** The CalendarWeekRule.FirstDay rule: Week 1 begins on the first day of the year.
497 ** Assume f is the specifed firstDayOfWeek,
498 ** and n is the day of week for January 1 of the specified year.
499 ** Assign offset = n - f;
500 ** Case 1: offset = 0
501 ** E.g.
502 ** f=1
503 ** weekday 0 1 2 3 4 5 6 0 1
504 ** date 1/1
505 ** week# 1 2
506 ** then week of year = (GetDayOfYear(time) - 1) / 7 + 1
508 ** Case 2: offset < 0
509 ** e.g.
510 ** n=1 f=3
511 ** weekday 0 1 2 3 4 5 6 0
512 ** date 1/1
513 ** week# 1 2
514 ** This means that the first week actually starts 5 days before 1/1.
515 ** So week of year = (GetDayOfYear(time) + (7 + offset) - 1) / 7 + 1
516 ** Case 3: offset > 0
517 ** e.g.
518 ** f=0 n=2
519 ** weekday 0 1 2 3 4 5 6 0 1 2
520 ** date 1/1
521 ** week# 1 2
522 ** This means that the first week actually starts 2 days before 1/1.
523 ** So Week of year = (GetDayOfYear(time) + offset - 1) / 7 + 1
524 ============================================================================*/
526 internal int GetFirstDayWeekOfYear(DateTime time, int firstDayOfWeek) {
527 int dayOfYear = GetDayOfYear(time) - 1; // Make the day of year to be 0-based, so that 1/1 is day 0.
528 // Calculate the day of week for the first day of the year.
529 // dayOfWeek - (dayOfYear % 7) is the day of week for the first day of this year. Note that
530 // this value can be less than 0. It's fine since we are making it positive again in calculating offset.
531 int dayForJan1 = (int)GetDayOfWeek(time) - (dayOfYear % 7);
532 int offset = (dayForJan1 - firstDayOfWeek + 14) % 7;
533 Contract.Assert(offset >= 0, "Calendar.GetFirstDayWeekOfYear(): offset >= 0");
534 return ((dayOfYear + offset) / 7 + 1);
537 private int GetWeekOfYearFullDays(DateTime time, int firstDayOfWeek, int fullDays) {
538 int dayForJan1;
539 int offset;
540 int day;
542 int dayOfYear = GetDayOfYear(time) - 1; // Make the day of year to be 0-based, so that 1/1 is day 0.
544 // Calculate the number of days between the first day of year (1/1) and the first day of the week.
545 // This value will be a positive value from 0 ~ 6. We call this value as "offset".
547 // If offset is 0, it means that the 1/1 is the start of the first week.
548 // Assume the first day of the week is Monday, it will look like this:
549 // Sun Mon Tue Wed Thu Fri Sat
550 // 12/31 1/1 1/2 1/3 1/4 1/5 1/6
551 // +--> First week starts here.
553 // If offset is 1, it means that the first day of the week is 1 day ahead of 1/1.
554 // Assume the first day of the week is Monday, it will look like this:
555 // Sun Mon Tue Wed Thu Fri Sat
556 // 1/1 1/2 1/3 1/4 1/5 1/6 1/7
557 // +--> First week starts here.
559 // If offset is 2, it means that the first day of the week is 2 days ahead of 1/1.
560 // Assume the first day of the week is Monday, it will look like this:
561 // Sat Sun Mon Tue Wed Thu Fri Sat
562 // 1/1 1/2 1/3 1/4 1/5 1/6 1/7 1/8
563 // +--> First week starts here.
567 // Day of week is 0-based.
568 // Get the day of week for 1/1. This can be derived from the day of week of the target day.
569 // Note that we can get a negative value. It's ok since we are going to make it a positive value when calculating the offset.
570 dayForJan1 = (int)GetDayOfWeek(time) - (dayOfYear % 7);
572 // Now, calculate the offset. Subtract the first day of week from the dayForJan1. And make it a positive value.
573 offset = (firstDayOfWeek - dayForJan1 + 14) % 7;
574 if (offset != 0 && offset >= fullDays)
577 // If the offset is greater than the value of fullDays, it means that
578 // the first week of the year starts on the week where Jan/1 falls on.
580 offset -= 7;
583 // Calculate the day of year for specified time by taking offset into account.
585 day = dayOfYear - offset;
586 if (day >= 0) {
588 // If the day of year value is greater than zero, get the week of year.
590 return (day/7 + 1);
593 // Otherwise, the specified time falls on the week of previous year.
594 // Call this method again by passing the last day of previous year.
596 // the last day of the previous year may "underflow" to no longer be a valid date time for
597 // this calendar if we just subtract so we need the subclass to provide us with
598 // that information
599 if (time <= MinSupportedDateTime.AddDays(dayOfYear))
601 return GetWeekOfYearOfMinSupportedDateTime(firstDayOfWeek, fullDays);
603 return (GetWeekOfYearFullDays(time.AddDays(-(dayOfYear + 1)), firstDayOfWeek, fullDays));
606 private int GetWeekOfYearOfMinSupportedDateTime(int firstDayOfWeek, int minimumDaysInFirstWeek)
608 int dayOfYear = GetDayOfYear(MinSupportedDateTime) - 1; // Make the day of year to be 0-based, so that 1/1 is day 0.
609 int dayOfWeekOfFirstOfYear = (int)GetDayOfWeek(MinSupportedDateTime) - dayOfYear % 7;
611 // Calculate the offset (how many days from the start of the year to the start of the week)
612 int offset = (firstDayOfWeek + 7 - dayOfWeekOfFirstOfYear) % 7;
613 if (offset == 0 || offset >= minimumDaysInFirstWeek)
615 // First of year falls in the first week of the year
616 return 1;
619 int daysInYearBeforeMinSupportedYear = DaysInYearBeforeMinSupportedYear - 1; // Make the day of year to be 0-based, so that 1/1 is day 0.
620 int dayOfWeekOfFirstOfPreviousYear = dayOfWeekOfFirstOfYear - 1 - (daysInYearBeforeMinSupportedYear % 7);
622 // starting from first day of the year, how many days do you have to go forward
623 // before getting to the first day of the week?
624 int daysInInitialPartialWeek = (firstDayOfWeek - dayOfWeekOfFirstOfPreviousYear + 14) % 7;
625 int day = daysInYearBeforeMinSupportedYear - daysInInitialPartialWeek;
626 if (daysInInitialPartialWeek >= minimumDaysInFirstWeek)
628 // If the offset is greater than the minimum Days in the first week, it means that
629 // First of year is part of the first week of the year even though it is only a partial week
630 // add another week
631 day += 7;
634 return (day / 7 + 1);
637 // it would be nice to make this abstract but we can't since that would break previous implementations
638 protected virtual int DaysInYearBeforeMinSupportedYear
642 return 365;
647 // Returns the week of year for the specified DateTime. The returned value is an
648 // integer between 1 and 53.
651 public virtual int GetWeekOfYear(DateTime time, CalendarWeekRule rule, DayOfWeek firstDayOfWeek)
653 if ((int)firstDayOfWeek < 0 || (int)firstDayOfWeek > 6) {
654 throw new ArgumentOutOfRangeException(
655 "firstDayOfWeek", Environment.GetResourceString("ArgumentOutOfRange_Range",
656 DayOfWeek.Sunday, DayOfWeek.Saturday));
658 Contract.EndContractBlock();
659 switch (rule) {
660 case CalendarWeekRule.FirstDay:
661 return (GetFirstDayWeekOfYear(time, (int)firstDayOfWeek));
662 case CalendarWeekRule.FirstFullWeek:
663 return (GetWeekOfYearFullDays(time, (int)firstDayOfWeek, 7));
664 case CalendarWeekRule.FirstFourDayWeek:
665 return (GetWeekOfYearFullDays(time, (int)firstDayOfWeek, 4));
667 throw new ArgumentOutOfRangeException(
668 "rule", Environment.GetResourceString("ArgumentOutOfRange_Range",
669 CalendarWeekRule.FirstDay, CalendarWeekRule.FirstFourDayWeek));
673 // Returns the year part of the specified DateTime. The returned value is an
674 // integer between 1 and 9999.
677 public abstract int GetYear(DateTime time);
679 // Checks whether a given day in the current era is a leap day. This method returns true if
680 // the date is a leap day, or false if not.
683 public virtual bool IsLeapDay(int year, int month, int day)
685 return (IsLeapDay(year, month, day, CurrentEra));
688 // Checks whether a given day in the specified era is a leap day. This method returns true if
689 // the date is a leap day, or false if not.
692 public abstract bool IsLeapDay(int year, int month, int day, int era);
694 // Checks whether a given month in the current era is a leap month. This method returns true if
695 // month is a leap month, or false if not.
698 public virtual bool IsLeapMonth(int year, int month) {
699 return (IsLeapMonth(year, month, CurrentEra));
702 // Checks whether a given month in the specified era is a leap month. This method returns true if
703 // month is a leap month, or false if not.
706 public abstract bool IsLeapMonth(int year, int month, int era);
708 // Returns the leap month in a calendar year of the current era. This method returns 0
709 // if this calendar does not have leap month, or this year is not a leap year.
712 [System.Runtime.InteropServices.ComVisible(false)]
713 public virtual int GetLeapMonth(int year)
715 return (GetLeapMonth(year, CurrentEra));
718 // Returns the leap month in a calendar year of the specified era. This method returns 0
719 // if this calendar does not have leap month, or this year is not a leap year.
722 [System.Runtime.InteropServices.ComVisible(false)]
723 public virtual int GetLeapMonth(int year, int era)
725 if (!IsLeapYear(year, era))
726 return 0;
728 int monthsCount = GetMonthsInYear(year, era);
729 for (int month=1; month<=monthsCount; month++)
731 if (IsLeapMonth(year, month, era))
732 return month;
735 return 0;
738 // Checks whether a given year in the current era is a leap year. This method returns true if
739 // year is a leap year, or false if not.
742 public virtual bool IsLeapYear(int year)
744 return (IsLeapYear(year, CurrentEra));
747 // Checks whether a given year in the specified era is a leap year. This method returns true if
748 // year is a leap year, or false if not.
751 public abstract bool IsLeapYear(int year, int era);
753 // Returns the date and time converted to a DateTime value. Throws an exception if the n-tuple is invalid.
756 public virtual DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond)
758 return (ToDateTime(year, month, day, hour, minute, second, millisecond, CurrentEra));
761 // Returns the date and time converted to a DateTime value. Throws an exception if the n-tuple is invalid.
764 public abstract DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era);
766 internal virtual Boolean TryToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era, out DateTime result) {
767 result = DateTime.MinValue;
768 try {
769 result = ToDateTime(year, month, day, hour, minute, second, millisecond, era);
770 return true;
772 catch (ArgumentException) {
773 return false;
777 internal virtual bool IsValidYear(int year, int era) {
778 return (year >= GetYear(MinSupportedDateTime) && year <= GetYear(MaxSupportedDateTime));
781 internal virtual bool IsValidMonth(int year, int month, int era) {
782 return (IsValidYear(year, era) && month >= 1 && month <= GetMonthsInYear(year, era));
785 internal virtual bool IsValidDay(int year, int month, int day, int era)
787 return (IsValidMonth(year, month, era) && day >= 1 && day <= GetDaysInMonth(year, month, era));
791 // Returns and assigns the maximum value to represent a two digit year. This
792 // value is the upper boundary of a 100 year range that allows a two digit year
793 // to be properly translated to a four digit year. For example, if 2029 is the
794 // upper boundary, then a two digit value of 30 should be interpreted as 1930
795 // while a two digit value of 29 should be interpreted as 2029. In this example
796 // , the 100 year range would be from 1930-2029. See ToFourDigitYear().
798 public virtual int TwoDigitYearMax
802 return (twoDigitYearMax);
807 VerifyWritable();
808 twoDigitYearMax = value;
812 // Converts the year value to the appropriate century by using the
813 // TwoDigitYearMax property. For example, if the TwoDigitYearMax value is 2029,
814 // then a two digit value of 30 will get converted to 1930 while a two digit
815 // value of 29 will get converted to 2029.
817 public virtual int ToFourDigitYear(int year) {
818 if (year < 0) {
819 throw new ArgumentOutOfRangeException("year",
820 Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
822 Contract.EndContractBlock();
823 if (year < 100) {
824 return ((TwoDigitYearMax/100 - ( year > TwoDigitYearMax % 100 ? 1 : 0))*100 + year);
826 // If the year value is above 100, just return the year value. Don't have to do
827 // the TwoDigitYearMax comparison.
828 return (year);
831 // Return the tick count corresponding to the given hour, minute, second.
832 // Will check the if the parameters are valid.
833 internal static long TimeToTicks(int hour, int minute, int second, int millisecond)
835 if (hour >= 0 && hour < 24 && minute >= 0 && minute < 60 && second >=0 && second < 60)
837 if (millisecond < 0 || millisecond >= MillisPerSecond) {
838 throw new ArgumentOutOfRangeException(
839 "millisecond",
840 String.Format(
841 CultureInfo.InvariantCulture,
842 Environment.GetResourceString("ArgumentOutOfRange_Range"), 0, MillisPerSecond - 1));
844 return TimeSpan.TimeToTicks(hour, minute, second) + millisecond * TicksPerMillisecond;
846 throw new ArgumentOutOfRangeException(null, Environment.GetResourceString("ArgumentOutOfRange_BadHourMinuteSecond"));
849 [System.Security.SecuritySafeCritical] // auto-generated
850 [ResourceExposure(ResourceScope.None)]
851 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
852 internal static int GetSystemTwoDigitYearSetting(int CalID, int defaultYearValue)
854 // Call nativeGetTwoDigitYearMax
855 int twoDigitYearMax = CalendarData.nativeGetTwoDigitYearMax(CalID);
856 if (twoDigitYearMax < 0)
858 twoDigitYearMax = defaultYearValue;
860 return (twoDigitYearMax);