3 // (C) Ulrich Kunitz 2002
6 namespace System.Globalization {
12 /// The class serves as a base class for calendar classes.
15 public abstract class Calendar {
16 /// <value>An protected integer property that gives the number of
17 /// days in a week. It might be overridden.</value>
18 protected virtual int M_DaysInWeek
24 /// The protected method creates the string used in the
25 /// <see cref="T:System.ArgumentOutOfRangeException"/>
27 /// <param name="a">An object that represents the smallest
28 /// allowable value.</param>
29 /// <param name="b">An object that represents the greatest allowable
31 /// <returns>The string used in the
32 /// <see cref="T:System.ArgumentOutOfRangeException"/>
34 protected string M_ValidValues(object a, object b)
36 StringWriter sw = new StringWriter();
37 sw.Write("Valid values are between {0} and {1}, inclusive.",
43 /// The protected method checks wether the parameter
44 /// <paramref name="arg"/> is in the allowed range.
46 /// <param name="param">A string that gives the name of the
47 /// parameter to check.</param>
48 /// <param name="arg">An integer that gives the value to check.
50 /// <param name="a">An integer that represents the smallest allowed
52 /// <param name="b">An integer that represents the greatest allowed
54 /// <exception cref="T:System.ArgumentOutOfRangeException">
55 /// The exception is thrown, if the <paramref name="arg"/> is outside
56 /// the allowed range.
58 protected void M_ArgumentInRange(string param, int arg, int a, int b)
60 if (a <= arg && arg <= b)
62 throw new ArgumentOutOfRangeException(param, M_ValidValues(a, b));
66 /// The protected method, that checks whether
67 /// <paramref name="hour"/>, <paramref name="minute"/>,
68 /// <paramref name="second"/>, and <parameref name="millisecond"/>
69 /// are in their valid ranges
71 /// <param name="hour">An integer that represents a hour,
72 /// should be between 0 and 23.</param>
73 /// <param name="minute">An integer that represents a minute,
74 /// should be between 0 and 59.</param>
75 /// <param name="second">An integer that represents a second,
76 /// should be between 0 and 59.</param>
77 /// <param name="milliseconds">An integer that represents a number
78 /// of milliseconds, should be between 0 and 999999.</param>
79 /// <exception cref="T:System.ArgumentOutOfRangeException">
80 /// The Exception is thrown, if one of the parameter is outside the
81 /// allowed the range.
83 protected void M_CheckHMSM(int hour, int minute, int second,
86 M_ArgumentInRange("hour", hour, 0, 23);
87 M_ArgumentInRange("minute", minute, 0, 59);
88 M_ArgumentInRange("second", second, 0, 59);
89 M_ArgumentInRange("milliseconds", milliseconds, 0, 999999);
93 /// A represantation of the CurrentEra.
95 public const int CurrentEra = 0;
97 /// <value>When overridden gives the eras supported by the
98 /// calendar as an array of integers.
100 public abstract int[] Eras { get; }
103 /// The protected member stores the value for the
104 /// <see cref="P:TwoDigitYearMax"/>
107 protected int M_TwoDigitYearMax;
111 /// Private field containing the maximum year for the calendar.
113 private int M_MaxYearValue = 0;
116 /// Get-only property returing the maximum allowed year for this
119 protected virtual int M_MaxYear {
121 if (M_MaxYearValue == 0) {
122 M_MaxYearValue = GetYear(DateTime.MaxValue);
124 return M_MaxYearValue;
129 /// Checks whether the year is the era is valid, if era = CurrentEra
130 /// the right value is set.
132 /// <param name="year">The year to check.</param>
133 /// <param name="era">The era to check.</Param>
134 /// <exception cref="T:ArgumentOutOfRangeException">
135 /// The exception will be thrown, if the year is not valid.
137 protected abstract void M_CheckYE(int year, ref int era);
140 /// <para>The property gives the maximum value for years with two
141 /// digits. If the property has the value 2029, than the two-digit
142 /// integer 29 results in the year 2029 and 30 in the
143 /// year 1930.</para>
144 /// <para>It might be overridden.</para>
146 public virtual int TwoDigitYearMax {
147 get { return M_TwoDigitYearMax; }
149 M_ArgumentInRange("year", value, 100, M_MaxYear);
150 int era = CurrentEra;
151 M_CheckYE(value, ref era);
152 M_TwoDigitYearMax = value;
157 /// The virtual method adds days to a given date.
159 /// <param name="time">The
160 /// <see cref="T:System.DateTime"/> to which to add
163 /// <param name="days">The number of days to add.</param>
164 /// <returns>A new <see cref="T:System.DateTime"/> value, that
165 /// results from adding <paramref name="days"/> to the specified
166 /// DateTime.</returns>
167 public virtual DateTime AddDays(DateTime time, int days) {
168 return time.Add(TimeSpan.FromDays(days));
172 /// The virtual method adds hours to a given date.
174 /// <param name="time">The
175 /// <see cref="T:System.DateTime"/> to which to add
178 /// <param name="hours">The number of hours to add.</param>
179 /// <returns>A new <see cref="T:System.DateTime"/> value, that
180 /// results from adding <paramref name="hours"/> to the specified
181 /// DateTime.</returns>
182 public virtual DateTime AddHours(DateTime time, int hours) {
183 return time.Add(TimeSpan.FromHours(hours));
187 /// The virtual method adds milliseconds to a given date.
189 /// <param name="time">The
190 /// <see cref="T:System.DateTime"/> to which to add
193 /// <param name="milliseconds">The number of milliseconds given as
194 /// double to add. Keep in mind the 100 nanosecond resolution of
195 /// <see cref="T:System.DateTime"/>.
197 /// <returns>A new <see cref="T:System.DateTime"/> value, that
198 /// results from adding <paramref name="milliseconds"/> to the specified
199 /// DateTime.</returns>
200 public virtual DateTime AddMilliseconds(DateTime time,
203 return time.Add(TimeSpan.FromMilliseconds(milliseconds));
207 /// The virtual method adds minutes to a given date.
209 /// <param name="time">The
210 /// <see cref="T:System.DateTime"/> to which to add
213 /// <param name="minutes">The number of minutes to add.</param>
214 /// <returns>A new <see cref="T:System.DateTime"/> value, that
215 /// results from adding <paramref name="minutes"/> to the specified
216 /// DateTime.</returns>
217 public virtual DateTime AddMinutes(DateTime time, int minutes) {
218 return time.Add(TimeSpan.FromMinutes(minutes));
222 /// When overrideden adds months to a given date.
224 /// <param name="time">The
225 /// <see cref="T:System.DateTime"/> to which to add
228 /// <param name="months">The number of months to add.</param>
229 /// <returns>A new <see cref="T:System.DateTime"/> value, that
230 /// results from adding <paramref name="months"/> to the specified
231 /// DateTime.</returns>
232 public abstract DateTime AddMonths(DateTime time, int months);
235 /// The virtual method adds seconds to a given date.
237 /// <param name="time">The
238 /// <see cref="T:System.DateTime"/> to which to add
241 /// <param name="seconds">The number of seconds to add.</param>
242 /// <returns>A new <see cref="T:System.DateTime"/> value, that
243 /// results from adding <paramref name="seconds"/> to the specified
244 /// DateTime.</returns>
245 public virtual DateTime AddSeconds(DateTime time, int seconds) {
246 return time.Add(TimeSpan.FromSeconds(seconds));
250 /// A wirtual method that adds weeks to a given date.
252 /// <param name="time">The
253 /// <see cref="T:System.DateTime"/> to which to add
256 /// <param name="weeks">The number of weeks to add.</param>
257 /// <returns>A new <see cref="T:System.DateTime"/> value, that
258 /// results from adding <paramref name="weeks"/> to the specified
259 /// DateTime.</returns>
260 public virtual DateTime AddWeeks(DateTime time, int weeks) {
261 return time.AddDays(weeks * M_DaysInWeek);
265 /// When overrideden adds years to a given date.
267 /// <param name="time">The
268 /// <see cref="T:System.DateTime"/> to which to add
271 /// <param name="years">The number of years to add.</param>
272 /// <returns>A new <see cref="T:System.DateTime"/> value, that
273 /// results from adding <paramref name="years"/> to the specified
274 /// DateTime.</returns>
275 public abstract DateTime AddYears(DateTime time, int years);
278 /// When overriden gets the day of the month from
279 /// <paramref name="time"/>.
281 /// <param name="time">The
282 /// <see cref="T:System.DateTime"/> that specifies a
285 /// <returns>An integer giving the day of months, starting with 1.
287 public abstract int GetDayOfMonth(DateTime time);
290 /// When overriden gets the day of the week from the specified date.
292 /// <param name="time">The
293 /// <see cref="T:System.DateTime"/> that specifies a
296 /// <returns>An integer giving the day of months, starting with 1.
298 public abstract DayOfWeek GetDayOfWeek(DateTime time);
301 /// When overridden gives the number of the day in the year.
303 /// <param name="time">The
304 /// <see cref="T:System.DateTime"/> that specifies a
307 /// <returns>An integer representing the day of the year,
308 /// starting with 1.</returns>
309 public abstract int GetDayOfYear(DateTime time);
312 /// A virtual method that gives the number of days of the specified
313 /// month of the <paramref name="year"/> and the
314 /// <see cref="P:CurrentEra"/>.
316 /// <param name="year">An integer that gives the year in the current
318 /// <param name="month">An integer that gives the month, starting
320 /// <returns>An integer that gives the number of days of the
321 /// specified month.</returns>
322 /// <exception cref="T:System.ArgumentOutOfRangeException">
323 /// The exception is thrown, if <paramref name="month"/> or
324 /// <paramref name="year"/> is outside the allowed range.
326 public virtual int GetDaysInMonth(int year, int month) {
327 return GetDaysInMonth(year, month, CurrentEra);
331 /// When overridden gives the number of days in the specified month
332 /// of the given year and era.
334 /// <param name="year">An integer that gives the year.
336 /// <param name="month">An integer that gives the month, starting
338 /// <param name="era">An intger that gives the era of the specified
340 /// <returns>An integer that gives the number of days of the
341 /// specified month.</returns>
342 /// <exception cref="T:System.ArgumentOutOfRangeException">
343 /// The exception is thrown, if <paramref name="month"/>,
344 /// <paramref name="year"/> ,or <paramref name="era"/> is outside
345 /// the allowed range.
347 public abstract int GetDaysInMonth(int year, int month, int era);
350 /// A virtual method that gives the number of days of the specified
351 /// year of the <see cref="P:CurrentEra"/>.
353 /// <param name="year">An integer that gives the year in the current
355 /// <returns>An integer that gives the number of days of the
356 /// specified year.</returns>
357 /// <exception cref="T:System.ArgumentOutOfRangeException">
358 /// The exception is thrown, if
359 /// <paramref name="year"/> is outside the allowed range.
361 public virtual int GetDaysInYear(int year) {
362 return GetDaysInYear(year, CurrentEra);
366 /// When overridden gives the number of days of the specified
367 /// year of the given era..
369 /// <param name="year">An integer that specifies the year.
371 /// <param name="era">An ineger that specifies the era.
373 /// <returns>An integer that gives the number of days of the
374 /// specified year.</returns>
375 /// <exception cref="T:System.ArgumentOutOfRangeExceiption">
376 /// The exception is thrown, if
377 /// <paramref name="year"/> is outside the allowed range.
379 public abstract int GetDaysInYear(int year, int era);
382 /// When overridden gives the era of the specified date.
384 /// <param name="time">The
385 /// <see cref="T:System.DateTime"/> that specifies a
388 /// <returns>An integer representing the era of the calendar.
390 public abstract int GetEra(DateTime time);
393 /// Virtual method that gives the hour of the specified time.
395 /// <param name="time">The
396 /// <see cref="T:System.DateTime"/> that specifies the
399 /// <returns>An integer that gives the hour of the specified time,
400 /// starting with 0.</returns>
401 public virtual int GetHour(DateTime time) {
402 return time.TimeOfDay.Hours;
406 /// Virtual method that gives the milliseconds in the current second
407 /// of the specified time.
409 /// <param name="time">The
410 /// <see cref="T:System.DateTime"/> that specifies the
413 /// <returns>An integer that gives the milliseconds in the seconds
414 /// of the specified time, starting with 0.</returns>
415 public virtual double GetMilliseconds(DateTime time) {
416 return time.TimeOfDay.Milliseconds;
420 /// Virtual method that gives the minute of the specified time.
422 /// <param name="time">The
423 /// <see cref="T:System.DateTime"/> that specifies the
426 /// <returns>An integer that gives the minute of the specified time,
427 /// starting with 0.</returns>
428 public virtual int GetMinute(DateTime time) {
429 return time.TimeOfDay.Minutes;
433 /// When overridden gives the number of the month of the specified
436 /// <param name="time">The
437 /// <see cref="T:System.DateTime"/> that specifies a
440 /// <returns>An integer representing the month,
441 /// starting with 1.</returns>
442 public abstract int GetMonth(DateTime time);
445 /// Virtual method that gives the number of months of the specified
446 /// year of the <see cref="M:CurrentEra"/>.
448 /// <param name="year">An integer that specifies the year in the
451 /// <returns>An integer that gives the number of the months in the
452 /// specified year.</returns>
453 /// <exception cref="T:System.ArgumentOutOfRangeException">
454 /// The exception is thrown, if the year is not allowed in the
457 public virtual int GetMonthsInYear(int year) {
458 return GetMonthsInYear(year, CurrentEra);
462 /// When overridden gives the number of months in the specified year
465 /// <param name="year">An integer that specifies the year.
467 /// <param name="era">An integer that specifies the era.
469 /// <returns>An integer that gives the number of the months in the
470 /// specified year.</returns>
471 /// <exception cref="T:System.ArgumentOutOfRangeException">
472 /// The exception is thrown, if the year or the era are not valid.
474 public abstract int GetMonthsInYear(int year, int era);
477 /// Virtual method that gives the second of the specified time.
479 /// <param name="time">The
480 /// <see cref="T:System.DateTime"/> that specifies the
483 /// <returns>An integer that gives the second of the specified time,
484 /// starting with 0.</returns>
485 public virtual int GetSecond(DateTime time) {
486 return time.TimeOfDay.Seconds;
490 /// A protected method to calculate the number of days between two
493 /// <param name="timeA">A <see cref="T:System.DateTime"/>
494 /// representing the first date.
496 /// <param name="timeB">A <see cref="T:System.DateTime"/>
497 /// representing the second date.
499 /// <returns>An integer that represents the difference of days
500 /// between <paramref name="timeA"/> and <paramref name="timeB"/>.
502 protected int M_DiffDays(DateTime timeA, DateTime timeB) {
503 long diff = timeA.Ticks - timeB.Ticks;
506 return (int)(diff/TimeSpan.TicksPerDay);
510 return -1 + (int)(diff/TimeSpan.TicksPerDay);
514 /// A protected method that gives the first day of the second week of
517 /// <param name="year">An integer that represents the year.</param>
518 /// <param name="rule">The
519 /// <see cref="T:System.Globalization.CalendarWeekRule"/>
520 /// to be used for the calculation.
522 /// <param name="firstDayOfWeek">
523 /// The <see cref="T:System.Globalization.DayOfWeek"/>
524 /// specifying the first day in a week.
526 /// <returns>The <see cref="T:System.DateTime"/> representing
527 /// the first day of the second week of the year.
529 protected DateTime M_GetFirstDayOfSecondWeekOfYear(
530 int year, CalendarWeekRule rule, DayOfWeek firstDayOfWeek)
532 DateTime d1 = ToDateTime(year, 1, 1, 0, 0, 0, 0);
533 int dow1 = (int)GetDayOfWeek(d1);
534 int fdow = (int)firstDayOfWeek;
538 case CalendarWeekRule.FirstDay:
543 d += fdow + M_DaysInWeek - dow1;
546 case CalendarWeekRule.FirstFullWeek:
552 d += fdow + M_DaysInWeek - dow1;
555 case CalendarWeekRule.FirstFourDayWeek:
556 int dow4 = (dow1 + 3)%M_DaysInWeek;
563 d += fdow + M_DaysInWeek - dow4;
568 return AddDays(d1, d);
572 /// A virtual method that gives the number of the week in the year.
574 /// <param name="time">A
575 /// <see cref="T:System.DateTime"/> representing the date.
577 /// <param name="rule">The
578 /// <see cref="T:System.Globalization.CalendarWeekRule"/>
579 /// to be used for the calculation.
581 /// <param name="firstDayOfWeek">
582 /// The <see cref="T:System.Globalization.DayOfWeek"/>
583 /// specifying the first day in a week.
585 /// <returns>An integer representing the number of the week in the
586 /// year, starting with 1.
588 public virtual int GetWeekOfYear(DateTime time,
589 CalendarWeekRule rule,
590 DayOfWeek firstDayOfWeek)
592 if (firstDayOfWeek < DayOfWeek.Sunday ||
593 DayOfWeek.Saturday < firstDayOfWeek)
595 throw new ArgumentOutOfRangeException("firstDayOfWeek",
596 "Value is not a valid day of week.");
598 int year = GetYear(time);
603 DateTime secondWeek = M_GetFirstDayOfSecondWeekOfYear(
604 year, rule, firstDayOfWeek);
605 days = M_DiffDays(time, secondWeek) + M_DaysInWeek;
611 return 1 + days/M_DaysInWeek;
615 /// When overridden gives the number of the year of the specified
618 /// <param name="time">The
619 /// <see cref="T:System.DateTime"/> that specifies a
622 /// <returns>An integer representing the year,
623 /// starting with 1.</returns>
624 public abstract int GetYear(DateTime time);
627 /// A virtual method that tells whether the given day in the
628 /// <see cref="M:CurrentEra"/> is a leap day.
630 /// <param name="year">An integer that specifies the year in the
633 /// <param name="month">An integer that specifies the month.
635 /// <param name="day">An integer that specifies the day.
637 /// <returns>A boolean that tells whether the given day is a leap
640 /// <exception cref="T:System.ArgumentOutOfRangeException">
641 /// The exception is thrown, if the year, month or day is not valid
644 public virtual bool IsLeapDay(int year, int month, int day) {
645 return IsLeapDay(year, month, day, CurrentEra);
649 /// Tells when overridden whether the given day
652 /// <param name="year">An integer that specifies the year in the
655 /// <param name="month">An integer that specifies the month.
657 /// <param name="day">An integer that specifies the day.
659 /// <param name="era">An integer that specifies the era.
661 /// <returns>A boolean that tells whether the given day is a leap
664 /// <exception cref="T:System.ArgumentOutOfRangeException">
665 /// The exception is thrown, if the year, month, day, or era is not
668 public abstract bool IsLeapDay(int year, int month, int day, int era);
671 /// A virtual method that tells whether the given month of the
672 /// specified year in the
673 /// <see cref="M:CurrentEra"/> is a leap month.
675 /// <param name="year">An integer that specifies the year in the
678 /// <param name="month">An integer that specifies the month.
680 /// <returns>A boolean that tells whether the given month is a leap
683 /// <exception cref="T:System.ArgumentOutOfRangeException">
684 /// The exception is thrown, if the year or month is not valid
687 public virtual bool IsLeapMonth(int year, int month) {
688 return IsLeapMonth(year, month, CurrentEra);
692 /// Tells when overridden whether the given month
695 /// <param name="year">An integer that specifies the year in the
698 /// <param name="month">An integer that specifies the month.
700 /// <param name="era">An integer that specifies the era.
702 /// <returns>A boolean that tells whether the given month is a leap
705 /// <exception cref="T:System.ArgumentOutOfRangeException">
706 /// The exception is thrown, if the year, month, or era is not
709 public abstract bool IsLeapMonth(int year, int month, int era);
712 /// A virtual method that tells whether the given year
714 /// <see cref="M:CurrentEra"/> is a leap year.
716 /// <param name="year">An integer that specifies the year in the
719 /// <returns>A boolean that tells whether the given year is a leap
722 /// <exception cref="T:System.ArgumentOutOfRangeException">
723 /// The exception is thrown, if the year is not valid
726 public virtual bool IsLeapYear(int year) {
727 return IsLeapYear(year, CurrentEra);
731 /// Tells when overridden whether the given year
734 /// <param name="year">An integer that specifies the year in the
737 /// <param name="era">An integer that specifies the era.
739 /// <returns>A boolean that tells whether the given year is a leap
742 /// <exception cref="T:System.ArgumentOutOfRangeException">
743 /// The exception is thrown, if the year or era is not
746 public abstract bool IsLeapYear(int year, int era);
749 /// A virtual method that creates the
750 /// <see cref="T:System.DateTime"/> from the parameters.
752 /// <param name="year">An integer that gives the year in the
753 /// <see cref="M:CurrentEra"/>.
755 /// <param name="month">An integer that specifies the month.
757 /// <param name="day">An integer that specifies the day.
759 /// <param name="hour">An integer that specifies the hour.
761 /// <param name="minute">An integer that specifies the minute.
763 /// <param name="second">An integer that gives the second.
765 /// <param name="milliseconds">An integer that gives the
769 /// <see cref="T:system.DateTime"/> representig the date and time.
771 /// <exception cref="T:System.ArgumentOutOfRangeException">
772 /// The exception is thrown, if at least one of the parameters
775 public virtual DateTime ToDateTime(int year, int month, int day,
776 int hour, int minute, int second, int milliseconds)
778 return ToDateTime(year, month, day, hour, minute, second,
779 milliseconds, CurrentEra);
784 /// When overridden creates the
785 /// <see cref="T:System.DateTime"/> from the parameters.
787 /// <param name="year">An integer that gives the year in the
788 /// <paramref name="era"/>.
790 /// <param name="month">An integer that specifies the month.
792 /// <param name="day">An integer that specifies the day.
794 /// <param name="hour">An integer that specifies the hour.
796 /// <param name="minute">An integer that specifies the minute.
798 /// <param name="second">An integer that gives the second.
800 /// <param name="milliseconds">An integer that gives the
803 /// <param name="era">An integer that specifies the era.
806 /// <see cref="T:system.DateTime"/> representig the date and time.
808 /// <exception cref="T:System.ArgumentOutOfRangeException">
809 /// The exception is thrown, if at least one of the parameters
812 public abstract DateTime ToDateTime(int year, int month, int day,
813 int hour, int minute, int second, int milliseconds,
817 /// A virtual method that converts a two-digit year to a four-digit
818 /// year. It uses the <see cref="M:TwoDigitYearMax"/> property.
820 /// <param name="year">An integer that gives the two-digit year.
822 /// <returns>An integer giving the four digit year.
824 /// <exception cref="T:System.ArgumentOutOfRangeException">
825 /// The exception is thrown if the year is negative or the resulting
828 public virtual int ToFourDigitYear(int year) {
830 throw new ArgumentOutOfRangeException(
831 "year", "Non-negative number required.");
832 /* seems not to be the right thing to do, but .NET is
836 int year2 = TwoDigitYearMax%100;
837 int d = year - year2;
838 year = TwoDigitYearMax + d + (d <= 0 ? 0 : -100);
840 int era = CurrentEra;
841 M_CheckYE(year, ref era);
845 // TwoDigitYearMax: Windows reads it from the Registry, we
846 // should have an XML file with the defaults
848 /// The default constructor, is sets the TwoDigitYearMax to 2029.
851 /// The .NET framework reads the value from the registry.
852 /// We should implement it here. Currently I set the default values
853 /// in the ctors of the derived classes, if it is 99.
855 protected Calendar() {
856 M_TwoDigitYearMax = 99;
859 /// <summary>Protected field storing the abbreviated era names.
861 protected string[] M_AbbrEraNames;
862 /// <summary>Protected field storing the era names.
864 protected string[] M_EraNames;
867 /// The property stores the era names. It might be overwritten by
870 internal string[] AbbreviatedEraNames {
872 if (M_AbbrEraNames == null ||
873 M_AbbrEraNames.Length != Eras.Length)
875 "Internal: M_AbbrEraNames " +
876 "wrong initialized!");
877 return (string[])M_AbbrEraNames.Clone();
880 if (value.Length != Eras.Length) {
881 StringWriter sw = new StringWriter();
882 sw.Write("Array length must be equal Eras " +
883 "length {0}.", Eras.Length);
884 throw new ArgumentException(
887 M_AbbrEraNames = (string[])value.Clone();
892 /// The property stores the era names. It might be overwritten by
895 internal string[] EraNames {
897 if (M_EraNames == null ||
898 M_EraNames.Length != Eras.Length)
900 "Internal: M_EraNames " +
902 return (string[])M_EraNames.Clone();
905 if (value.Length != Eras.Length) {
906 StringWriter sw = new StringWriter();
907 sw.Write("Array length must be equal Eras " +
908 "length {0}.", Eras.Length);
909 throw new ArgumentException(
912 M_EraNames = (string[])value.Clone();
917 } // namespace System.Globalization