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