*Calendar classes
[mono.git] / mcs / class / corlib / System.Globalization / Calendar.cs
1 // Calendar.cs
2 //
3 // (C) Ulrich Kunitz 2002
4 //
5
6 namespace System.Globalization {
7
8 using System;
9 using System.IO;
10
11 /// <remarks>
12 /// The class serves as a base class for calendar classes.
13 /// </remarks>
14 [Serializable]
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
19         {
20                 get { return 7; }
21         }
22
23         /// <summary>
24         /// The protected method creates the string used in the
25         /// <see cref="T:System.ArgumentOutOfRangeException"/>
26         /// </summary>
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
30         /// value.</param>
31         /// <returns>The string used in the
32         /// <see cref="T:System.ArgumentOutOfRangeException"/>
33         /// </returns>
34         protected string M_ValidValues(object a, object b)
35         {
36                 StringWriter sw = new StringWriter();
37                 sw.Write("Valid values are between {0} and {1}, inclusive.",
38                         a, b);
39                 return sw.ToString();
40         }
41
42         /// <summary>
43         /// The protected method checks wether the parameter
44         /// <paramref name="arg"/> is in the allowed range.
45         /// </summary>
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.
49         /// </param>
50         /// <param name="a">An integer that represents the smallest allowed
51         /// value.</param>
52         /// <param name="b">An integer that represents the greatest allowed
53         /// value.</param>
54         /// <exception cref="T:System.ArgumentOutOfRangeException">
55         /// The exception is thrown, if the <paramref name="arg"/> is outside
56         /// the allowed range.
57         /// </exception>
58         protected void M_ArgumentInRange(string param, int arg, int a, int b)
59         {
60                 if (a <= arg && arg <= b)
61                         return;
62                 throw new ArgumentOutOfRangeException(param, M_ValidValues(a, b));
63         }
64
65         /// <summary>
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
70         /// </summary>
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.
82         /// </exception>
83         protected void M_CheckHMSM(int hour, int minute, int second,
84                 int milliseconds)
85         {
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);
90         }
91
92         /// <value>
93         /// A represantation of the CurrentEra.
94         /// </value>
95         public const int CurrentEra = 0;
96
97         /// <value>When overridden gives the eras supported by the
98         /// calendar as an array of integers.
99         /// </value>
100         public abstract int[] Eras { get; }
101
102         /// <summary>
103         /// The protected member stores the value for the
104         /// <see cref="P:TwoDigitYearMax"/>
105         /// property.
106         /// </summary>
107         protected int M_TwoDigitYearMax;
108         
109
110         /// <summary>
111         /// Private field containing the maximum year for the calendar.
112         /// </summary>
113         private int M_MaxYearValue = 0;
114
115         /// <value>
116         /// Get-only property returing the maximum allowed year for this
117         /// class.
118         /// </value>
119         protected virtual int M_MaxYear {
120                 get {
121                         if (M_MaxYearValue == 0) {
122                                 M_MaxYearValue = GetYear(DateTime.MaxValue);
123                         }
124                         return M_MaxYearValue;
125                 }
126         }
127
128         /// <summary>
129         /// Checks whether the year is the era is valid, if era = CurrentEra
130         /// the right value is set.
131         /// </summary>
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.
136         /// </exception>
137         protected abstract void M_CheckYE(int year, ref int era);
138
139         /// <value>
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>
145         /// </value>
146         public virtual int TwoDigitYearMax {
147                 get { return M_TwoDigitYearMax; }
148                 set {
149                         M_ArgumentInRange("year", value, 100, M_MaxYear);
150                         int era = CurrentEra;
151                         M_CheckYE(value, ref era);
152                         M_TwoDigitYearMax = value;
153                 }
154         }
155
156         /// <summary>
157         /// The virtual method adds days to a given date.
158         /// </summary>
159         /// <param name="time">The
160         /// <see cref="T:System.DateTime"/> to which to add
161         /// days.
162         /// </param>
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));
169         }
170
171         /// <summary>
172         /// The virtual method adds hours to a given date.
173         /// </summary>
174         /// <param name="time">The
175         /// <see cref="T:System.DateTime"/> to which to add
176         /// hours.
177         /// </param>
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));
184         }
185
186         /// <summary>
187         /// The virtual method adds milliseconds to a given date.
188         /// </summary>
189         /// <param name="time">The
190         /// <see cref="T:System.DateTime"/> to which to add
191         /// milliseconds.
192         /// </param>
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"/>.
196         /// </param>
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,
201                 double milliseconds)
202         {
203                 return time.Add(TimeSpan.FromMilliseconds(milliseconds));
204         }
205
206         /// <summary>
207         /// The virtual method adds minutes to a given date.
208         /// </summary>
209         /// <param name="time">The
210         /// <see cref="T:System.DateTime"/> to which to add
211         /// minutes.
212         /// </param>
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));
219         }
220
221         /// <summary>
222         /// When overrideden adds months to a given date.
223         /// </summary>
224         /// <param name="time">The
225         /// <see cref="T:System.DateTime"/> to which to add
226         /// months.
227         /// </param>
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);
233
234         /// <summary>
235         /// The virtual method adds seconds to a given date.
236         /// </summary>
237         /// <param name="time">The
238         /// <see cref="T:System.DateTime"/> to which to add
239         /// seconds.
240         /// </param>
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));
247         }
248
249         /// <summary>
250         /// A wirtual method that adds weeks to a given date.
251         /// </summary>
252         /// <param name="time">The
253         /// <see cref="T:System.DateTime"/> to which to add
254         /// weeks.
255         /// </param>
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);
262         }
263
264         /// <summary>
265         /// When overrideden adds years to a given date.
266         /// </summary>
267         /// <param name="time">The
268         /// <see cref="T:System.DateTime"/> to which to add
269         /// years.
270         /// </param>
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);
276
277         /// <summary>
278         /// When overriden gets the day of the month from
279         /// <paramref name="time"/>.
280         /// </summary>
281         /// <param name="time">The
282         /// <see cref="T:System.DateTime"/> that specifies a
283         /// date.
284         /// </param>
285         /// <returns>An integer giving the day of months, starting with 1.
286         /// </returns>
287         public abstract int GetDayOfMonth(DateTime time);
288
289         /// <summary>
290         /// When overriden gets the day of the week from the specified date.
291         /// </summary>
292         /// <param name="time">The
293         /// <see cref="T:System.DateTime"/> that specifies a
294         /// date.
295         /// </param>
296         /// <returns>An integer giving the day of months, starting with 1.
297         /// </returns>
298         public abstract DayOfWeek GetDayOfWeek(DateTime time);
299
300         /// <summary>
301         /// When overridden gives the number of the day in the year.
302         /// </summary>
303         /// <param name="time">The
304         /// <see cref="T:System.DateTime"/> that specifies a
305         /// date.
306         /// </param>
307         /// <returns>An integer representing the day of the year,
308         /// starting with 1.</returns>
309         public abstract int GetDayOfYear(DateTime time);
310
311         /// <summary>
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"/>.
315         /// </summary>
316         /// <param name="year">An integer that gives the year in the current
317         /// era.</param>
318         /// <param name="month">An integer that gives the month, starting
319         /// with 1.</param>
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.
325         /// </exception>
326         public virtual int GetDaysInMonth(int year, int month) {
327                 return GetDaysInMonth(year, month, CurrentEra);
328         }
329
330         /// <summary>
331         /// When overridden gives the number of days in the specified month
332         /// of the given year and era.
333         /// </summary>
334         /// <param name="year">An integer that gives the year.
335         /// </param>
336         /// <param name="month">An integer that gives the month, starting
337         /// with 1.</param>
338         /// <param name="era">An intger that gives the era of the specified
339         /// year.</param>
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.
346         /// </exception>
347         public abstract int GetDaysInMonth(int year, int month, int era);
348
349         /// <summary>
350         /// A virtual method that gives the number of days of the specified
351         /// year of the <see cref="P:CurrentEra"/>.
352         /// </summary>
353         /// <param name="year">An integer that gives the year in the current
354         /// era.</param>
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.
360         /// </exception>
361         public virtual int GetDaysInYear(int year) {
362                 return GetDaysInYear(year, CurrentEra);
363         }
364
365         /// <summary>
366         /// When overridden gives the number of days of the specified
367         /// year of the given era.. 
368         /// </summary>
369         /// <param name="year">An integer that specifies the year. 
370         /// </param>
371         /// <param name="era">An ineger that specifies the era.
372         /// </param>
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.
378         /// </exception>
379         public abstract int GetDaysInYear(int year, int era);
380
381         /// <summary>
382         /// When overridden gives the era of the specified date.
383         /// </summary>
384         /// <param name="time">The
385         /// <see cref="T:System.DateTime"/> that specifies a
386         /// date.
387         /// </param>
388         /// <returns>An integer representing the era of the calendar.
389         /// </returns>
390         public abstract int GetEra(DateTime time);
391
392         /// <summary>
393         /// Virtual method that gives the hour of the specified time.
394         /// </summary>
395         /// <param name="time">The
396         /// <see cref="T:System.DateTime"/> that specifies the
397         /// time.
398         /// </param>
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;
403         }
404
405         /// <summary>
406         /// Virtual method that gives the milliseconds in the current second
407         /// of the specified time.
408         /// </summary>
409         /// <param name="time">The
410         /// <see cref="T:System.DateTime"/> that specifies the
411         /// time.
412         /// </param>
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;
417         }
418
419         /// <summary>
420         /// Virtual method that gives the minute of the specified time.
421         /// </summary>
422         /// <param name="time">The
423         /// <see cref="T:System.DateTime"/> that specifies the
424         /// time.
425         /// </param>
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;
430         }
431
432         /// <summary>
433         /// When overridden gives the number of the month of the specified
434         /// date.
435         /// </summary>
436         /// <param name="time">The
437         /// <see cref="T:System.DateTime"/> that specifies a
438         /// date.
439         /// </param>
440         /// <returns>An integer representing the month, 
441         /// starting with 1.</returns>
442         public abstract int GetMonth(DateTime time);
443
444         /// <summary>
445         /// Virtual method that gives the number of months of the specified
446         /// year of the <see cref="M:CurrentEra"/>.
447         /// </summary>
448         /// <param name="year">An integer that specifies the year in the
449         /// current era.
450         /// </param>
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
455         /// current era.
456         /// </exception>
457         public virtual int GetMonthsInYear(int year) {
458                 return GetMonthsInYear(year, CurrentEra);
459         }
460
461         /// <summary>
462         /// When overridden gives the number of months in the specified year 
463         /// and era.
464         /// </summary>
465         /// <param name="year">An integer that specifies the year.
466         /// </param>
467         /// <param name="era">An integer that specifies the era.
468         /// </param>
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.
473         /// </exception>
474         public abstract int GetMonthsInYear(int year, int era);
475
476         /// <summary>
477         /// Virtual method that gives the second of the specified time.
478         /// </summary>
479         /// <param name="time">The
480         /// <see cref="T:System.DateTime"/> that specifies the
481         /// time.
482         /// </param>
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;
487         }
488
489         /// <summary>
490         /// A protected method to calculate the number of days between two
491         /// dates.
492         /// </summary>
493         /// <param name="timeA">A <see cref="T:System.DateTime"/>
494         /// representing the first date.
495         /// </param>
496         /// <param name="timeB">A <see cref="T:System.DateTime"/>
497         /// representing the second date.
498         /// </param>
499         /// <returns>An integer that represents the difference of days
500         /// between <paramref name="timeA"/> and <paramref name="timeB"/>.
501         /// </returns>
502         protected int M_DiffDays(DateTime timeA, DateTime timeB) {
503                 long diff = timeA.Ticks - timeB.Ticks;
504
505                 if (diff >= 0) {
506                         return (int)(diff/TimeSpan.TicksPerDay);
507                 }
508
509                 diff += 1;
510                 return -1 + (int)(diff/TimeSpan.TicksPerDay);
511         }
512
513         /// <summary>
514         /// A protected method that gives the first day of the second week of
515         /// the year.
516         /// </summary>
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.
521         /// </param>
522         /// <param name="firstDayOfWeek">
523         /// The <see cref="T:System.Globalization.DayOfWeek"/>
524         /// specifying the first day in a week.
525         /// </param>
526         /// <returns>The <see cref="T:System.DateTime"/> representing 
527         /// the first day of the second week of the year.
528         /// </returns>
529         protected DateTime M_GetFirstDayOfSecondWeekOfYear(
530                 int year, CalendarWeekRule rule, DayOfWeek firstDayOfWeek)
531         {
532                 DateTime d1 = ToDateTime(year, 1, 1, 0, 0, 0, 0);
533                 int dow1 = (int)GetDayOfWeek(d1);
534                 int fdow = (int)firstDayOfWeek;
535                 int d = 0;
536
537                 switch (rule) {
538                 case CalendarWeekRule.FirstDay:
539                         if (fdow > dow1) {
540                                 d += fdow - dow1;
541                         }
542                         else {
543                                 d += fdow + M_DaysInWeek - dow1;
544                         }
545                         break;
546                 case CalendarWeekRule.FirstFullWeek:
547                         d = M_DaysInWeek;
548                         if (fdow >= dow1) {
549                                 d += fdow - dow1;
550                         }
551                         else {
552                                 d += fdow + M_DaysInWeek - dow1;
553                         }
554                         break;
555                 case CalendarWeekRule.FirstFourDayWeek:
556                         int dow4 = (dow1 + 3)%M_DaysInWeek;
557
558                         d = 3;
559                         if (fdow > dow4) {
560                                 d += fdow - dow4;
561                         }
562                         else {
563                                 d += fdow + M_DaysInWeek - dow4;
564                         }
565                         break;
566                 }
567
568                 return AddDays(d1, d);
569         }
570
571         /// <summary>
572         /// A virtual method that gives the number of the week in the year.
573         /// </summary>
574         /// <param name="time">A 
575         /// <see cref="T:System.DateTime"/> representing the date.
576         /// </param>
577         /// <param name="rule">The
578         /// <see cref="T:System.Globalization.CalendarWeekRule"/>
579         /// to be used for the calculation.
580         /// </param>
581         /// <param name="firstDayOfWeek">
582         /// The <see cref="T:System.Globalization.DayOfWeek"/>
583         /// specifying the first day in a week.
584         /// </param>
585         /// <returns>An integer representing the number of the week in the
586         /// year, starting with 1.
587         /// </returns>
588         public virtual int GetWeekOfYear(DateTime time,
589                 CalendarWeekRule rule, 
590                 DayOfWeek firstDayOfWeek)
591         {
592                 if (firstDayOfWeek < DayOfWeek.Sunday ||
593                     DayOfWeek.Saturday < firstDayOfWeek)
594                 {
595                         throw new ArgumentOutOfRangeException("firstDayOfWeek",
596                                 "Value is not a valid day of week.");
597                 }
598                 int year = GetYear(time);
599
600                 int days;
601
602                 while (true) {
603                         DateTime secondWeek = M_GetFirstDayOfSecondWeekOfYear(
604                                 year, rule, firstDayOfWeek);
605                         days = M_DiffDays(time, secondWeek) + M_DaysInWeek;
606                         if (days >= 0)
607                                 break;
608                         year -= 1;
609                 }
610
611                 return 1 + days/M_DaysInWeek;
612         }
613
614         /// <summary>
615         /// When overridden gives the number of the year of the specified
616         /// date.
617         /// </summary>
618         /// <param name="time">The
619         /// <see cref="T:System.DateTime"/> that specifies a
620         /// date.
621         /// </param>
622         /// <returns>An integer representing the year, 
623         /// starting with 1.</returns>
624         public abstract int GetYear(DateTime time);
625
626         /// <summary>
627         /// A virtual method that tells whether the given day in the
628         /// <see cref="M:CurrentEra"/> is a leap day.
629         /// </summary>
630         /// <param name="year">An integer that specifies the year in the
631         /// current era.
632         /// </param>
633         /// <param name="month">An integer that specifies the month.
634         /// </param>
635         /// <param name="day">An integer that specifies the day.
636         /// </param>
637         /// <returns>A boolean that tells whether the given day is a leap
638         /// day.
639         /// </returns>
640         /// <exception cref="T:System.ArgumentOutOfRangeException">
641         /// The exception is thrown, if the year, month or day is not valid
642         /// the current era.
643         /// </exception>
644         public virtual bool IsLeapDay(int year, int month, int day) {
645                 return IsLeapDay(year, month, day, CurrentEra);
646         }
647
648         /// <summary>
649         /// Tells when overridden whether the given day 
650         /// is a leap day.
651         /// </summary>
652         /// <param name="year">An integer that specifies the year in the
653         /// given era.
654         /// </param>
655         /// <param name="month">An integer that specifies the month.
656         /// </param>
657         /// <param name="day">An integer that specifies the day.
658         /// </param>
659         /// <param name="era">An integer that specifies the era.
660         /// </param>
661         /// <returns>A boolean that tells whether the given day is a leap
662         /// day.
663         /// </returns>
664         /// <exception cref="T:System.ArgumentOutOfRangeException">
665         /// The exception is thrown, if the year, month, day, or era is not
666         /// valid.
667         /// </exception>
668         public abstract bool IsLeapDay(int year, int month, int day, int era);
669
670         /// <summary>
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.
674         /// </summary>
675         /// <param name="year">An integer that specifies the year in the
676         /// current era.
677         /// </param>
678         /// <param name="month">An integer that specifies the month.
679         /// </param>
680         /// <returns>A boolean that tells whether the given month is a leap
681         /// month.
682         /// </returns>
683         /// <exception cref="T:System.ArgumentOutOfRangeException">
684         /// The exception is thrown, if the year or month is not valid
685         /// the current era.
686         /// </exception>
687         public virtual bool IsLeapMonth(int year, int month) {
688                 return IsLeapMonth(year, month, CurrentEra);
689         }
690
691         /// <summary>
692         /// Tells when overridden whether the given month 
693         /// is a leap month.
694         /// </summary>
695         /// <param name="year">An integer that specifies the year in the
696         /// given era.
697         /// </param>
698         /// <param name="month">An integer that specifies the month.
699         /// </param>
700         /// <param name="era">An integer that specifies the era.
701         /// </param>
702         /// <returns>A boolean that tells whether the given month is a leap
703         /// month.
704         /// </returns>
705         /// <exception cref="T:System.ArgumentOutOfRangeException">
706         /// The exception is thrown, if the year, month, or era is not
707         /// valid.
708         /// </exception>
709         public abstract bool IsLeapMonth(int year, int month, int era);
710
711         /// <summary>
712         /// A virtual method that tells whether the given year
713         /// in the
714         /// <see cref="M:CurrentEra"/> is a leap year.
715         /// </summary>
716         /// <param name="year">An integer that specifies the year in the
717         /// current era.
718         /// </param>
719         /// <returns>A boolean that tells whether the given year is a leap
720         /// year.
721         /// </returns>
722         /// <exception cref="T:System.ArgumentOutOfRangeException">
723         /// The exception is thrown, if the year is not valid
724         /// the current era.
725         /// </exception>
726         public virtual bool IsLeapYear(int year) {
727                 return IsLeapYear(year, CurrentEra);
728         }
729
730         /// <summary>
731         /// Tells when overridden whether the given year
732         /// is a leap year.
733         /// </summary>
734         /// <param name="year">An integer that specifies the year in the
735         /// given era.
736         /// </param>
737         /// <param name="era">An integer that specifies the era.
738         /// </param>
739         /// <returns>A boolean that tells whether the given year is a leap
740         /// year.
741         /// </returns>
742         /// <exception cref="T:System.ArgumentOutOfRangeException">
743         /// The exception is thrown, if the year or era is not
744         /// valid.
745         /// </exception>
746         public abstract bool IsLeapYear(int year, int era);
747
748         /// <summary>
749         /// A virtual method that creates the
750         /// <see cref="T:System.DateTime"/> from the parameters.
751         /// </summary>
752         /// <param name="year">An integer that gives the year in the
753         /// <see cref="M:CurrentEra"/>.
754         /// </param>
755         /// <param name="month">An integer that specifies the month.
756         /// </param>
757         /// <param name="day">An integer that specifies the day.
758         /// </param>
759         /// <param name="hour">An integer that specifies the hour.
760         /// </param>
761         /// <param name="minute">An integer that specifies the minute.
762         /// </param>
763         /// <param name="second">An integer that gives the second.
764         /// </param>
765         /// <param name="milliseconds">An integer that gives the
766         /// milliseconds.
767         /// </param>
768         /// <returns>A
769         /// <see cref="T:system.DateTime"/> representig the date and time.
770         /// </returns>
771         /// <exception cref="T:System.ArgumentOutOfRangeException">
772         /// The exception is thrown, if at least one of the parameters
773         /// is out of range.
774         /// </exception>
775         public virtual DateTime ToDateTime(int year, int month, int day,
776                 int hour, int minute, int second, int milliseconds)
777         {
778                 return ToDateTime(year, month, day, hour, minute, second, 
779                         milliseconds, CurrentEra);
780         }
781
782
783         /// <summary>
784         /// When overridden creates the
785         /// <see cref="T:System.DateTime"/> from the parameters.
786         /// </summary>
787         /// <param name="year">An integer that gives the year in the
788         /// <paramref name="era"/>.
789         /// </param>
790         /// <param name="month">An integer that specifies the month.
791         /// </param>
792         /// <param name="day">An integer that specifies the day.
793         /// </param>
794         /// <param name="hour">An integer that specifies the hour.
795         /// </param>
796         /// <param name="minute">An integer that specifies the minute.
797         /// </param>
798         /// <param name="second">An integer that gives the second.
799         /// </param>
800         /// <param name="milliseconds">An integer that gives the
801         /// milliseconds.
802         /// </param>
803         /// <param name="era">An integer that specifies the era.
804         /// </param>
805         /// <returns>A
806         /// <see cref="T:system.DateTime"/> representig the date and time.
807         /// </returns>
808         /// <exception cref="T:System.ArgumentOutOfRangeException">
809         /// The exception is thrown, if at least one of the parameters
810         /// is out of range.
811         /// </exception>
812         public abstract DateTime ToDateTime(int year, int month, int day,
813                 int hour, int minute, int second, int milliseconds,
814                 int era);
815
816         /// <summary>
817         /// A virtual method that converts a two-digit year to a four-digit
818         /// year. It uses the <see cref="M:TwoDigitYearMax"/> property.
819         /// </summary>
820         /// <param name="year">An integer that gives the two-digit year.
821         /// </param>
822         /// <returns>An integer giving the four digit year.
823         /// </returns>
824         /// <exception cref="T:System.ArgumentOutOfRangeException">
825         /// The exception is thrown if the year is negative or the resulting 
826         /// year is invalid.
827         /// </exception>
828         public virtual int ToFourDigitYear(int year) {
829                 if (year < 0)
830                         throw new ArgumentOutOfRangeException(
831                                 "year", "Non-negative number required.");
832                 /* seems not to be the right thing to do, but .NET is
833                  * doing it this way.
834                  */
835                 if (year <= 99) {
836                         int year2 = TwoDigitYearMax%100;
837                         int d = year - year2;
838                         year = TwoDigitYearMax + d + (d <= 0 ? 0 : -100); 
839                 }
840                 int era = CurrentEra;
841                 M_CheckYE(year, ref era);
842                 return year;
843         }
844
845         // TwoDigitYearMax: Windows reads it from the Registry, we
846         // should have an XML file with the defaults
847         /// <summary>
848         /// The default constructor, is sets the TwoDigitYearMax to 2029.
849         /// </summary>
850         /// <remarks>
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.
854         /// </remarks>
855         protected Calendar() {
856                 M_TwoDigitYearMax = 99;
857         }
858
859         /// <summary>Protected field storing the abbreviated era names.
860         /// </summary>
861         protected string[] M_AbbrEraNames;
862         /// <summary>Protected field storing the era names.
863         /// </summary>
864         protected string[] M_EraNames;
865
866         /// <value>
867         /// The property stores the era names. It might be overwritten by
868         /// CultureInfo.
869         /// </value>
870         internal string[] AbbreviatedEraNames {
871                 get {
872                         if (M_AbbrEraNames == null ||
873                             M_AbbrEraNames.Length != Eras.Length)
874                                 throw new Exception(
875                                         "Internal: M_AbbrEraNames " +
876                                         "wrong initialized!");
877                         return (string[])M_AbbrEraNames.Clone();
878                 }
879                 set {
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(
885                                         sw.ToString());
886                         } 
887                         M_AbbrEraNames = (string[])value.Clone();
888                 }
889         }
890
891         /// <value>
892         /// The property stores the era names. It might be overwritten by
893         /// CultureInfo.
894         /// </value>
895         internal string[] EraNames {
896                 get {
897                         if (M_EraNames == null ||
898                             M_EraNames.Length != Eras.Length)
899                                 throw new Exception(
900                                         "Internal: M_EraNames " +
901                                         "not initialized!");
902                         return (string[])M_EraNames.Clone();
903                 }
904                 set {
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(
910                                         sw.ToString());
911                         } 
912                         M_EraNames = (string[])value.Clone();
913                 }
914         }
915 } // class Calendar
916         
917 } // namespace System.Globalization