This commit was manufactured by cvs2svn to create branch 'mono-1-0'.
[mono.git] / mcs / class / corlib / System.Globalization / Calendar.cs
1 // Calendar.cs
2 //
3 // (C) Ulrich Kunitz 2002
4 //
5
6 //
7 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29 namespace System.Globalization {
30
31 using System;
32 using System.IO;
33
34 /// <remarks>
35 /// The class serves as a base class for calendar classes.
36 /// </remarks>
37 [Serializable]
38 public abstract class Calendar {
39         /// <value>An protected integer property that gives the number of
40         /// days in a week. It might be overridden.</value>
41         internal virtual int M_DaysInWeek
42         {
43                 get { return 7; }
44         }
45
46         /// <summary>
47         /// The protected method creates the string used in the
48         /// <see cref="T:System.ArgumentOutOfRangeException"/>
49         /// </summary>
50         /// <param name="a">An object that represents the smallest 
51         /// allowable value.</param>
52         /// <param name="b">An object that represents the greatest allowable
53         /// value.</param>
54         /// <returns>The string used in the
55         /// <see cref="T:System.ArgumentOutOfRangeException"/>
56         /// </returns>
57         internal string M_ValidValues(object a, object b)
58         {
59                 StringWriter sw = new StringWriter();
60                 sw.Write("Valid values are between {0} and {1}, inclusive.",
61                         a, b);
62                 return sw.ToString();
63         }
64
65         /// <summary>
66         /// The protected method checks wether the parameter
67         /// <paramref name="arg"/> is in the allowed range.
68         /// </summary>
69         /// <param name="param">A string that gives the name of the
70         /// parameter to check.</param>
71         /// <param name="arg">An integer that gives the value to check.
72         /// </param>
73         /// <param name="a">An integer that represents the smallest allowed
74         /// value.</param>
75         /// <param name="b">An integer that represents the greatest allowed
76         /// value.</param>
77         /// <exception cref="T:System.ArgumentOutOfRangeException">
78         /// The exception is thrown, if the <paramref name="arg"/> is outside
79         /// the allowed range.
80         /// </exception>
81         internal void M_ArgumentInRange(string param, int arg, int a, int b)
82         {
83                 if (a <= arg && arg <= b)
84                         return;
85                 throw new ArgumentOutOfRangeException(param, M_ValidValues(a, b));
86         }
87
88         /// <summary>
89         /// The protected method, that checks whether
90         /// <paramref name="hour"/>, <paramref name="minute"/>,
91         /// <paramref name="second"/>, and <parameref name="millisecond"/>
92         /// are in their valid ranges
93         /// </summary>
94         /// <param name="hour">An integer that represents a hour, 
95         /// should be between 0 and 23.</param>
96         /// <param name="minute">An integer that represents a minute,
97         /// should be between 0 and 59.</param>
98         /// <param name="second">An integer that represents a second,
99         /// should be between 0 and 59.</param>
100         /// <param name="milliseconds">An integer that represents a number
101         /// of milliseconds, should be between 0 and 999999.</param>
102         /// <exception cref="T:System.ArgumentOutOfRangeException">
103         /// The Exception is thrown, if one of the parameter is outside the
104         /// allowed the range.
105         /// </exception>
106         internal void M_CheckHMSM(int hour, int minute, int second,
107                 int milliseconds)
108         {
109                 M_ArgumentInRange("hour", hour, 0, 23);
110                 M_ArgumentInRange("minute", minute, 0, 59);
111                 M_ArgumentInRange("second", second, 0, 59);
112                 M_ArgumentInRange("milliseconds", milliseconds, 0, 999999);
113         }
114
115         /// <value>
116         /// A represantation of the CurrentEra.
117         /// </value>
118         public const int CurrentEra = 0;
119
120         /// <value>When overridden gives the eras supported by the
121         /// calendar as an array of integers.
122         /// </value>
123         public abstract int[] Eras { get; }
124
125         /// <summary>
126         /// The protected member stores the value for the
127         /// <see cref="P:TwoDigitYearMax"/>
128         /// property.
129         /// </summary>
130         internal int M_TwoDigitYearMax;
131         
132
133         /// <summary>
134         /// Private field containing the maximum year for the calendar.
135         /// </summary>
136         private int M_MaxYearValue = 0;
137
138         /// <value>
139         /// Get-only property returing the maximum allowed year for this
140         /// class.
141         /// </value>
142         internal virtual int M_MaxYear {
143                 get {
144                         if (M_MaxYearValue == 0) {
145                                 M_MaxYearValue = GetYear(DateTime.MaxValue);
146                         }
147                         return M_MaxYearValue;
148                 }
149         }
150
151         /// <summary>
152         /// Checks whether the year is the era is valid, if era = CurrentEra
153         /// the right value is set.
154         /// </summary>
155         /// <param name="year">The year to check.</param>
156         /// <param name="era">The era to check.</Param>
157         /// <exception cref="T:ArgumentOutOfRangeException">
158         /// The exception will be thrown, if the year is not valid.
159         /// </exception>
160         internal abstract void M_CheckYE(int year, ref int era);
161
162         /// <value>
163         /// <para>The property gives the maximum value for years with two
164         /// digits. If the property has the value 2029, than the two-digit
165         /// integer 29 results in the year 2029 and 30 in the 
166         /// year 1930.</para>
167         /// <para>It might be overridden.</para>
168         /// </value>
169         public virtual int TwoDigitYearMax {
170                 get { return M_TwoDigitYearMax; }
171                 set {
172                         M_ArgumentInRange("year", value, 100, M_MaxYear);
173                         int era = CurrentEra;
174                         M_CheckYE(value, ref era);
175                         M_TwoDigitYearMax = value;
176                 }
177         }
178
179         /// <summary>
180         /// The virtual method adds days to a given date.
181         /// </summary>
182         /// <param name="time">The
183         /// <see cref="T:System.DateTime"/> to which to add
184         /// days.
185         /// </param>
186         /// <param name="days">The number of days to add.</param>
187         /// <returns>A new <see cref="T:System.DateTime"/> value, that
188         /// results from adding <paramref name="days"/> to the specified
189         /// DateTime.</returns>
190         public virtual DateTime AddDays(DateTime time, int days) {
191                 return time.Add(TimeSpan.FromDays(days));
192         }
193
194         /// <summary>
195         /// The virtual method adds hours to a given date.
196         /// </summary>
197         /// <param name="time">The
198         /// <see cref="T:System.DateTime"/> to which to add
199         /// hours.
200         /// </param>
201         /// <param name="hours">The number of hours to add.</param>
202         /// <returns>A new <see cref="T:System.DateTime"/> value, that
203         /// results from adding <paramref name="hours"/> to the specified
204         /// DateTime.</returns>
205         public virtual DateTime AddHours(DateTime time, int hours) {
206                 return time.Add(TimeSpan.FromHours(hours));
207         }
208
209         /// <summary>
210         /// The virtual method adds milliseconds to a given date.
211         /// </summary>
212         /// <param name="time">The
213         /// <see cref="T:System.DateTime"/> to which to add
214         /// milliseconds.
215         /// </param>
216         /// <param name="milliseconds">The number of milliseconds given as
217         /// double to add. Keep in mind the 100 nanosecond resolution of 
218         /// <see cref="T:System.DateTime"/>.
219         /// </param>
220         /// <returns>A new <see cref="T:System.DateTime"/> value, that
221         /// results from adding <paramref name="milliseconds"/> to the specified
222         /// DateTime.</returns>
223         public virtual DateTime AddMilliseconds(DateTime time,
224                 double milliseconds)
225         {
226                 return time.Add(TimeSpan.FromMilliseconds(milliseconds));
227         }
228
229         /// <summary>
230         /// The virtual method adds minutes to a given date.
231         /// </summary>
232         /// <param name="time">The
233         /// <see cref="T:System.DateTime"/> to which to add
234         /// minutes.
235         /// </param>
236         /// <param name="minutes">The number of minutes to add.</param>
237         /// <returns>A new <see cref="T:System.DateTime"/> value, that
238         /// results from adding <paramref name="minutes"/> to the specified
239         /// DateTime.</returns>
240         public virtual DateTime AddMinutes(DateTime time, int minutes) {
241                 return time.Add(TimeSpan.FromMinutes(minutes));
242         }
243
244         /// <summary>
245         /// When overrideden adds months to a given date.
246         /// </summary>
247         /// <param name="time">The
248         /// <see cref="T:System.DateTime"/> to which to add
249         /// months.
250         /// </param>
251         /// <param name="months">The number of months to add.</param>
252         /// <returns>A new <see cref="T:System.DateTime"/> value, that
253         /// results from adding <paramref name="months"/> to the specified
254         /// DateTime.</returns>
255         public abstract DateTime AddMonths(DateTime time, int months);
256
257         /// <summary>
258         /// The virtual method adds seconds to a given date.
259         /// </summary>
260         /// <param name="time">The
261         /// <see cref="T:System.DateTime"/> to which to add
262         /// seconds.
263         /// </param>
264         /// <param name="seconds">The number of seconds to add.</param>
265         /// <returns>A new <see cref="T:System.DateTime"/> value, that
266         /// results from adding <paramref name="seconds"/> to the specified
267         /// DateTime.</returns>
268         public virtual DateTime AddSeconds(DateTime time, int seconds) {
269                 return time.Add(TimeSpan.FromSeconds(seconds));
270         }
271
272         /// <summary>
273         /// A wirtual method that adds weeks to a given date.
274         /// </summary>
275         /// <param name="time">The
276         /// <see cref="T:System.DateTime"/> to which to add
277         /// weeks.
278         /// </param>
279         /// <param name="weeks">The number of weeks to add.</param>
280         /// <returns>A new <see cref="T:System.DateTime"/> value, that
281         /// results from adding <paramref name="weeks"/> to the specified
282         /// DateTime.</returns>
283         public virtual DateTime AddWeeks(DateTime time, int weeks) {
284                 return time.AddDays(weeks * M_DaysInWeek);
285         }
286
287         /// <summary>
288         /// When overrideden adds years to a given date.
289         /// </summary>
290         /// <param name="time">The
291         /// <see cref="T:System.DateTime"/> to which to add
292         /// years.
293         /// </param>
294         /// <param name="years">The number of years to add.</param>
295         /// <returns>A new <see cref="T:System.DateTime"/> value, that
296         /// results from adding <paramref name="years"/> to the specified
297         /// DateTime.</returns>
298         public abstract DateTime AddYears(DateTime time, int years);
299
300         /// <summary>
301         /// When overriden gets the day of the month from
302         /// <paramref name="time"/>.
303         /// </summary>
304         /// <param name="time">The
305         /// <see cref="T:System.DateTime"/> that specifies a
306         /// date.
307         /// </param>
308         /// <returns>An integer giving the day of months, starting with 1.
309         /// </returns>
310         public abstract int GetDayOfMonth(DateTime time);
311
312         /// <summary>
313         /// When overriden gets the day of the week from the specified date.
314         /// </summary>
315         /// <param name="time">The
316         /// <see cref="T:System.DateTime"/> that specifies a
317         /// date.
318         /// </param>
319         /// <returns>An integer giving the day of months, starting with 1.
320         /// </returns>
321         public abstract DayOfWeek GetDayOfWeek(DateTime time);
322
323         /// <summary>
324         /// When overridden gives the number of the day in the year.
325         /// </summary>
326         /// <param name="time">The
327         /// <see cref="T:System.DateTime"/> that specifies a
328         /// date.
329         /// </param>
330         /// <returns>An integer representing the day of the year,
331         /// starting with 1.</returns>
332         public abstract int GetDayOfYear(DateTime time);
333
334         /// <summary>
335         /// A virtual method that gives the number of days of the specified
336         /// month of the <paramref name="year"/> and the
337         /// <see cref="P:CurrentEra"/>.
338         /// </summary>
339         /// <param name="year">An integer that gives the year in the current
340         /// era.</param>
341         /// <param name="month">An integer that gives the month, starting
342         /// with 1.</param>
343         /// <returns>An integer that gives the number of days of the
344         /// specified month.</returns>
345         /// <exception cref="T:System.ArgumentOutOfRangeException">
346         /// The exception is thrown, if <paramref name="month"/> or
347         /// <paramref name="year"/> is outside the allowed range.
348         /// </exception>
349         public virtual int GetDaysInMonth(int year, int month) {
350                 return GetDaysInMonth(year, month, CurrentEra);
351         }
352
353         /// <summary>
354         /// When overridden gives the number of days in the specified month
355         /// of the given year and era.
356         /// </summary>
357         /// <param name="year">An integer that gives the year.
358         /// </param>
359         /// <param name="month">An integer that gives the month, starting
360         /// with 1.</param>
361         /// <param name="era">An intger that gives the era of the specified
362         /// year.</param>
363         /// <returns>An integer that gives the number of days of the
364         /// specified month.</returns>
365         /// <exception cref="T:System.ArgumentOutOfRangeException">
366         /// The exception is thrown, if <paramref name="month"/>,
367         /// <paramref name="year"/> ,or <paramref name="era"/> is outside
368         /// the allowed range.
369         /// </exception>
370         public abstract int GetDaysInMonth(int year, int month, int era);
371
372         /// <summary>
373         /// A virtual method that gives the number of days of the specified
374         /// year of the <see cref="P:CurrentEra"/>.
375         /// </summary>
376         /// <param name="year">An integer that gives the year in the current
377         /// era.</param>
378         /// <returns>An integer that gives the number of days of the
379         /// specified year.</returns>
380         /// <exception cref="T:System.ArgumentOutOfRangeException">
381         /// The exception is thrown, if
382         /// <paramref name="year"/> is outside the allowed range.
383         /// </exception>
384         public virtual int GetDaysInYear(int year) {
385                 return GetDaysInYear(year, CurrentEra);
386         }
387
388         /// <summary>
389         /// When overridden gives the number of days of the specified
390         /// year of the given era.. 
391         /// </summary>
392         /// <param name="year">An integer that specifies the year. 
393         /// </param>
394         /// <param name="era">An ineger that specifies the era.
395         /// </param>
396         /// <returns>An integer that gives the number of days of the
397         /// specified year.</returns>
398         /// <exception cref="T:System.ArgumentOutOfRangeExceiption">
399         /// The exception is thrown, if
400         /// <paramref name="year"/> is outside the allowed range.
401         /// </exception>
402         public abstract int GetDaysInYear(int year, int era);
403
404         /// <summary>
405         /// When overridden gives the era of the specified date.
406         /// </summary>
407         /// <param name="time">The
408         /// <see cref="T:System.DateTime"/> that specifies a
409         /// date.
410         /// </param>
411         /// <returns>An integer representing the era of the calendar.
412         /// </returns>
413         public abstract int GetEra(DateTime time);
414
415         /// <summary>
416         /// Virtual method that gives the hour of the specified time.
417         /// </summary>
418         /// <param name="time">The
419         /// <see cref="T:System.DateTime"/> that specifies the
420         /// time.
421         /// </param>
422         /// <returns>An integer that gives the hour of the specified time,
423         /// starting with 0.</returns>
424         public virtual int GetHour(DateTime time) {
425                 return time.TimeOfDay.Hours;
426         }
427
428         /// <summary>
429         /// Virtual method that gives the milliseconds in the current second
430         /// of the specified time.
431         /// </summary>
432         /// <param name="time">The
433         /// <see cref="T:System.DateTime"/> that specifies the
434         /// time.
435         /// </param>
436         /// <returns>An integer that gives the milliseconds in the seconds
437         /// of the specified time, starting with 0.</returns>
438         public virtual double GetMilliseconds(DateTime time) {
439                 return time.TimeOfDay.Milliseconds;
440         }
441
442         /// <summary>
443         /// Virtual method that gives the minute of the specified time.
444         /// </summary>
445         /// <param name="time">The
446         /// <see cref="T:System.DateTime"/> that specifies the
447         /// time.
448         /// </param>
449         /// <returns>An integer that gives the minute of the specified time,
450         /// starting with 0.</returns>
451         public virtual int GetMinute(DateTime time) {
452                 return time.TimeOfDay.Minutes;
453         }
454
455         /// <summary>
456         /// When overridden gives the number of the month of the specified
457         /// date.
458         /// </summary>
459         /// <param name="time">The
460         /// <see cref="T:System.DateTime"/> that specifies a
461         /// date.
462         /// </param>
463         /// <returns>An integer representing the month, 
464         /// starting with 1.</returns>
465         public abstract int GetMonth(DateTime time);
466
467         /// <summary>
468         /// Virtual method that gives the number of months of the specified
469         /// year of the <see cref="M:CurrentEra"/>.
470         /// </summary>
471         /// <param name="year">An integer that specifies the year in the
472         /// current era.
473         /// </param>
474         /// <returns>An integer that gives the number of the months in the
475         /// specified year.</returns>
476         /// <exception cref="T:System.ArgumentOutOfRangeException">
477         /// The exception is thrown, if the year is not allowed in the
478         /// current era.
479         /// </exception>
480         public virtual int GetMonthsInYear(int year) {
481                 return GetMonthsInYear(year, CurrentEra);
482         }
483
484         /// <summary>
485         /// When overridden gives the number of months in the specified year 
486         /// and era.
487         /// </summary>
488         /// <param name="year">An integer that specifies the year.
489         /// </param>
490         /// <param name="era">An integer that specifies the era.
491         /// </param>
492         /// <returns>An integer that gives the number of the months in the
493         /// specified year.</returns>
494         /// <exception cref="T:System.ArgumentOutOfRangeException">
495         /// The exception is thrown, if the year or the era are not valid.
496         /// </exception>
497         public abstract int GetMonthsInYear(int year, int era);
498
499         /// <summary>
500         /// Virtual method that gives the second of the specified time.
501         /// </summary>
502         /// <param name="time">The
503         /// <see cref="T:System.DateTime"/> that specifies the
504         /// time.
505         /// </param>
506         /// <returns>An integer that gives the second of the specified time,
507         /// starting with 0.</returns>
508         public virtual int GetSecond(DateTime time) {
509                 return time.TimeOfDay.Seconds;
510         }
511
512         /// <summary>
513         /// A protected method to calculate the number of days between two
514         /// dates.
515         /// </summary>
516         /// <param name="timeA">A <see cref="T:System.DateTime"/>
517         /// representing the first date.
518         /// </param>
519         /// <param name="timeB">A <see cref="T:System.DateTime"/>
520         /// representing the second date.
521         /// </param>
522         /// <returns>An integer that represents the difference of days
523         /// between <paramref name="timeA"/> and <paramref name="timeB"/>.
524         /// </returns>
525         internal int M_DiffDays(DateTime timeA, DateTime timeB) {
526                 long diff = timeA.Ticks - timeB.Ticks;
527
528                 if (diff >= 0) {
529                         return (int)(diff/TimeSpan.TicksPerDay);
530                 }
531
532                 diff += 1;
533                 return -1 + (int)(diff/TimeSpan.TicksPerDay);
534         }
535
536         /// <summary>
537         /// A protected method that gives the first day of the second week of
538         /// the year.
539         /// </summary>
540         /// <param name="year">An integer that represents the year.</param>
541         /// <param name="rule">The
542         /// <see cref="T:System.Globalization.CalendarWeekRule"/>
543         /// to be used for the calculation.
544         /// </param>
545         /// <param name="firstDayOfWeek">
546         /// The <see cref="T:System.Globalization.DayOfWeek"/>
547         /// specifying the first day in a week.
548         /// </param>
549         /// <returns>The <see cref="T:System.DateTime"/> representing 
550         /// the first day of the second week of the year.
551         /// </returns>
552         internal DateTime M_GetFirstDayOfSecondWeekOfYear(
553                 int year, CalendarWeekRule rule, DayOfWeek firstDayOfWeek)
554         {
555                 DateTime d1 = ToDateTime(year, 1, 1, 0, 0, 0, 0);
556                 int dow1 = (int)GetDayOfWeek(d1);
557                 int fdow = (int)firstDayOfWeek;
558                 int d = 0;
559
560                 switch (rule) {
561                 case CalendarWeekRule.FirstDay:
562                         if (fdow > dow1) {
563                                 d += fdow - dow1;
564                         }
565                         else {
566                                 d += fdow + M_DaysInWeek - dow1;
567                         }
568                         break;
569                 case CalendarWeekRule.FirstFullWeek:
570                         d = M_DaysInWeek;
571                         if (fdow >= dow1) {
572                                 d += fdow - dow1;
573                         }
574                         else {
575                                 d += fdow + M_DaysInWeek - dow1;
576                         }
577                         break;
578                 case CalendarWeekRule.FirstFourDayWeek:
579                         int dow4 = (dow1 + 3)%M_DaysInWeek;
580
581                         d = 3;
582                         if (fdow > dow4) {
583                                 d += fdow - dow4;
584                         }
585                         else {
586                                 d += fdow + M_DaysInWeek - dow4;
587                         }
588                         break;
589                 }
590
591                 return AddDays(d1, d);
592         }
593
594         /// <summary>
595         /// A virtual method that gives the number of the week in the year.
596         /// </summary>
597         /// <param name="time">A 
598         /// <see cref="T:System.DateTime"/> representing the date.
599         /// </param>
600         /// <param name="rule">The
601         /// <see cref="T:System.Globalization.CalendarWeekRule"/>
602         /// to be used for the calculation.
603         /// </param>
604         /// <param name="firstDayOfWeek">
605         /// The <see cref="T:System.Globalization.DayOfWeek"/>
606         /// specifying the first day in a week.
607         /// </param>
608         /// <returns>An integer representing the number of the week in the
609         /// year, starting with 1.
610         /// </returns>
611         public virtual int GetWeekOfYear(DateTime time,
612                 CalendarWeekRule rule, 
613                 DayOfWeek firstDayOfWeek)
614         {
615                 if (firstDayOfWeek < DayOfWeek.Sunday ||
616                     DayOfWeek.Saturday < firstDayOfWeek)
617                 {
618                         throw new ArgumentOutOfRangeException("firstDayOfWeek",
619                                 "Value is not a valid day of week.");
620                 }
621                 int year = GetYear(time);
622
623                 int days;
624
625                 while (true) {
626                         DateTime secondWeek = M_GetFirstDayOfSecondWeekOfYear(
627                                 year, rule, firstDayOfWeek);
628                         days = M_DiffDays(time, secondWeek) + M_DaysInWeek;
629                         if (days >= 0)
630                                 break;
631                         year -= 1;
632                 }
633
634                 return 1 + days/M_DaysInWeek;
635         }
636
637         /// <summary>
638         /// When overridden gives the number of the year of the specified
639         /// date.
640         /// </summary>
641         /// <param name="time">The
642         /// <see cref="T:System.DateTime"/> that specifies a
643         /// date.
644         /// </param>
645         /// <returns>An integer representing the year, 
646         /// starting with 1.</returns>
647         public abstract int GetYear(DateTime time);
648
649         /// <summary>
650         /// A virtual method that tells whether the given day in the
651         /// <see cref="M:CurrentEra"/> is a leap day.
652         /// </summary>
653         /// <param name="year">An integer that specifies the year in the
654         /// current era.
655         /// </param>
656         /// <param name="month">An integer that specifies the month.
657         /// </param>
658         /// <param name="day">An integer that specifies the day.
659         /// </param>
660         /// <returns>A boolean that tells whether the given day is a leap
661         /// day.
662         /// </returns>
663         /// <exception cref="T:System.ArgumentOutOfRangeException">
664         /// The exception is thrown, if the year, month or day is not valid
665         /// the current era.
666         /// </exception>
667         public virtual bool IsLeapDay(int year, int month, int day) {
668                 return IsLeapDay(year, month, day, CurrentEra);
669         }
670
671         /// <summary>
672         /// Tells when overridden whether the given day 
673         /// is a leap day.
674         /// </summary>
675         /// <param name="year">An integer that specifies the year in the
676         /// given era.
677         /// </param>
678         /// <param name="month">An integer that specifies the month.
679         /// </param>
680         /// <param name="day">An integer that specifies the day.
681         /// </param>
682         /// <param name="era">An integer that specifies the era.
683         /// </param>
684         /// <returns>A boolean that tells whether the given day is a leap
685         /// day.
686         /// </returns>
687         /// <exception cref="T:System.ArgumentOutOfRangeException">
688         /// The exception is thrown, if the year, month, day, or era is not
689         /// valid.
690         /// </exception>
691         public abstract bool IsLeapDay(int year, int month, int day, int era);
692
693         /// <summary>
694         /// A virtual method that tells whether the given month of the
695         /// specified year in the
696         /// <see cref="M:CurrentEra"/> is a leap month.
697         /// </summary>
698         /// <param name="year">An integer that specifies the year in the
699         /// current era.
700         /// </param>
701         /// <param name="month">An integer that specifies the month.
702         /// </param>
703         /// <returns>A boolean that tells whether the given month is a leap
704         /// month.
705         /// </returns>
706         /// <exception cref="T:System.ArgumentOutOfRangeException">
707         /// The exception is thrown, if the year or month is not valid
708         /// the current era.
709         /// </exception>
710         public virtual bool IsLeapMonth(int year, int month) {
711                 return IsLeapMonth(year, month, CurrentEra);
712         }
713
714         /// <summary>
715         /// Tells when overridden whether the given month 
716         /// is a leap month.
717         /// </summary>
718         /// <param name="year">An integer that specifies the year in the
719         /// given era.
720         /// </param>
721         /// <param name="month">An integer that specifies the month.
722         /// </param>
723         /// <param name="era">An integer that specifies the era.
724         /// </param>
725         /// <returns>A boolean that tells whether the given month is a leap
726         /// month.
727         /// </returns>
728         /// <exception cref="T:System.ArgumentOutOfRangeException">
729         /// The exception is thrown, if the year, month, or era is not
730         /// valid.
731         /// </exception>
732         public abstract bool IsLeapMonth(int year, int month, int era);
733
734         /// <summary>
735         /// A virtual method that tells whether the given year
736         /// in the
737         /// <see cref="M:CurrentEra"/> is a leap year.
738         /// </summary>
739         /// <param name="year">An integer that specifies the year in the
740         /// current era.
741         /// </param>
742         /// <returns>A boolean that tells whether the given year is a leap
743         /// year.
744         /// </returns>
745         /// <exception cref="T:System.ArgumentOutOfRangeException">
746         /// The exception is thrown, if the year is not valid
747         /// the current era.
748         /// </exception>
749         public virtual bool IsLeapYear(int year) {
750                 return IsLeapYear(year, CurrentEra);
751         }
752
753         /// <summary>
754         /// Tells when overridden whether the given year
755         /// is a leap year.
756         /// </summary>
757         /// <param name="year">An integer that specifies the year in the
758         /// given era.
759         /// </param>
760         /// <param name="era">An integer that specifies the era.
761         /// </param>
762         /// <returns>A boolean that tells whether the given year is a leap
763         /// year.
764         /// </returns>
765         /// <exception cref="T:System.ArgumentOutOfRangeException">
766         /// The exception is thrown, if the year or era is not
767         /// valid.
768         /// </exception>
769         public abstract bool IsLeapYear(int year, int era);
770
771         /// <summary>
772         /// A virtual method that creates the
773         /// <see cref="T:System.DateTime"/> from the parameters.
774         /// </summary>
775         /// <param name="year">An integer that gives the year in the
776         /// <see cref="M:CurrentEra"/>.
777         /// </param>
778         /// <param name="month">An integer that specifies the month.
779         /// </param>
780         /// <param name="day">An integer that specifies the day.
781         /// </param>
782         /// <param name="hour">An integer that specifies the hour.
783         /// </param>
784         /// <param name="minute">An integer that specifies the minute.
785         /// </param>
786         /// <param name="second">An integer that gives the second.
787         /// </param>
788         /// <param name="milliseconds">An integer that gives the
789         /// milliseconds.
790         /// </param>
791         /// <returns>A
792         /// <see cref="T:system.DateTime"/> representig the date and time.
793         /// </returns>
794         /// <exception cref="T:System.ArgumentOutOfRangeException">
795         /// The exception is thrown, if at least one of the parameters
796         /// is out of range.
797         /// </exception>
798         public virtual DateTime ToDateTime(int year, int month, int day,
799                 int hour, int minute, int second, int milliseconds)
800         {
801                 return ToDateTime(year, month, day, hour, minute, second, 
802                         milliseconds, CurrentEra);
803         }
804
805
806         /// <summary>
807         /// When overridden creates the
808         /// <see cref="T:System.DateTime"/> from the parameters.
809         /// </summary>
810         /// <param name="year">An integer that gives the year in the
811         /// <paramref name="era"/>.
812         /// </param>
813         /// <param name="month">An integer that specifies the month.
814         /// </param>
815         /// <param name="day">An integer that specifies the day.
816         /// </param>
817         /// <param name="hour">An integer that specifies the hour.
818         /// </param>
819         /// <param name="minute">An integer that specifies the minute.
820         /// </param>
821         /// <param name="second">An integer that gives the second.
822         /// </param>
823         /// <param name="milliseconds">An integer that gives the
824         /// milliseconds.
825         /// </param>
826         /// <param name="era">An integer that specifies the era.
827         /// </param>
828         /// <returns>A
829         /// <see cref="T:system.DateTime"/> representig the date and time.
830         /// </returns>
831         /// <exception cref="T:System.ArgumentOutOfRangeException">
832         /// The exception is thrown, if at least one of the parameters
833         /// is out of range.
834         /// </exception>
835         public abstract DateTime ToDateTime(int year, int month, int day,
836                 int hour, int minute, int second, int milliseconds,
837                 int era);
838
839         /// <summary>
840         /// A virtual method that converts a two-digit year to a four-digit
841         /// year. It uses the <see cref="M:TwoDigitYearMax"/> property.
842         /// </summary>
843         /// <param name="year">An integer that gives the two-digit year.
844         /// </param>
845         /// <returns>An integer giving the four digit year.
846         /// </returns>
847         /// <exception cref="T:System.ArgumentOutOfRangeException">
848         /// The exception is thrown if the year is negative or the resulting 
849         /// year is invalid.
850         /// </exception>
851         public virtual int ToFourDigitYear(int year) {
852                 if (year < 0)
853                         throw new ArgumentOutOfRangeException(
854                                 "year", "Non-negative number required.");
855                 /* seems not to be the right thing to do, but .NET is
856                  * doing it this way.
857                  */
858                 if (year <= 99) {
859                         int year2 = TwoDigitYearMax%100;
860                         int d = year - year2;
861                         year = TwoDigitYearMax + d + (d <= 0 ? 0 : -100); 
862                 }
863                 int era = CurrentEra;
864                 M_CheckYE(year, ref era);
865                 return year;
866         }
867
868         // TwoDigitYearMax: Windows reads it from the Registry, we
869         // should have an XML file with the defaults
870         /// <summary>
871         /// The default constructor, is sets the TwoDigitYearMax to 2029.
872         /// </summary>
873         /// <remarks>
874         /// The .NET framework reads the value from the registry.
875         /// We should implement it here. Currently I set the default values
876         /// in the ctors of the derived classes, if it is 99.
877         /// </remarks>
878         protected Calendar() {
879                 M_TwoDigitYearMax = 99;
880         }
881
882         /// <summary>Protected field storing the abbreviated era names.
883         /// </summary>
884         internal string[] M_AbbrEraNames;
885         /// <summary>Protected field storing the era names.
886         /// </summary>
887         internal string[] M_EraNames;
888
889         /// <value>
890         /// The property stores the era names. It might be overwritten by
891         /// CultureInfo.
892         /// </value>
893         internal string[] AbbreviatedEraNames {
894                 get {
895                         if (M_AbbrEraNames == null ||
896                             M_AbbrEraNames.Length != Eras.Length)
897                                 throw new Exception(
898                                         "Internal: M_AbbrEraNames " +
899                                         "wrong initialized!");
900                         return (string[])M_AbbrEraNames.Clone();
901                 }
902                 set {
903                         if (value.Length != Eras.Length) {
904                                 StringWriter sw = new StringWriter();
905                                 sw.Write("Array length must be equal Eras " +
906                                         "length {0}.", Eras.Length);
907                                 throw new ArgumentException(
908                                         sw.ToString());
909                         } 
910                         M_AbbrEraNames = (string[])value.Clone();
911                 }
912         }
913
914         /// <value>
915         /// The property stores the era names. It might be overwritten by
916         /// CultureInfo.
917         /// </value>
918         internal string[] EraNames {
919                 get {
920                         if (M_EraNames == null ||
921                             M_EraNames.Length != Eras.Length)
922                                 throw new Exception(
923                                         "Internal: M_EraNames " +
924                                         "not initialized!");
925                         return (string[])M_EraNames.Clone();
926                 }
927                 set {
928                         if (value.Length != Eras.Length) {
929                                 StringWriter sw = new StringWriter();
930                                 sw.Write("Array length must be equal Eras " +
931                                         "length {0}.", Eras.Length);
932                                 throw new ArgumentException(
933                                         sw.ToString());
934                         } 
935                         M_EraNames = (string[])value.Clone();
936                 }
937         }
938 } // class Calendar
939         
940 } // namespace System.Globalization