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