3 // Copyright (c) Microsoft Corporation. All rights reserved.
6 namespace System
.Globalization
{
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.
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
{
138 // Return the Base calendar ID for calendars that didn't have defined data in calendarData
141 internal virtual int BaseCalendarID
146 // Returns the type of the calendar.
148 [System
.Runtime
.InteropServices
.ComVisible(false)]
149 public virtual CalendarAlgorithmType AlgorithmType
153 return CalendarAlgorithmType
.Unknown
;
157 ////////////////////////////////////////////////////////////////////////
161 // Detect if the object is readonly.
163 ////////////////////////////////////////////////////////////////////////
164 [System
.Runtime
.InteropServices
.ComVisible(false)]
165 public bool IsReadOnly
167 get { return (m_isReadOnly); }
170 ////////////////////////////////////////////////////////////////////////
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);
185 ////////////////////////////////////////////////////////////////////////
189 // Create a cloned readonly instance or return the input one if it is
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()
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.
226 ** The value is from calendar.nlp.
227 ============================================================================*/
229 internal virtual int CurrentEraValue
{
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
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
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.
432 ============================================================================*/
435 public abstract int[] Eras
{
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.
494 ** firstDayOfWeek the first day of week (0=Sunday, 1=Monday, ... 6=Saturday)
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
503 ** weekday 0 1 2 3 4 5 6 0 1
506 ** then week of year = (GetDayOfYear(time) - 1) / 7 + 1
508 ** Case 2: offset < 0
511 ** weekday 0 1 2 3 4 5 6 0
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
519 ** weekday 0 1 2 3 4 5 6 0 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
) {
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.
583 // Calculate the day of year for specified time by taking offset into account.
585 day
= dayOfYear
- offset
;
588 // If the day of year value is greater than zero, get the week of year.
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
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
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
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
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();
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
))
728 int monthsCount
= GetMonthsInYear(year
, era
);
729 for (int month
=1; month
<=monthsCount
; month
++)
731 if (IsLeapMonth(year
, month
, era
))
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
;
769 result
= ToDateTime(year
, month
, day
, hour
, minute
, second
, millisecond
, era
);
772 catch (ArgumentException
) {
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
);
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
) {
819 throw new ArgumentOutOfRangeException("year",
820 Environment
.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
822 Contract
.EndContractBlock();
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.
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(
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
);