2008-01-15 Stephane Delcroix <sdelcroix@novell.com>
[mono.git] / mcs / class / corlib / System.Globalization / CalendricalCalculations.cs
1 // CalendricalCalculations.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.Collections;
32
33 /// <summary>A class that provides mathematical functions.</summary>
34 /// <remarks>
35 /// <para>
36 /// We are breaking the .Net
37 /// naming conventions to be compatible to the "Calendrical Calculations"
38 /// bool. 
39 /// </para>
40 /// </remarks>
41 internal class CCMath {
42         /// <summary>
43         /// A static method which rounds a double value.
44         /// </summary>
45         /// <param name="x">The double value to round.</param>
46         /// <returns>The rounded double.</returns>
47         public static double round(double x) {
48                 return System.Math.Floor(x+0.5);
49         }
50
51         /// <summary>
52         /// A static method that computes the remainder of the division
53         /// of two doubles.
54         /// </summary>
55         /// <param name="x">The double value which is divided.</param>
56         /// <param name="y">The divisor.</param>
57         /// <returns>The remainder as double value.</returns>
58         public static double mod(double x, double y) {
59                 return x - y * System.Math.Floor(x/y);
60         }
61
62         /// <summary>
63         /// The static method divides two integers.
64         /// </summary>
65         /// <param name="x">The integer x value.</param>
66         /// <param name="y">The integer y value.</param>
67         /// <returns>The qotient of x and y defined by floor(x/y).
68         /// </returns>
69         /// <remarks>
70         /// Please notify that the function is not compatible to the standard
71         /// integer divide operation /.
72         /// </remarks>
73         public static int div(int x, int y) {
74                 return (int)System.Math.Floor((double)x/(double)y);
75         }
76
77         /// <summary>
78         /// The static method computes the remainder of two integers.
79         /// </summary>
80         /// <param name="x">The integer value which will be divided.</param>
81         /// <param name="y">The divisor integer value.</param>
82         /// <returns> The remainder as integer value.</returns>
83         /// <remarks>
84         /// Please notify that the method is not compatible to the C#
85         /// remainder operation %.
86         /// </remarks>
87         public static int mod(int x, int y) {
88                 return x - y * div(x, y);
89         }
90
91         /// <summary>
92         /// A static method that combines integer division and remainder
93         /// computation.
94         /// </summary>
95         /// <param name="remainder">Remainder integer output value.
96         /// </param>
97         /// <param name="x">Integer to be divided.</param>
98         /// <param name="y">Divisor integer value.</param>
99         /// <returns>The quotient as integer.</returns>
100         /// <seealso cref="M:div"/>
101         /// <seealso cref="M:mod"/>
102         public static int div_mod(out int remainder, int x, int y) {
103                 int d = div(x, y);
104                 remainder = x - y * d;
105                 return d;
106         }
107
108         /// <summary>
109         /// A static method returning the sign of the argument.
110         /// </summary>
111         /// <param name="x">The double argument.</param>
112         /// <returns>An integer value: -1 for a negative argument;
113         /// 0 for a zero argument, and 1 for a positive argument.
114         /// </returns>
115         public static int signum(double x) {
116                 if (x < 0.0)
117                         return -1;
118                 if (x == 0.0)
119                         return 0;
120                 return 1;
121         }
122
123         /// <summary>
124         /// A static method returning the sign of the integer
125         /// argument.
126         /// </summary>
127         /// <param name="x">The integer argument.</param>
128         /// <returns>An integer value: -1 for a negative argument;
129         /// 0 for a zero argument, and 1 for a positive argument.
130         /// </returns>
131         public static int signum(int x) {
132                 if (x < 0)
133                         return -1;
134                 if (x == 0)
135                         return 0;
136                 return 1;
137         }
138
139         /// <summary>
140         /// An adjusted remainder function as defined in "Calendrical
141         /// Calculations".
142         /// </summary>
143         /// <param name="x">The double x argument.</param>
144         /// <param name="y">The double y argument, the divisor.</param>
145         /// <returns>A double value representing remainder; but instead 0.0
146         /// the divisor y is returned.
147         /// </returns>
148         public static double amod(double x, double y) {
149                 double d = mod(x, y);
150                 return (d == 0.0) ? y : d;
151         }
152
153         /// <summary>
154         /// The adjusted remainder functions for integers as defined in
155         /// "Calendrical Calculations".
156         /// </summary>
157         /// <param name="x">The integer argument to be divided.</param>
158         /// <param name="y">The integer divisor argument.</param>
159         /// <returns>The remainder as an integer; however instead 0 
160         /// is the divisor y returned.
161         /// </returns>
162         public static int amod(int x, int y) {
163                 int i = mod(x, y);
164                 return (i == 0) ? y : i;
165         }
166 }
167
168 /// <summary>The class implements methods to handle the fixed date value from
169 /// the "Calendrical Calculations" books.
170 /// </summary>
171 /// <remarks>
172 /// <para>
173 /// For implementing the Calendar classes I used the algorithms from the
174 /// book "Calendrical Calculations" by Nachum Dershowitz and Edward M.
175 /// Rheingold, second reprint 1998. Trying to prevent the introduction of new
176 /// bugs, I implemented their algorithms in the
177 /// <see cref="N:CalendricalCalculations"/>
178 /// namespace and wrapped it in the calendar classes.
179 /// </para>
180 /// <para>
181 /// The fixed day number is also known as R.D. - rata die.
182 /// Midnight at the onset of Monday,
183 /// January 1, year 1 (Gregorian) is R.D. 1.
184 /// </para>
185 /// <para>Here are all my references:</para>
186 /// <list type="table">
187 /// <item><description>
188 /// [1] Nachum Dershowitz and Edward M. Rheingold: "Calendrical Calculations";
189 /// Cambridge University Press; second reprint 1998.
190 /// </description></item>
191 /// <item><description>
192 /// [2] P. Kenneth Seidelmann (ed.): "Explanatory Supplement to the Astronomical
193 /// Almanac"; University Science Books, Sausalito; 1992 
194 /// </description></item>
195 /// <item><description>
196 /// [3] F. Richard Stephenson: "Historical Eclipses and Earth Rotation";
197 /// Cambridge University Press; 1997
198 /// </description></item>
199 /// </list>
200 /// </remarks>
201 internal class CCFixed {
202         /// <summary>The method computes the
203         /// <see cref="T:System.DateTime"/>
204         /// from a fixed day number.
205         /// </summary>
206         /// <param name="date">A integer representing the fixed day number.
207         /// </param>
208         /// <returns>The <see cref="T:System.DateTime"/> representing
209         /// the date.
210         /// </returns>
211         public static System.DateTime ToDateTime(int date) {
212                 long ticks = (date - 1) * System.TimeSpan.TicksPerDay;
213                 return new System.DateTime(ticks);
214         }
215
216         /// <summary>The method computes the
217         /// <see cref="T:System.DateTime"/>
218         /// from a fixed day number and time arguments.
219         /// </summary>
220         /// <param name="date">An integer representing the fixed day number.
221         /// </param>
222         /// <param name="hour">An integer argument specifying the hour.
223         /// </param>
224         /// <param name="minute">An integer argument specifying the minute.
225         /// </param>
226         /// <param name="second">An integer argument giving the second.
227         /// </param>
228         /// <param name="milliseconds">An double argument specifying
229         /// the milliseconds. Notice that
230         /// <see cref="T:System.DateTime"/> has 100 nanosecond resolution.
231         /// </param>
232         /// <returns>The <see cref="T:System.DateTime"/> representing
233         /// the date.
234         /// </returns>
235         public static System.DateTime ToDateTime(int date,
236                 int hour, int minute, int second, double milliseconds)
237         {
238                 System.DateTime time = ToDateTime(date);
239                 time = time.AddHours(hour);
240                 time = time.AddMinutes(minute);
241                 time = time.AddSeconds(second);
242                 return time.AddMilliseconds(milliseconds);
243         }
244
245         /// <summary>
246         /// A static method computing the fixed day number from a 
247         /// <see cref="T:System.DateTime"/> value.
248         /// </summary>
249         /// <param name="time">A
250         /// <see cref="T:System.DateTime"/> value representing the date.
251         /// </param>
252         /// <returns>The fixed day number as integer representing the date.
253         /// </returns>
254         public static int FromDateTime(System.DateTime time) {
255                 return 1 + (int)(time.Ticks / System.TimeSpan.TicksPerDay);
256         }
257
258         /// <summary>
259         /// The static method computes the <see cref="T:DayOfWeek"/>.
260         /// </summary>
261         /// <param name="date">An integer representing the fixed day number.
262         /// </param>
263         /// <returns>The day of week.</returns>
264         public static DayOfWeek day_of_week(int date) {
265                 return (DayOfWeek)CCMath.mod(date, 7);
266         }
267
268         /// <summary>
269         /// The static method computes the date of a day of week on or before
270         /// a particular date.
271         /// </summary>
272         /// <param name="date">An integer representing the date as
273         /// fixed day number.
274         /// </param>
275         /// <param name="k">An integer representing the day of the week,
276         /// starting with 0 for sunday.
277         /// </param>
278         /// <returns>The fixed day number of the day of week specified by k
279         /// on or before the given date.
280         /// </returns>
281         public static int kday_on_or_before(int date, int k) {
282                 return date - (int)day_of_week(date-k);
283         }
284
285         /// <summary>
286         /// The static method computes the date of a day of week on or after
287         /// a particular date.
288         /// </summary>
289         /// <param name="date">An integer representing the date as
290         /// fixed day number.
291         /// </param>
292         /// <param name="k">An integer representing the day of the week,
293         /// starting with 0 for sunday.
294         /// </param>
295         /// <returns>The fixed day number of the day of week specified by k
296         /// on or after the given date.
297         /// </returns>
298         public static int kday_on_or_after(int date, int k) {
299                 return kday_on_or_before(date+6, k);
300         }
301
302         /// <summary>
303         /// The static method computes the date of a day of week that is
304         /// nearest to a particular date.
305         /// </summary>
306         /// <param name="date">An integer representing the date as
307         /// fixed day number.
308         /// </param>
309         /// <param name="k">An integer representing the day of the week,
310         /// starting with 0 for sunday.
311         /// </param>
312         /// <returns>The fixed day number of the day of week neares to the
313         /// given date.
314         /// </returns>
315         public static int kd_nearest(int date, int k) {
316                 return kday_on_or_before(date+3, k);
317         }
318
319         /// <summary>
320         /// The static method computes the date of a day of week after
321         /// a particular date.
322         /// </summary>
323         /// <param name="date">An integer representing the date as
324         /// fixed day number.
325         /// </param>
326         /// <param name="k">An integer representing the day of the week,
327         /// starting with 0 for sunday.
328         /// </param>
329         /// <returns>The fixed day number of the day of week specified by k
330         /// after the given date.
331         /// </returns>
332         public static int kday_after(int date, int k) {
333                 return kday_on_or_before(date+7, k);
334         }
335
336         /// <summary>
337         /// The static method computes the date of a day of week before
338         /// a particular date.
339         /// </summary>
340         /// <param name="date">An integer representing the date as
341         /// fixed day number.
342         /// </param>
343         /// <param name="k">An integer representing the day of the week,
344         /// starting with 0 for sunday.
345         /// </param>
346         /// <returns>The fixed day number of the day of week specified by k
347         /// before the given date.
348         /// </returns>
349         public static int kday_before(int date, int k) {
350                 return kday_on_or_before(date-1, k);
351         }
352 } // class CCFixed
353
354 /// <summary>
355 /// A class encapsulating the functions of the Gregorian calendar as static
356 /// methods.
357 /// </summary>
358 /// <remarks>
359 /// <para>
360 /// This class is not compatible to
361 /// <see cref="T:System.Globalization.GregorianCalendar"/>.
362 /// </para>
363 /// <para>
364 /// The fixed day number is also known as R.D. - rata die.
365 /// Midnight at the onset of Monday,
366 /// January 1, year 1 (Gregorian) is R.D. 1.
367 /// </para>
368 /// <seealso cref="T:CCFixed"/>
369 /// </remarks>
370 internal class CCGregorianCalendar {
371         /// <summary>An integer defining the epoch of the Gregorian calendar
372         /// as fixed day number.</summary>
373         /// <remarks>The epoch is January 3, 1 C.E. (Julian).</remarks>
374         const int epoch = 1;
375
376         /// <summary>The enumeration defines the months of the Gregorian
377         /// calendar.
378         /// </summary>
379         public enum Month {
380                 /// <summary>
381                 /// January.
382                 /// </summary>
383                 january = 1,
384                 /// <summary>
385                 /// February.
386                 /// </summary>
387                 february,
388                 /// <summary>
389                 /// March.
390                 /// </summary>
391                 march,
392                 /// <summary>
393                 /// April.
394                 /// </summary>
395                 april,
396                 /// <summary>
397                 /// May.
398                 /// </summary>
399                 may,
400                 /// <summary>
401                 /// June.
402                 /// </summary>
403                 june,
404                 /// <summary>
405                 /// July.
406                 /// </summary>
407                 july,
408                 /// <summary>
409                 /// August.
410                 /// </summary>
411                 august,
412                 /// <summary>
413                 /// September.
414                 /// </summary>
415                 september,
416                 /// <summary>
417                 /// October.
418                 /// </summary>
419                 october,
420                 /// <summary>
421                 /// November.
422                 /// </summary>
423                 november,
424                 /// <summary>
425                 /// December.
426                 /// </summary>
427                 december
428         };
429
430
431         /// <summary>
432         /// The method tells whether the year is a leap year.
433         /// </summary>
434         /// <param name="year">An integer representing the Gregorian year.
435         /// </param>
436         /// <returns>A boolean which is true if <paramref name="year"/> is
437         /// a leap year.
438         /// </returns>
439         public static bool is_leap_year(int year) {
440                 if (CCMath.mod(year, 4) != 0)
441                         return false;
442                 switch (CCMath.mod(year, 400)) {
443                         case 100: 
444                                 return false;
445                         case 200:
446                                 return false;
447                         case 300:
448                                 return false;
449                 }
450                 return true;
451         }
452
453         /// <summary>
454         /// The method returns the fixed day number of the given Gregorian
455         /// date.
456         /// </summary>
457         /// <param name="day">An integer representing the day of the month,
458         /// counting from 1.
459         /// </param>
460         /// <param name="month">An integer representing the month in the
461         /// Gregorian year.
462         /// </param>
463         /// <param name="year">An integer representing the Gregorian year.
464         /// Non-positive values are allowed also.
465         /// </param>
466         /// <returns>An integer value representing the fixed day number.
467         /// </returns>
468         public static int fixed_from_dmy(int day, int month, int year) {
469                 int k = epoch - 1;
470                 k += 365 * (year-1);
471                 k += CCMath.div(year-1, 4);
472                 k -= CCMath.div(year-1, 100);
473                 k += CCMath.div(year-1, 400);
474                 k += CCMath.div(367*month-362, 12);
475                 if (month > 2) {
476                         k += is_leap_year(year) ? -1 : -2;
477                 }
478
479                 k += day;
480
481                 return k;
482         }
483
484         /// <summary>
485         /// The method computes the Gregorian year from a fixed day number.
486         /// </summary>
487         /// <param name="date">The fixed day number.
488         /// </param>
489         /// <returns>An integer value giving the Gregorian year of the date.
490         /// </returns>
491         public static int year_from_fixed(int date) {
492                 int d           = date - epoch;
493                 int n_400       = CCMath.div_mod(out d, d, 146097);
494                 int n_100       = CCMath.div_mod(out d, d, 36524);
495                 int n_4         = CCMath.div_mod(out d, d, 1461);
496                 int n_1         = CCMath.div(d, 365);
497
498                 int year = 400*n_400 + 100*n_100 + 4*n_4 + n_1;
499                 return (n_100 == 4 || n_1 == 4) ? year : year + 1;
500         }
501
502         /// <summary>
503         /// The method computes the Gregorian year and month from a fixed day
504         /// number.
505         /// </summary>
506         /// <param name="month">The output value giving the Gregorian month.
507         /// </param>
508         /// <param name="year">The output value giving the Gregorian year.
509         /// </param>
510         /// <param name="date">An integer value specifying the fixed day
511         /// number.</param>
512         public static void my_from_fixed(out int month, out int year,
513                 int date)
514         {
515                 year = year_from_fixed(date);
516
517                 int prior_days = date - fixed_from_dmy(1, (int)Month.january,
518                         year);
519                 
520                 int correction;
521                 if (date < fixed_from_dmy(1, (int)Month.march, year)) {
522                         correction = 0;
523                 } else if (is_leap_year(year)) {
524                         correction = 1;
525                 } else {
526                         correction = 2;
527                 }
528
529                 month = CCMath.div(12 * (prior_days + correction) + 373, 367);
530
531         }
532
533         /// <summary>
534         /// The method computes the Gregorian year, month, and day from a
535         /// fixed day number.
536         /// </summary>
537         /// <param name="day">The output value returning the day of the
538         /// month.
539         /// </param>
540         /// <param name="month">The output value giving the Gregorian month.
541         /// </param>
542         /// <param name="year">The output value giving the Gregorian year.
543         /// </param>
544         /// <param name="date">An integer value specifying the fixed day
545         /// number.</param>
546         public static void dmy_from_fixed(out int day, out int month,
547                 out int year,
548                 int date)
549         {
550                 my_from_fixed(out month, out year, date);
551                 day = date - fixed_from_dmy(1, month, year) + 1;
552         }
553
554         /// <summary>A method computing the Gregorian month from a fixed
555         /// day number.
556         /// </summary>
557         /// <param name="date">An integer specifying the fixed day number.
558         /// </param>
559         /// <returns>An integer value representing the Gregorian month.
560         /// </returns>
561         public static int month_from_fixed(int date) {
562                 int month, year;
563
564                 my_from_fixed(out month, out year, date);
565                 return month;
566         }
567
568         /// <summary>
569         /// A method computing the day of the month from a fixed day number.
570         /// </summary>
571         /// <param name="date">An integer specifying the fixed day number.
572         /// </param>
573         /// <returns>An integer value representing the day of the month.
574         /// </returns>
575         public static int day_from_fixed(int date) {
576                 int day, month, year;
577
578                 dmy_from_fixed(out day, out month, out year, date);
579                 return day;
580         }
581
582         /// <summary>
583         /// The method computes the difference between two Gregorian dates.
584         /// </summary>
585         /// <param name="dayA">The integer parameter gives the day of month
586         /// of the first date.
587         /// </param>
588         /// <param name="monthA">The integer parameter gives the Gregorian
589         /// month of the first date.
590         /// </param>
591         /// <param name="yearA">The integer parameter gives the Gregorian
592         /// year of the first date.
593         /// </param>
594         /// <param name="dayB">The integer parameter gives the day of month
595         /// of the second date.
596         /// </param>
597         /// <param name="monthB">The integer parameter gives the Gregorian
598         /// month of the second date.
599         /// </param>
600         /// <param name="yearB">The integer parameter gives the Gregorian
601         /// year of the second date.
602         /// </param>
603         /// <returns>An integer giving the difference of days from the first
604         /// the second date.
605         /// </returns>
606         public static int date_difference(int dayA, int monthA, int yearA,
607                 int dayB, int monthB, int yearB)
608         {
609                 return  fixed_from_dmy(dayB, monthB, yearB) -
610                         fixed_from_dmy(dayA, monthA, yearA);
611         }
612
613         /// <summary>
614         /// The method computes the number of the day in the year from
615         /// a Gregorian date.
616         /// </summary>
617         /// <param name="day">An integer representing the day of the month,
618         /// counting from 1.
619         /// </param>
620         /// <param name="month">An integer representing the month in the
621         /// Gregorian year.
622         /// </param>
623         /// <param name="year">An integer representing the Gregorian year.
624         /// Non-positive values are allowed also.
625         /// </param>
626         /// <returns>An integer value giving the number of the day in the
627         /// Gregorian year, counting from 1.
628         /// </returns>
629         public static int day_number(int day, int month, int year) {
630                 return date_difference(31, (int)Month.december, year-1,
631                         day, month, year);
632         }
633
634         /// <summary>
635         /// The method computes the days remaining in the given Gregorian
636         /// year from a Gregorian date.
637         /// </summary>
638         /// <param name="day">An integer representing the day of the month,
639         /// counting from 1.
640         /// </param>
641         /// <param name="month">An integer representing the month in the
642         /// Gregorian year.
643         /// </param>
644         /// <param name="year">An integer representing the Gregorian year.
645         /// Non-positive values are allowed also.
646         /// </param>
647         /// <returns>An integer value giving the number of days remaining in
648         /// the Gregorian year.
649         /// </returns>
650         public static int days_remaining(int day, int month, int year) {
651                 return date_difference(day, month, year,
652                         31, (int)Month.december, year);
653         }
654
655         // Helper functions for the Gregorian calendars.
656
657         /// <summary>
658         /// Adds months to the given date.
659         /// </summary>
660         /// <param name="time">The
661         /// <see cref="T:System.DateTime"/> to which to add
662         /// months.
663         /// </param>
664         /// <param name="months">The number of months to add.</param>
665         /// <returns>A new <see cref="T:System.DateTime"/> value, that
666         /// results from adding <paramref name="months"/> to the specified
667         /// DateTime.</returns>
668         public static System.DateTime AddMonths(System.DateTime time,
669                 int months)
670         {
671                 int rd = CCFixed.FromDateTime(time);
672                 int day, month, year;
673                 dmy_from_fixed(out day, out month, out year, rd);
674                 month += months;
675                 year += CCMath.div_mod(out month, month, 12);
676                 int maxday = GetDaysInMonth (year, month);
677                 if (day > maxday)
678                         day = maxday;
679                 rd = fixed_from_dmy(day, month, year);
680                 System.DateTime t = CCFixed.ToDateTime(rd);
681                 return t.Add(time.TimeOfDay);
682         }
683
684         /// <summary>
685         /// Adds years to the given date.
686         /// </summary>
687         /// <param name="time">The
688         /// <see cref="T:System.DateTime"/> to which to add
689         /// months.
690         /// </param>
691         /// <param name="years">The number of years to add.</param>
692         /// <returns>A new <see cref="T:System.DateTime"/> value, that
693         /// results from adding <paramref name="years"/> to the specified
694         /// DateTime.</returns>
695         public static System.DateTime AddYears(System.DateTime time,
696                 int years)
697         {
698                 int rd = CCFixed.FromDateTime(time);
699                 int day, month, year;
700                 dmy_from_fixed(out day, out month, out year, rd);
701                 year += years;
702                 int maxday = GetDaysInMonth (year, month);
703                 if (day > maxday)
704                         day = maxday;
705                 rd = fixed_from_dmy(day, month, year);
706                 System.DateTime t = CCFixed.ToDateTime(rd);
707                 return t.Add(time.TimeOfDay);
708         }
709
710         /// <summary>
711         /// Gets the of the month from <paramref name="time"/>.
712         /// </summary>
713         /// <param name="time">The
714         /// <see cref="T:System.DateTime"/> that specifies a
715         /// date.
716         /// </param>
717         /// <returns>An integer giving the day of months, starting with 1.
718         /// </returns>
719         public static int GetDayOfMonth(System.DateTime time) {
720                 return day_from_fixed(CCFixed.FromDateTime(time));
721         }
722
723         /// <summary>
724         /// The method gives the number of the day in the year.
725         /// </summary>
726         /// <param name="time">The
727         /// <see cref="T:System.DateTime"/> that specifies a
728         /// date.
729         /// </param>
730         /// <returns>An integer representing the day of the year,
731         /// starting with 1.</returns>
732         public static int GetDayOfYear(System.DateTime time) {
733                 int rd = CCFixed.FromDateTime(time);
734                 int year = year_from_fixed(rd);
735                 int rd1_1 = fixed_from_dmy(1, 1, year);
736                 return rd - rd1_1 + 1;
737         }
738
739         /// <summary>
740         /// A method that gives the number of days of the specified
741         /// month of the <paramref name="year"/>.
742         /// </summary>
743         /// <param name="year">An integer that gives the year in the current
744         /// era.</param>
745         /// <param name="month">An integer that gives the month, starting
746         /// with 1.</param>
747         /// <returns>An integer that gives the number of days of the
748         /// specified month.</returns>
749         public static int GetDaysInMonth(int year, int month) {
750                 int rd1 = fixed_from_dmy(1, month, year);
751                 int rd2 = fixed_from_dmy(1, month+1, year);
752                 return rd2 - rd1;
753         }
754
755         /// <summary>
756         /// The method gives the number of days in the specified year.
757         /// </summary>
758         /// <param name="year">An integer that gives the year.
759         /// </param>
760         /// <returns>An integer that gives the number of days of the
761         /// specified year.</returns>
762         public static int GetDaysInYear(int year) {
763                 int rd1 = fixed_from_dmy(1, 1, year);
764                 int rd2 = fixed_from_dmy(1, 1, year+1);
765                 return rd2 - rd1;
766         }
767
768         /// <summary>
769         /// The method gives the number of the month of the specified
770         /// date.
771         /// </summary>
772         /// <param name="time">The
773         /// <see cref="T:System.DateTime"/> that specifies a
774         /// date.
775         /// </param>
776         /// <returns>An integer representing the month, 
777         /// starting with 1.</returns>
778         public static int GetMonth(System.DateTime time) {
779                 return month_from_fixed(CCFixed.FromDateTime(time));
780         }
781
782         /// <summary>
783         /// The method gives the number of the year of the specified
784         /// date.
785         /// </summary>
786         /// <param name="time">The
787         /// <see cref="T:System.DateTime"/> that specifies a
788         /// date.
789         /// </param>
790         /// <returns>An integer representing the year. 
791         /// </returns>
792         public static int GetYear(System.DateTime time) {
793                 return year_from_fixed(CCFixed.FromDateTime(time));
794         }
795
796         /// <summary>
797         /// A virtual method that tells whether the given day
798         /// is a leap day.
799         /// </summary>
800         /// <param name="year">An integer that specifies the year.
801         /// </param>
802         /// <param name="month">An integer that specifies the month.
803         /// </param>
804         /// <param name="day">An integer that specifies the day.
805         /// </param>
806         /// <returns>A boolean that tells whether the given day is a leap
807         /// day.
808         /// </returns>
809         public static bool IsLeapDay(int year, int month, int day) {
810                 return is_leap_year(year) && month == 2 && day == 29;
811         }
812
813         /// <summary>
814         /// A method that creates the
815         /// <see cref="T:System.DateTime"/> from the parameters.
816         /// </summary>
817         /// <param name="year">An integer that gives the year
818         /// </param>
819         /// <param name="month">An integer that specifies the month.
820         /// </param>
821         /// <param name="day">An integer that specifies the day.
822         /// </param>
823         /// <param name="hour">An integer that specifies the hour.
824         /// </param>
825         /// <param name="minute">An integer that specifies the minute.
826         /// </param>
827         /// <param name="second">An integer that gives the second.
828         /// </param>
829         /// <param name="milliseconds">An integer that gives the
830         /// milliseconds.
831         /// </param>
832         /// <returns>A
833         /// <see cref="T:system.DateTime"/> representig the date and time.
834         /// </returns>
835         public static System.DateTime ToDateTime(int year, int month, int day,
836                 int hour, int minute, int second, int milliseconds)
837         {
838                 return CCFixed.ToDateTime(fixed_from_dmy(day, month, year),
839                         hour, minute, second, milliseconds);
840         }
841 } // class CCGregorianCalendar
842
843 /// <summary>
844 /// A class encapsulating the functions of the Julian calendar as static
845 /// methods.
846 /// </summary>
847 /// <remarks>
848 /// <para>The algorithms don't support a year 0. Years before Common Era
849 /// (B.C.E. or B.C.) are negative and years of Common Era (C.E. or A.D.)
850 /// are positive.
851 /// </para>
852 /// <para>
853 /// This class is not compatible to
854 /// <see cref="T:System.Globalization.JulianCalendar"/>.
855 /// </para>
856 /// <seealso cref="T:CCFixed"/>
857 /// </remarks>
858 internal class CCJulianCalendar {
859         /// <summary>An integer defining the epoch of the Julian calendar
860         /// as fixed day number.</summary>
861         /// <remarks>The epoch is December 30, 0 (Gregorian).</remarks>
862         const int epoch = -1; // 30. 12. 0 Gregorian
863
864         /// <summary>The enumeration defines the months of the Julian
865         /// calendar.
866         /// </summary>
867         public enum Month {
868                 /// <summary>
869                 /// January.
870                 /// </summary>
871                 january = 1,
872                 /// <summary>
873                 /// February.
874                 /// </summary>
875                 february,
876                 /// <summary>
877                 /// March.
878                 /// </summary>
879                 march,
880                 /// <summary>
881                 /// April.
882                 /// </summary>
883                 april,
884                 /// <summary>
885                 /// May.
886                 /// </summary>
887                 may,
888                 /// <summary>
889                 /// June.
890                 /// </summary>
891                 june,
892                 /// <summary>
893                 /// July.
894                 /// </summary>
895                 july,
896                 /// <summary>
897                 /// August.
898                 /// </summary>
899                 august,
900                 /// <summary>
901                 /// September.
902                 /// </summary>
903                 september,
904                 /// <summary>
905                 /// October.
906                 /// </summary>
907                 october,
908                 /// <summary>
909                 /// November.
910                 /// </summary>
911                 november,
912                 /// <summary>
913                 /// December.
914                 /// </summary>
915                 december
916         };
917
918         /// <summary>
919         /// The method tells whether the year is a leap year.
920         /// </summary>
921         /// <param name="year">An integer representing the Julian year.
922         /// </param>
923         /// <returns>A boolean which is true if <paramref name="year"/> is
924         /// a leap year.
925         /// </returns>
926         public static bool is_leap_year(int year) {
927                 return CCMath.mod(year, 4) == (year > 0 ? 0 : 3);
928         }
929
930         /// <summary>
931         /// The method returns the fixed day number of the given Julian
932         /// date.
933         /// </summary>
934         /// <param name="day">An integer representing the day of the month,
935         /// counting from 1.
936         /// </param>
937         /// <param name="month">An integer representing the month in the
938         /// Julian year.
939         /// </param>
940         /// <param name="year">An integer representing the Julian year.
941         /// Positive and Negative values are allowed.
942         /// </param>
943         /// <returns>An integer value representing the fixed day number.
944         /// </returns>
945         public static int fixed_from_dmy(int day, int month, int year) {
946                 int y = year < 0 ? year+1 : year;
947                 int k = epoch - 1;
948                 k += 365 * (y-1);
949                 k += CCMath.div(y-1, 4);
950                 k += CCMath.div(367*month-362, 12);
951                 if (month > 2) {
952                         k += is_leap_year(year) ? -1 : -2;
953                 }
954                 k += day;
955
956                 return k;
957         }
958
959         /// <summary>
960         /// The method computes the Julian year from a fixed day number.
961         /// </summary>
962         /// <param name="date">The fixed day number.
963         /// </param>
964         /// <returns>An integer value giving the Julian year of the date.
965         /// </returns>
966         public static int year_from_fixed(int date) {
967                 int approx = CCMath.div(4*(date-epoch)+1464, 1461);
968                 return approx <= 0 ? approx - 1 : approx;
969         }
970
971         /// <summary>
972         /// The method computes the Julian year and month from a fixed day
973         /// number.
974         /// </summary>
975         /// <param name="month">The output value giving the Julian month.
976         /// </param>
977         /// <param name="year">The output value giving the Julian year.
978         /// </param>
979         /// <param name="date">An integer value specifying the fixed day
980         /// number.</param>
981         public static void my_from_fixed(out int month, out int year, int date)
982         {
983                 year = year_from_fixed(date);
984
985                 int prior_days = date - fixed_from_dmy(1, (int)Month.january,
986                         year);
987                 
988                 int correction;
989                 if (date < fixed_from_dmy(1, (int)Month.march, year)) {
990                         correction = 0;
991                 } else if (is_leap_year(year)) {
992                         correction = 1;
993                 } else {
994                         correction = 2;
995                 }
996
997                 month = CCMath.div(12 * (prior_days + correction) + 373, 367);
998         }
999         
1000
1001         /// <summary>
1002         /// The method computes the Julian year, month, and day from a
1003         /// fixed day number.
1004         /// </summary>
1005         /// <param name="day">The output value returning the day of the
1006         /// month.
1007         /// </param>
1008         /// <param name="month">The output value giving the Julian month.
1009         /// </param>
1010         /// <param name="year">The output value giving the Julian year.
1011         /// </param>
1012         /// <param name="date">An integer value specifying the fixed day
1013         /// number.</param>
1014         public static void dmy_from_fixed(out int day, out int month,
1015                 out int year, int date)
1016         {
1017                 my_from_fixed(out month, out year, date);
1018                 day = date - fixed_from_dmy(1, month, year) + 1;
1019         }
1020
1021         /// <summary>A method computing the Julian month from a fixed
1022         /// day number.
1023         /// </summary>
1024         /// <param name="date">An integer specifying the fixed day number.
1025         /// </param>
1026         /// <returns>An integer value representing the Julian month.
1027         /// </returns>
1028         public static int month_from_fixed(int date) {
1029                 int month, year;
1030
1031                 my_from_fixed(out month, out year, date);
1032                 return month;
1033         }
1034
1035         /// <summary>
1036         /// A method computing the day of the month from a fixed day number.
1037         /// </summary>
1038         /// <param name="date">An integer specifying the fixed day number.
1039         /// </param>
1040         /// <returns>An integer value representing the day of the month.
1041         /// </returns>
1042         public static int day_from_fixed(int date) {
1043                 int day;
1044                 int month;
1045                 int year;
1046
1047                 dmy_from_fixed(out day, out month, out year, date);
1048                 return day;
1049         }
1050
1051         /// <summary>
1052         /// The method computes the difference between two Julian dates.
1053         /// </summary>
1054         /// <param name="dayA">The integer parameter gives the day of month
1055         /// of the first date.
1056         /// </param>
1057         /// <param name="monthA">The integer parameter gives the Julian
1058         /// month of the first date.
1059         /// </param>
1060         /// <param name="yearA">The integer parameter gives the Julian
1061         /// year of the first date.
1062         /// </param>
1063         /// <param name="dayB">The integer parameter gives the day of month
1064         /// of the second date.
1065         /// </param>
1066         /// <param name="monthB">The integer parameter gives the Julian
1067         /// month of the second date.
1068         /// </param>
1069         /// <param name="yearB">The integer parameter gives the Julian
1070         /// year of the second date.
1071         /// </param>
1072         /// <returns>An integer giving the difference of days from the first
1073         /// the second date.
1074         /// </returns>
1075         public static int date_difference(int dayA, int monthA, int yearA,
1076                 int dayB, int monthB, int yearB)
1077         {
1078                 return  fixed_from_dmy(dayB, monthB, yearB) -
1079                         fixed_from_dmy(dayA, monthA, yearA);
1080         }
1081
1082         /// <summary>
1083         /// The method computes the number of the day in the year from
1084         /// a Julian date.
1085         /// </summary>
1086         /// <param name="day">An integer representing the day of the month,
1087         /// counting from 1.
1088         /// </param>
1089         /// <param name="month">An integer representing the month in the
1090         /// Julian year.
1091         /// </param>
1092         /// <param name="year">An integer representing the Julian year.
1093         /// Negative values are allowed also.
1094         /// </param>
1095         /// <returns>An integer value giving the number of the day in the
1096         /// Julian year, counting from 1.
1097         /// </returns>
1098         public static int day_number(int day, int month, int year) {
1099                 return date_difference(31, (int)Month.december, year-1,
1100                         day, month, year);
1101         }
1102
1103         /// <summary>
1104         /// The method computes the days remaining in the given Julian
1105         /// year from a Julian date.
1106         /// </summary>
1107         /// <param name="day">An integer representing the day of the month,
1108         /// counting from 1.
1109         /// </param>
1110         /// <param name="month">An integer representing the month in the
1111         /// Julian year.
1112         /// </param>
1113         /// <param name="year">An integer representing the Julian year.
1114         /// Negative values are allowed also.
1115         /// </param>
1116         /// <returns>An integer value giving the number of days remaining in
1117         /// the Julian year.
1118         /// </returns>
1119         public static int days_remaining(int day, int month, int year) {
1120                 return date_difference(day, month, year,
1121                         31, (int)Month.december, year);
1122         }
1123 } // class CCJulianCalendar
1124
1125 /// <summary>
1126 /// A class encapsulating the functions of the Hebrew calendar as static
1127 /// methods.
1128 /// </summary>
1129 /// <remarks>
1130 /// <para>
1131 /// This class is not compatible to
1132 /// <see cref="T:System.Globalization.HebrewCalendar"/>.
1133 /// </para>
1134 /// <seealso cref="T:CCFixed"/>
1135 /// </remarks>
1136 internal class CCHebrewCalendar {
1137         /// <summary>An integer defining the epoch of the Hebrew calendar
1138         /// as fixed day number.</summary>
1139         /// <remarks>The epoch is October 10, 3761 B.C.E. (Julian).</remarks>
1140         const int epoch = -1373427;
1141
1142         /// <summary>The enumeration defines the months of the Gregorian
1143         /// calendar.
1144         /// </summary>
1145         /// <remarks>
1146         /// The enumaration differs from .NET which defines Tishri as month 1.
1147         /// </remarks>
1148         public enum Month {
1149                 /// <summary>
1150                 /// Nisan.
1151                 /// </summary>
1152                 nisan    = 1,
1153                 /// <summary>
1154                 /// Iyyar.
1155                 /// </summary>
1156                 iyyar,
1157                 /// <summary>
1158                 /// Sivan.
1159                 /// </summary>
1160                 sivan,
1161                 /// <summary>
1162                 /// Tammuz.
1163                 /// </summary>
1164                 tammuz,
1165                 /// <summary>
1166                 /// Av.
1167                 /// </summary>
1168                 av,
1169                 /// <summary>
1170                 /// Elul.
1171                 /// </summary>
1172                 elul,
1173                 /// <summary>
1174                 /// Tishri.
1175                 /// </summary>
1176                 tishri,
1177                 /// <summary>
1178                 /// Heshvan.
1179                 /// </summary>
1180                 heshvan,
1181                 /// <summary>
1182                 /// Kislev.
1183                 /// </summary>
1184                 kislev,
1185                 /// <summary>
1186                 /// Teveth.
1187                 /// </summary>
1188                 teveth,
1189                 /// <summary>
1190                 /// Shevat.
1191                 /// </summary>
1192                 shevat,
1193                 /// <summary>
1194                 /// Adar.
1195                 /// </summary>
1196                 adar,
1197                 /// <summary>
1198                 /// Adar I. Only in years with Adar II.
1199                 /// </summary>
1200                 adar_I = 12,
1201                 /// <summary>
1202                 /// Adar II. Only in years wirh Adar I.
1203                 /// </summary>
1204                 adar_II = 13,
1205         };
1206
1207         /// <summary>
1208         /// The method tells whether the year is a leap year.
1209         /// </summary>
1210         /// <param name="year">An integer representing the Hebrew year.
1211         /// </param>
1212         /// <returns>A boolean which is true if <paramref name="year"/> is
1213         /// a leap year.
1214         /// </returns>
1215         public static bool is_leap_year(int year) {
1216                 return CCMath.mod(7*year+1, 19) < 7; 
1217         }
1218
1219         /// <summary>
1220         /// The Method gives the number of the last month in a year, which
1221         /// is equal with the number of month in a Hebrew year.
1222         /// </summary>
1223         /// <param name="year">An integer representing the Hebrew year.
1224         /// </param>
1225         /// <returns>An integer giving the number of the last month of the 
1226         /// Hebrew year, which is the same as the numbers of month in the
1227         /// year.
1228         /// </returns>
1229         public static int last_month_of_year(int year) {
1230                 return is_leap_year(year) ? 13 : 12;
1231         }
1232
1233         
1234         /// <summary>The method is a helper function.</summary>
1235         /// <param name="year">An integer specifying the Hebrew year.
1236         /// </param>
1237         /// <returns>An integer representing the number of elapsed days
1238         /// until the Hebrew year.</returns>
1239         public static int elapsed_days(int year) {
1240                 int months_elapsed = CCMath.div(235*year-234, 19);
1241                 int r;
1242                 int d = CCMath.div_mod(out r, months_elapsed, 1080);
1243                 int parts_elapsed = 204 + 793 * r;
1244                 int hours_elapsed = 11 + 12 * months_elapsed +
1245                                     793 * d + CCMath.div(parts_elapsed, 1080);
1246
1247                 int day = 29*months_elapsed + CCMath.div(hours_elapsed, 24);
1248
1249                 if (CCMath.mod(3*(day+1), 7) < 3) {
1250                         day += 1;
1251                 }
1252
1253                 return day;
1254         }
1255
1256         /// <summary>A method computing the delay of new year for the given
1257         /// Hebrew year.
1258         /// </summary>
1259         /// <param name="year">An integer that gives the Hebrew year.
1260         /// </param>
1261         /// <returns>The new year delay in days of the given Hebrew year.
1262         /// </returns>
1263         public static int new_year_delay(int year) {
1264                 int ny1 = elapsed_days(year);
1265                 int ny2 = elapsed_days(year+1);
1266
1267                 if (ny2 - ny1 == 356) {
1268                         return 2;
1269                 }
1270                 int ny0 = elapsed_days(year-1);
1271                 if (ny1 - ny0 == 382) {
1272                         return 1;
1273                 }
1274                 return 0;
1275         }
1276
1277         /// <summary>
1278         /// The method computes the last day of month (nummer of days in a
1279         /// month) of the given Hebrew year.
1280         /// </summary>
1281         /// <param name="month">The Hebrew month, allowed value between
1282         /// One and Thirteen.
1283         /// </param>
1284         /// <param name="year">An integer that gives the Hebrew year.
1285         /// </param>
1286         /// <returns>The number of the last day of the month of the given
1287         /// Hebrew year, which gives automatically the number of days in the
1288         /// month.
1289         /// </returns>
1290         /// <exception cref="T:System.ArgumentOutOfRange.Exception">
1291         /// The exception is thrown if month not between One and Thirteen.
1292         /// </exception>
1293         public static int last_day_of_month(int month, int year) {
1294                 if (month < 1 || month > 13)
1295                         throw new System.ArgumentOutOfRangeException("month",
1296                                 "Month should be between One and Thirteen.");
1297                 switch (month) {
1298                         case 2: return 29;
1299                         case 4: return 29;
1300                         case 6: return 29;
1301                         case 8:
1302                                 if (!long_heshvan(year))
1303                                         return 29;
1304                                 break;
1305                         case 9:
1306                                 if (short_kislev(year))
1307                                         return 29;
1308                                 break;
1309                         case 10: return 29;
1310                         case 12:
1311                                 if (!is_leap_year(year))
1312                                         return 29;
1313                                 break;
1314                         case 13: return 29;
1315                 }
1316                 return 30;
1317         }
1318         
1319         /// <summary>
1320         /// The functions checks whether the month Heshvan is a long one
1321         /// in the given Hebrew year.
1322         /// </summary>
1323         /// <param name="year">An integer that gives the Hebrew year.
1324         /// </param>
1325         /// <returns>A boolean value: true if there is a long Heshvan
1326         /// in the given Hebrew year; false otherwise.
1327         /// </returns>
1328         public static bool long_heshvan(int year) {
1329                 return CCMath.mod(days_in_year(year), 10) == 5;
1330         }
1331
1332         /// <summary>
1333         /// The functions checks whether the month Kislev is a short one
1334         /// in the given Hebrew year.
1335         /// </summary>
1336         /// <param name="year">An integer that gives the Hebrew year.
1337         /// </param>
1338         /// <returns>A boolean value: true if there is a short Kislev
1339         /// in the given Hebrew year; false otherwise.
1340         /// </returns>
1341         public static bool short_kislev(int year) {
1342                 return CCMath.mod(days_in_year(year), 10) == 3;
1343         }
1344
1345         /// <summary>
1346         /// The functions gives the number of days in the specified Hebrew
1347         /// year.
1348         /// </summary>
1349         /// <param name="year">An integer that gives the Hebrew year.
1350         /// </param>
1351         /// <returns>The days of the Hebrew year as integer.
1352         /// </returns>
1353         public static int days_in_year(int year) {
1354                 return  fixed_from_dmy(1, 7, year+1) -
1355                         fixed_from_dmy(1, 7, year);
1356         }
1357
1358         /// <summary>
1359         /// The method returns the fixed day number of the given Hebrew
1360         /// date.
1361         /// </summary>
1362         /// <param name="day">An integer representing the day of the month,
1363         /// counting from 1.
1364         /// </param>
1365         /// <param name="month">An integer representing the month in the
1366         /// Hebrew year.
1367         /// </param>
1368         /// <param name="year">An integer representing the Hebrew year.
1369         /// Non-positive values are allowed also.
1370         /// </param>
1371         /// <returns>An integer value representing the fixed day number.
1372         /// </returns>
1373         public static int fixed_from_dmy(int day, int month, int year) {
1374                 int m;
1375                 int k = epoch-1;
1376                 k += elapsed_days(year);
1377                 k += new_year_delay(year);
1378
1379                 if (month < 7) {
1380                         int l = last_month_of_year(year);
1381                         for (m = 7; m <= l; m++) {
1382                                 k += last_day_of_month(m, year);
1383                         }
1384                         for (m = 1; m < month; m++) {
1385                                 k += last_day_of_month(m, year);
1386                         }
1387                 }
1388                 else {
1389                         for (m = 7; m < month; m++) {
1390                                 k += last_day_of_month(m, year);
1391                         }
1392                 }
1393                 
1394                 k += day;
1395
1396                 return k;
1397         }
1398
1399         /// <summary>
1400         /// The method computes the Hebrew year from a fixed day number.
1401         /// </summary>
1402         /// <param name="date">The fixed day number.
1403         /// </param>
1404         /// <returns>An integer value giving the Hebrew year of the date.
1405         /// </returns>
1406         public static int year_from_fixed(int date) {
1407                 int approx = (int)System.Math.Floor(
1408                         ((double)(date - epoch))/(35975351.0/98496.0));
1409                 int y;
1410                 for (y = approx; date >= fixed_from_dmy(1, 7, y); y++) {} 
1411                 return y-1;
1412         }
1413
1414         /// <summary>
1415         /// The method computes the Hebrew year and month from a fixed day
1416         /// number.
1417         /// </summary>
1418         /// <param name="month">The output value giving the Hebrew month.
1419         /// </param>
1420         /// <param name="year">The output value giving the Hebrew year.
1421         /// </param>
1422         /// <param name="date">An integer value specifying the fixed day
1423         /// number.</param>
1424         public static void my_from_fixed(out int month, out int year,
1425                 int date)
1426         {
1427                 year = year_from_fixed(date);
1428
1429                 int start = date < fixed_from_dmy(1, 1, year) ? 7 : 1;
1430
1431                 for (month = start;
1432                      date > fixed_from_dmy(last_day_of_month(month, year),
1433                                                 month, year);
1434                      month++)
1435                 {}
1436         }
1437
1438         /// <summary>
1439         /// The method computes the Hebrew year, month, and day from a
1440         /// fixed day number.
1441         /// </summary>
1442         /// <param name="day">The output value returning the day of the
1443         /// month.
1444         /// </param>
1445         /// <param name="month">The output value giving the Hebrew month.
1446         /// </param>
1447         /// <param name="year">The output value giving the Hebrew year.
1448         /// </param>
1449         /// <param name="date">An integer value specifying the fixed day
1450         /// number.</param>
1451         public static void dmy_from_fixed(out int day, out int month,
1452                 out int year, int date)
1453         {
1454                 my_from_fixed(out month, out year, date);
1455                 day = date - fixed_from_dmy(1, month, year) + 1;
1456         }
1457
1458         /// <summary>A method computing the Hebrew month from a fixed
1459         /// day number.
1460         /// </summary>
1461         /// <param name="date">An integer specifying the fixed day number.
1462         /// </param>
1463         /// <returns>An integer value representing the Hebrew month.
1464         /// </returns>
1465         public static int month_from_fixed(int date) {
1466                 int month, year;
1467
1468                 my_from_fixed(out month, out year, date);
1469                 return month;
1470         }
1471
1472         /// <summary>
1473         /// A method computing the day of the month from a fixed day number.
1474         /// </summary>
1475         /// <param name="date">An integer specifying the fixed day number.
1476         /// </param>
1477         /// <returns>An integer value representing the day of the month.
1478         /// </returns>
1479         public static int day_from_fixed(int date) {
1480                 int day, month, year;
1481                 
1482                 dmy_from_fixed(out day, out month, out year, date);
1483                 return day;
1484         }
1485
1486         /// <summary>
1487         /// The method computes the difference between two Hebrew dates.
1488         /// </summary>
1489         /// <param name="dayA">The integer parameter gives the day of month
1490         /// of the first date.
1491         /// </param>
1492         /// <param name="monthA">The integer parameter gives the Hebrew
1493         /// month of the first date.
1494         /// </param>
1495         /// <param name="yearA">The integer parameter gives the Hebrew
1496         /// year of the first date.
1497         /// </param>
1498         /// <param name="dayB">The integer parameter gives the day of month
1499         /// of the second date.
1500         /// </param>
1501         /// <param name="monthB">The integer parameter gives the Hebrew
1502         /// month of the second date.
1503         /// </param>
1504         /// <param name="yearB">The integer parameter gives the Hebrew
1505         /// year of the second date.
1506         /// </param>
1507         /// <returns>An integer giving the difference of days from the first
1508         /// the second date.
1509         /// </returns>
1510         public static int date_difference(int dayA, int monthA, int yearA,
1511                 int dayB, int monthB, int yearB)
1512         {
1513                 return  fixed_from_dmy(dayB, monthB, yearB) -
1514                         fixed_from_dmy(dayA, monthA, yearA);
1515         }
1516
1517         /// <summary>
1518         /// The method computes the number of the day in the year from
1519         /// a Hebrew date.
1520         /// </summary>
1521         /// <param name="day">An integer representing the day of the month,
1522         /// counting from 1.
1523         /// </param>
1524         /// <param name="month">An integer representing the month in the
1525         /// Hebrew year.
1526         /// </param>
1527         /// <param name="year">An integer representing the Hebrew year.
1528         /// </param>
1529         /// <returns>An integer value giving the number of the day in the
1530         /// Hebrew year, counting from 1.
1531         /// </returns>
1532         public static int day_number(int day, int month, int year) {
1533                 return date_difference(1, 7, year,
1534                         day, month, year) + 1;
1535         }
1536
1537         /// <summary>
1538         /// The method computes the days remaining in the given Hebrew
1539         /// year from a Hebrew date.
1540         /// </summary>
1541         /// <param name="day">An integer representing the day of the month,
1542         /// counting from 1.
1543         /// </param>
1544         /// <param name="month">An integer representing the month in the
1545         /// Hebrew year.
1546         /// </param>
1547         /// <param name="year">An integer representing the Hebrew year.
1548         /// </param>
1549         /// <returns>An integer value giving the number of days remaining in
1550         /// the Hebrew year.
1551         /// </returns>
1552         public static int days_remaining(int day, int month, int year) {
1553                 return date_difference(day, month, year,
1554                         1, 7, year+1)-1;
1555         }
1556 } // class HebrewCalendar
1557
1558
1559 /// <summary>
1560 /// A class encapsulating the functions of the Islamic calendar as static
1561 /// methods.
1562 /// </summary>
1563 /// <remarks>
1564 /// <para>There is no difference here in using Hijri or Islamic calendar.
1565 /// </para>
1566 /// <para>The epoch of the Islamic calendar isn't fixed, because we cannot
1567 /// surely say today, when the crescent of the new moon has been observed 
1568 /// around the July 16, 622 C.E. Julian. Even today the start and end of 
1569 /// the month Ramadan is defined by religous authorities. So the calendar
1570 /// can be offset by two days.
1571 /// </para> 
1572 /// <para>
1573 /// We don't support the offset here, however we changed the epoch from
1574 /// "Calendrical Calculations" to value, that .Net seems to be using.
1575 /// </para>
1576 /// <para>
1577 /// This class is not compatible to
1578 /// <see cref="T:System.Globalization.HijriCalendar"/>.
1579 /// </para>
1580 /// <seealso cref="T:CCFixed"/>
1581 /// </remarks>
1582 internal class CCHijriCalendar {
1583         /// <summary>An integer defining the epoch of the Gregorian calendar
1584         /// as fixed day number.</summary>
1585         /// <remarks>
1586         /// <para>
1587         /// The epoch is given as 16 July 622 C.E. Julian (R.D. 227015)
1588         /// in Calendrical Calculations, the approximate date of
1589         /// the emigration of
1590         /// Muhammed to Medina. However there is no way to determine today
1591         /// the observation of the crescent of the new moon in July 622 C.E.
1592         /// (Julian). So there is some variability in the epoch.
1593         /// Religous authorities determine the epoch by observing the
1594         /// crescent of the new moon for the month Ramadan, so there might
1595         /// be an offsets by two days of the epoch.
1596         /// </para>
1597         /// <para>Windows
1598         /// supports an AddHijriDate parameter in the registry to adapt
1599         /// for it. It seems that the .NET implementation of
1600         /// HijriCalendar uses an epoch of 227014, so we use it here. The
1601         /// ArgumentOutOfRangeException gives July, 18 622 as epoch,
1602         /// which is 227014 supporting our theory.
1603         /// </para>
1604         /// </remarks>
1605         const int epoch = 227014;
1606
1607         /// <summary>The enumeration defines the months of the Islamic
1608         /// calendar.
1609         /// </summary>
1610         public enum Month {
1611                 /// <summary>
1612                 /// Muharram.
1613                 /// </summary>
1614                 muharram = 1,
1615                 /// <summary>
1616                 /// Safar.
1617                 /// </summary>
1618                 safar,
1619                 /// <summary>
1620                 /// Rabi I.
1621                 /// </summary>
1622                 rabi_I,
1623                 /// <summary>
1624                 /// Rabi II.
1625                 /// </summary>
1626                 rabi_II,
1627                 /// <summary>
1628                 /// Jumada I.
1629                 /// </summary>
1630                 jumada_I,
1631                 /// <summary>
1632                 /// Jumada II.
1633                 /// </summary>
1634                 jumada_II,
1635                 /// <summary>
1636                 /// Rajab.
1637                 /// </summary>
1638                 rajab,
1639                 /// <summary>
1640                 /// Shaban.
1641                 /// </summary>
1642                 shaban,
1643                 /// <summary>
1644                 /// Ramadan.
1645                 /// </summary>
1646                 ramadan,
1647                 /// <summary>
1648                 /// Shawwal.
1649                 /// </summary>
1650                 shawwal,
1651                 /// <summary>
1652                 /// Dhu Al-Quada.
1653                 /// </summary>
1654                 dhu_al_quada,
1655                 /// <summary>
1656                 /// Dhu Al-Hijja.
1657                 /// </summary>
1658                 dhu_al_hijja,
1659         };
1660
1661         /// <summary>
1662         /// The method tells whether the year is a leap year.
1663         /// </summary>
1664         /// <param name="year">An integer representing the Islamic year.
1665         /// </param>
1666         /// <returns>A boolean which is true if <paramref name="year"/> is
1667         /// a leap year.
1668         /// </returns>
1669         public static bool is_leap_year(int year) {
1670                 return CCMath.mod(14+11*year, 30) < 11;
1671         }
1672
1673         /// <summary>
1674         /// The method returns the fixed day number of the given Islamic
1675         /// date.
1676         /// </summary>
1677         /// <param name="day">An integer representing the day of the month,
1678         /// counting from 1.
1679         /// </param>
1680         /// <param name="month">An integer representing the month in the
1681         /// Islamic year.
1682         /// </param>
1683         /// <param name="year">An integer representing the Islamic year.
1684         /// Non-positive values are allowed also.
1685         /// </param>
1686         /// <returns>An integer value representing the fixed day number.
1687         /// </returns>
1688         public static int fixed_from_dmy(int day, int month, int year) {
1689                 int k = epoch - 1;
1690                 k += 354 * (year-1);
1691                 k += CCMath.div(3+11*year, 30);
1692                 k += (int)System.Math.Ceiling(29.5 * (double)(month-1));
1693                 k += day;
1694
1695                 return k;
1696         }
1697
1698         /// <summary>
1699         /// The method computes the Islamic year from a fixed day number.
1700         /// </summary>
1701         /// <param name="date">The fixed day number.
1702         /// </param>
1703         /// <returns>An integer value giving the Islamic year of the date.
1704         /// </returns>
1705         public static int year_from_fixed(int date) {
1706                 return CCMath.div(30*(date-epoch)+10646, 10631);
1707         }
1708
1709         /// <summary>
1710         /// The method computes the Islamic year and month from a fixed day
1711         /// number.
1712         /// </summary>
1713         /// <param name="month">The output value giving the Islamic month.
1714         /// </param>
1715         /// <param name="year">The output value giving the Islamic year.
1716         /// </param>
1717         /// <param name="date">An integer value specifying the fixed day
1718         /// number.</param>
1719         public static void my_from_fixed(out int month, out int year, int date)
1720         {
1721                 year = year_from_fixed(date);
1722
1723                 int m = 1+(int)System.Math.Ceiling(
1724                         ((double)(date-29-fixed_from_dmy(1,1,year)))/29.5);
1725
1726                 month = m < 12 ? m : 12;
1727         }
1728         
1729         /// <summary>
1730         /// The method computes the Islamic year, month, and day from a
1731         /// fixed day number.
1732         /// </summary>
1733         /// <param name="day">The output value returning the day of the
1734         /// month.
1735         /// </param>
1736         /// <param name="month">The output value giving the Islamic month.
1737         /// </param>
1738         /// <param name="year">The output value giving the Islamic year.
1739         /// </param>
1740         /// <param name="date">An integer value specifying the fixed day
1741         /// number.</param>
1742         public static void dmy_from_fixed(out int day, out int month,
1743                 out int year, int date)
1744         {
1745                 my_from_fixed(out month, out year, date);
1746                 day = date - fixed_from_dmy(1, month, year) + 1;
1747         }
1748
1749         /// <summary>A method computing the Islamic month from a fixed
1750         /// day number.
1751         /// </summary>
1752         /// <param name="date">An integer specifying the fixed day number.
1753         /// </param>
1754         /// <returns>An integer value representing the Islamic month.
1755         /// </returns>
1756         public static int month_from_fixed(int date) {
1757                 int month, year;
1758
1759                 my_from_fixed(out month, out year, date);
1760                 return month;
1761         }
1762
1763         /// <summary>
1764         /// A method computing the day of the month from a fixed day number.
1765         /// </summary>
1766         /// <param name="date">An integer specifying the fixed day number.
1767         /// </param>
1768         /// <returns>An integer value representing the day of the month.
1769         /// </returns>
1770         public static int day_from_fixed(int date) {
1771                 int day;
1772                 int month;
1773                 int year;
1774
1775                 dmy_from_fixed(out day, out month, out year, date);
1776                 return day;
1777         }
1778
1779         /// <summary>
1780         /// The method computes the difference between two Islamic dates.
1781         /// </summary>
1782         /// <param name="dayA">The integer parameter gives the day of month
1783         /// of the first date.
1784         /// </param>
1785         /// <param name="monthA">The integer parameter gives the Islamic
1786         /// month of the first date.
1787         /// </param>
1788         /// <param name="yearA">The integer parameter gives the Islamic
1789         /// year of the first date.
1790         /// </param>
1791         /// <param name="dayB">The integer parameter gives the day of month
1792         /// of the second date.
1793         /// </param>
1794         /// <param name="monthB">The integer parameter gives the Islamic
1795         /// month of the second date.
1796         /// </param>
1797         /// <param name="yearB">The integer parameter gives the Islamic
1798         /// year of the second date.
1799         /// </param>
1800         /// <returns>An integer giving the difference of days from the first
1801         /// the second date.
1802         /// </returns>
1803         public static int date_difference(int dayA, int monthA, int yearA,
1804                 int dayB, int monthB, int yearB)
1805         {
1806                 return  fixed_from_dmy(dayB, monthB, yearB) -
1807                         fixed_from_dmy(dayA, monthA, yearA);
1808         }
1809
1810         /// <summary>
1811         /// The method computes the number of the day in the year from
1812         /// a Islamic date.
1813         /// </summary>
1814         /// <param name="day">An integer representing the day of the month,
1815         /// counting from 1.
1816         /// </param>
1817         /// <param name="month">An integer representing the month in the
1818         /// Islamic year.
1819         /// </param>
1820         /// <param name="year">An integer representing the Islamic year.
1821         /// </param>
1822         /// <returns>An integer value giving the number of the day in the
1823         /// Islamic year, counting from 1.
1824         /// </returns>
1825         public static int day_number(int day, int month, int year) {
1826                 return date_difference(31, 12, year-1, day, month, year);
1827         }
1828
1829         /// <summary>
1830         /// The method computes the days remaining in the given Islamic
1831         /// year from a Islamic date.
1832         /// </summary>
1833         /// <param name="day">An integer representing the day of the month,
1834         /// counting from 1.
1835         /// </param>
1836         /// <param name="month">An integer representing the month in the
1837         /// Islamic year.
1838         /// </param>
1839         /// <param name="year">An integer representing the Islamic year.
1840         /// Non-positive values are allowed also.
1841         /// </param>
1842         /// <returns>An integer value giving the number of days remaining in
1843         /// the Islamic year.
1844         /// </returns>
1845         public static int days_remaining(int day, int month, int year) {
1846                 return date_difference(day, month, year,31, 12, year);
1847         }
1848 } // class CCHijriCalendar
1849
1850 internal class CCEastAsianLunisolarCalendar
1851 {
1852         const int initial_epact = 29; // at 1900
1853
1854         public static int fixed_from_dmy (int day, int month, int year)
1855         {
1856                 /*
1857                 int k = epoch - 1;
1858                 k += 354 * (year - 1);
1859                 k += CCMath.div (3+11*year, 30);
1860                 k += (int) Math.Ceiling(29.53 * (double)(month-1));
1861                 k += day;
1862
1863                 return k;
1864                 */
1865                 throw new Exception ("fixed_from_dmy");
1866         }
1867
1868         public static int year_from_fixed (int date)
1869         {
1870                 throw new Exception ("year_from_fixed");
1871         }
1872
1873         public static void my_from_fixed(out int month, out int year, int date)
1874         {
1875                 /*
1876                 year = year_from_fixed (date);
1877
1878                 int m = 1+(int)System.Math.Ceiling(
1879                         ((double)(date-29-fixed_from_dmy(1,1,year)))/29.5);
1880
1881                 month = m < 12 ? m : 12;
1882                 */
1883                 throw new Exception ("my_from_fixed");
1884         }
1885
1886         public static void dmy_from_fixed(out int day, out int month,
1887                 out int year, int date)
1888         {
1889                 /*
1890                 my_from_fixed (out month, out year, date);
1891                 day = date - fixed_from_dmy (1, month, year) + 1;
1892                 */
1893                 throw new Exception ("dmy_from_fixed");
1894         }
1895
1896         public static DateTime AddMonths (DateTime date, int months)
1897         {
1898                 
1899                 throw new Exception ("AddMonths");
1900         }
1901
1902         public static DateTime AddYears (DateTime date, int years)
1903         {
1904                 throw new Exception ("AddYears");
1905         }
1906
1907         public static int GetDayOfMonth (DateTime date)
1908         {
1909                 throw new Exception ("GetDayOfMonth");
1910         }
1911
1912         public static int GetDayOfYear (DateTime date)
1913         {
1914                 throw new Exception ("GetDayOfYear");
1915         }
1916
1917         public static int GetDaysInMonth (int gyear, int month)
1918         {
1919                 throw new Exception ("GetDaysInMonth");
1920         }
1921
1922         public static int GetDaysInYear (int year)
1923         {
1924                 throw new Exception ("GetDaysInYear");
1925         }
1926
1927         public static int GetMonth (DateTime date)
1928         {
1929                 throw new Exception ("GetMonth");
1930         }
1931
1932         static readonly int [] leap_month_calc = new int [] {
1933                 0, 2, 0, 2, 2, 4, 5, 6, 7, 8, 9, 10};
1934
1935         public static bool IsLeapMonth (int gyear, int month)
1936         {
1937                 int goldenNumber = gyear % 19;
1938
1939                 bool chu = false;
1940                 bool leap = false;
1941                 double s = 0;
1942                 for (int y = 0; y < goldenNumber; y++) {
1943                         for (int l = 0, m = 1; m <= month; m++) {
1944                                 if (leap) {
1945                                         l += 30;
1946                                         leap = false;
1947                                         if (y == goldenNumber && m == month)
1948                                                 return true;
1949                                 } else {
1950                                         l += chu ? 30 : 29;
1951                                         chu = !chu;
1952                                         s += 30.44;
1953                                         if (s - l > 29)
1954                                                 leap = true;
1955                                 }
1956                         }
1957                 }
1958                 return false;
1959         }
1960
1961         public static bool IsLeapYear (int gyear)
1962         {
1963
1964                 // FIXME: it is still wrong.
1965                 int d = gyear % 19;
1966                 switch (d) {
1967                 case 0: case 3: case 6: case 9: case 11: case 14: case 17:
1968                         return true;
1969                 default:
1970                         return false;
1971                 }
1972                 /*
1973                 int goldenNumber = (gyear - 1900) % 19;
1974                 int epact = 29;
1975                 bool leap = false;
1976                 while (goldenNumber-- >= 0) {
1977                         epact += 11;
1978                         leap = epact > 30;
1979                         if (epact > 30)
1980                                 epact -= 30;
1981                 }
1982                 return leap;
1983                 */
1984         }
1985
1986         public static DateTime ToDateTime (int year, int month, int day, int hour, int minute, int second, int millisecond)
1987         {
1988                 throw new Exception ("ToDateTime");
1989         }
1990 }
1991
1992 /// <summary>
1993 /// A class that supports the Gregorian based calendars with other eras
1994 /// (e.g. <see cref="T:System.Gloablization.JapaneseCalendar"/>).
1995 /// </summary>
1996 [System.Serializable]
1997 internal class CCGregorianEraHandler {
1998         /// <summary>
1999         /// A struct that represents a single era.
2000         /// </summary>
2001         [System.Serializable]
2002         struct Era {
2003                 /// <summary>
2004                 /// The integer number identifying the era.
2005                 /// </summary>
2006                 private int _nr;
2007
2008                 /// <value>
2009                 /// A get-only property that gives the era integer number.
2010                 /// </value>
2011                 public int Nr { get { return _nr; } }
2012
2013                 /// <summary>This integer gives the first day of the era as
2014                 /// fixed day number.
2015                 /// </summary>
2016                 private int _start; // inclusive
2017                 /// <summary>
2018                 /// This integer gives the gregorian year of the
2019                 /// <see cref="M:_start"/> value.
2020                 /// </summary>
2021                 private int _gregorianYearStart;
2022                 /// <summary>
2023                 /// This integer gives the last day of the era as fixed day
2024                 /// number.
2025                 /// </summary>
2026                 private int _end;   // inclusive        
2027                 /// <summary>
2028                 /// This integer gives the largest year number of this era.
2029                 /// </summary>
2030                 private int _maxYear;
2031
2032                 /// <summary>
2033                 /// This constructor creates the era structure.
2034                 /// </summary>
2035                 /// <param name="nr">The integer number of the era.
2036                 /// </param>
2037                 /// <param name="start">The fixed day number defining the
2038                 /// first day of the era.
2039                 /// </param>
2040                 /// <param name="end">The fixed day number that defines the
2041                 /// last day of the era.
2042                 /// </param>
2043                 public Era(int nr, int start, int end) {
2044                         if (nr == 0)
2045                                 throw new System.ArgumentException(
2046                                         "Era number shouldn't be zero.");
2047                         _nr = nr;
2048                         if (start > end) {
2049                                 throw new System.ArgumentException(
2050                                         "Era should start before end.");
2051                         }
2052                         _start = start;
2053                         _end = end;
2054
2055                         _gregorianYearStart =
2056                                 CCGregorianCalendar.year_from_fixed(_start);
2057                         int gregorianYearEnd =
2058                                 CCGregorianCalendar.year_from_fixed(_end);
2059                         _maxYear = gregorianYearEnd - _gregorianYearStart + 1;
2060                 }
2061
2062                 /// <summary>
2063                 /// This method computes the Gregorian year from the year
2064                 /// of this era.
2065                 /// </summary>
2066                 /// <param name="year">An integer giving the year in the
2067                 /// era.
2068                 /// </param>
2069                 /// <returns>
2070                 /// The Gregorian year as integer.
2071                 /// </returns>
2072                 /// <exception cref="T:System.ArgumentOutOfRangeException">
2073                 /// The exception is thrown if the year isn't valid in this
2074                 /// era.
2075                 /// </exception>
2076                 public int GregorianYear(int year) {
2077                         if (year < 1 || year > _maxYear) {
2078                                 System.IO.StringWriter sw = 
2079                                         new System.IO.StringWriter();
2080                                 sw.Write(
2081                                         "Valid Values are between " +
2082                                         "{0} and {1}, inclusive.",
2083                                         1, _maxYear);
2084                                 throw new System.ArgumentOutOfRangeException(
2085                                         "year", sw.ToString());
2086                         }
2087                         return year + _gregorianYearStart - 1;
2088                 }
2089
2090                 /// <summary>
2091                 /// This function checks wether the given fixed day number is
2092                 /// ion the time span of the era.
2093                 /// </summary>
2094                 /// <param name="date">An integer giving the fixed day
2095                 /// number.
2096                 /// </param>
2097                 /// <returns>A boolean: true if the argument is in the time
2098                 /// span of the era.
2099                 /// </returns>
2100                 public bool Covers(int date) {
2101                         return _start <= date && date <= _end;
2102                 }
2103
2104                 /// <summary>
2105                 /// This function returns the year of the era and sets
2106                 /// the era in an output parameter.
2107                 /// </summary>
2108                 /// <param name="era">An output parameter returning the
2109                 /// era number.
2110                 /// </param>
2111                 /// <param name="date">An integer giving the fixed day
2112                 /// number.
2113                 /// </param>
2114                 /// <returns>An integer giving the year of the era.
2115                 /// </returns>
2116                 /// <exception cref="T:System.ArgumentOutOfRangeException">
2117                 /// The exception is thrown if date is outside of the time
2118                 /// span of the era.
2119                 /// </exception>
2120                 public int EraYear(out int era, int date) {
2121                         if (!Covers(date))
2122                                 throw new System.ArgumentOutOfRangeException(
2123                                         "date", 
2124                                         "Time was out of Era range.");
2125                         int gregorianYear =
2126                                 CCGregorianCalendar.year_from_fixed(date);
2127                         era = _nr;
2128                         return gregorianYear - _gregorianYearStart + 1;
2129                 }
2130         } // struct Era
2131
2132         /// <summary>
2133         /// A private member storing the eras in a
2134         /// <see cref="T:System.Collections.SortedList"/>.
2135         /// </summary>
2136         private SortedList _Eras;
2137
2138         /// <value>
2139         /// The property returns the era numbers as an array of integers.
2140         /// </value>
2141         public int[] Eras {
2142                 get {
2143                         int[] a = new int[_Eras.Count];
2144
2145                         for (int i = 0; i < _Eras.Count; i++) {
2146                                 Era e = (Era)_Eras.GetByIndex(i);
2147                                 a[i] = e.Nr;
2148                         }
2149
2150                         return a;
2151                 }
2152         }
2153
2154         /// <summary>
2155         /// Constructor.
2156         /// </summary>
2157         public CCGregorianEraHandler() {
2158                 _Eras = new SortedList();
2159         }
2160
2161         /// <summary>
2162         /// Method adds an era to the GregorianEraHandler instance.
2163         /// </summary>
2164         /// <param name="nr">The integer number of the era.
2165         /// </param>
2166         /// <param name="rd_start">The fixed day number defining the
2167         /// first day of the era.
2168         /// </param>
2169         /// <param name="rd_end">The fixed day number that defines the
2170         /// last day of the era.
2171         /// </param>
2172         public void appendEra(int nr, int rd_start, int rd_end) {
2173                 Era era = new Era(nr, rd_start, rd_end);
2174                 _Eras[(System.Object)nr] = era;
2175         }
2176         /// <summary>
2177         /// Method adds a yet not-ended era to the GregorianEraHandler
2178         /// instance.
2179         /// </summary>
2180         /// <param name="nr">The integer number of the era.
2181         /// </param>
2182         /// <param name="rd_start">The fixed day number defining the
2183         /// first day of the era.
2184         /// </param>
2185         public void appendEra(int nr, int rd_start) {
2186                 appendEra(nr, rd_start,
2187                         CCFixed.FromDateTime(DateTime.MaxValue));
2188         }
2189
2190         /// <summary>
2191         /// This method computes the Gregorian year from the year
2192         /// of the given era.
2193         /// </summary>
2194         /// <param name="year">An integer giving the year in the
2195         /// era.
2196         /// </param>
2197         /// <param name="era">An integer giving the era number.
2198         /// </param>
2199         /// <returns>
2200         /// The Gregorian year as integer.
2201         /// </returns>
2202         /// <exception cref="T:System.ArgumentOutOfRangeException">
2203         /// The exception is thrown if the year isn't valid in this
2204         /// era.
2205         /// </exception>
2206         public int GregorianYear(int year, int era) {
2207                 Era e = (Era)_Eras[(System.Object)era];
2208                 return e.GregorianYear(year);
2209         }
2210
2211         /// <summary>
2212         /// This function returns the year of the era and sets
2213         /// the era in an output parameter.
2214         /// </summary>
2215         /// <param name="era">An output parameter returning the
2216         /// era number.
2217         /// </param>
2218         /// <param name="date">An integer giving the fixed day
2219         /// number.
2220         /// </param>
2221         /// <returns>An integer giving the year of the era.
2222         /// </returns>
2223         /// <exception cref="T:System.ArgumentOutOfRangeException">
2224         /// The exception is thrown if the fixed day number is outside of the
2225         /// time spans of all eras.
2226         /// </exception>
2227         public int EraYear(out int era, int date)
2228         {
2229                 IList list = _Eras.GetValueList();
2230
2231                 foreach (Era e in list) {
2232                         if (e.Covers(date))
2233                                 return e.EraYear(out era, date);
2234                 }
2235
2236                 throw new System.ArgumentOutOfRangeException("date",
2237                         "Time value was out of era range.");
2238         }
2239
2240         /// <summary>
2241         /// The method checks whether a given
2242         /// <see cref="T:System.DateTime"/> is covered by any era.
2243         /// </summary>
2244         /// <param name="time">A 
2245         /// <see cref="T:System.DateTime"/> giving the date and time.
2246         /// </param>
2247         /// <exception cref="T:System.ArgumentOutOfRangeException">
2248         /// The exception is thrown if the argument isn't inside the time
2249         /// span of any era.
2250         /// </exception>
2251         public void CheckDateTime(System.DateTime time) {
2252                 int date = CCFixed.FromDateTime(time);
2253
2254                 if (!ValidDate(date))
2255                         throw new System.ArgumentOutOfRangeException("time",
2256                                 "Time value was out of era range.");
2257         }
2258                 
2259         /// <summary>
2260         /// The method tests whether a given
2261         /// fixed day number is covered by any era.
2262         /// </summary>
2263         /// <param name="date">An integer representing the fixed day number.
2264         /// </param>
2265         /// <returns> A boolean is returned: true if the argument is inside
2266         /// the time span of one era; false otherwise.
2267         /// </returns>
2268         public bool ValidDate(int date) {
2269                 IList list = _Eras.GetValueList();
2270
2271                 foreach (Era e in list) {
2272                         if (e.Covers(date))
2273                                 return true;
2274                 }
2275
2276                 return false;
2277         }
2278
2279         /// <summary>
2280         /// The method tests, whether the era number does exist.
2281         /// </summary>
2282         /// <param name="era">An integer giving the era number.
2283         /// </param>
2284         /// <returns>A boole value: True if the era number does exist;
2285         /// false otherwise.
2286         /// </returns>
2287         public bool ValidEra(int era) {
2288                 return _Eras.Contains((System.Object)era);
2289         }
2290 } // class CCGregorianEraHandler
2291
2292
2293 // FIXME: remove this class. It should be identical to CCGregorianEraHandler
2294 [System.Serializable]
2295 internal class CCEastAsianLunisolarEraHandler
2296 {
2297         [Serializable]
2298         struct Era 
2299         {
2300                 private int _nr; // era index
2301
2302                 public int Nr {
2303                         get { return _nr; }
2304                 }
2305
2306                 private int _start; // inclusive
2307                 private int _gregorianYearStart;
2308                 private int _end;   // inclusive
2309                 private int _maxYear;
2310
2311                 public Era (int nr, int start, int end)
2312                 {
2313                         if (nr == 0)
2314                                 throw new ArgumentException ("Era number shouldn't be zero.");
2315                         _nr = nr;
2316                         if (start > end)
2317                                 throw new ArgumentException ("Era should start before end.");
2318                         _start = start;
2319                         _end = end;
2320
2321                         _gregorianYearStart = CCGregorianCalendar.year_from_fixed (_start);
2322                         int gregorianYearEnd = CCGregorianCalendar.year_from_fixed (_end);
2323                         _maxYear = gregorianYearEnd - _gregorianYearStart + 1;
2324                 }
2325
2326                 public int GregorianYear (int year) 
2327                 {
2328                         if (year < 1 || year > _maxYear)
2329                                 throw new ArgumentOutOfRangeException ("year", String.Format ("Valid Values are between {0} and {1}, inclusive.", 1, _maxYear));
2330                         return year + _gregorianYearStart - 1;
2331                 }
2332
2333                 public bool Covers (int date) {
2334                         return _start <= date && date <= _end;
2335                 }
2336
2337                 public int EraYear (out int era, int date) {
2338                         if (!Covers (date))
2339                                 throw new ArgumentOutOfRangeException ("date", "Time was out of Era range.");
2340                         int gregorianYear = CCGregorianCalendar.year_from_fixed (date);
2341                         era = _nr;
2342                         return gregorianYear - _gregorianYearStart + 1;
2343                 }
2344         }
2345
2346         private SortedList _Eras;
2347
2348         public int [] Eras 
2349         {
2350                 get {
2351                         int[] a = new int [_Eras.Count];
2352                         for (int i = 0; i < _Eras.Count; i++) {
2353                                 Era e = (Era) _Eras.GetByIndex (i);
2354                                 a[i] = e.Nr;
2355                         }
2356                         return a;
2357                 }
2358         }
2359
2360         public CCEastAsianLunisolarEraHandler ()
2361         {
2362                 _Eras = new SortedList ();
2363         }
2364
2365         public void appendEra (int nr, int rd_start, int rd_end)
2366         {
2367                 Era era = new Era (nr, rd_start, rd_end);
2368                 _Eras [nr] = era;
2369         }
2370
2371         public void appendEra (int nr, int rd_start)
2372         {
2373                 appendEra (nr, rd_start, CCFixed.FromDateTime (DateTime.MaxValue));
2374         }
2375
2376         public int GregorianYear (int year, int era)
2377         {
2378                 Era e = (Era) _Eras [era];
2379                 return e.GregorianYear (year);
2380         }
2381
2382         public int EraYear (out int era, int date)
2383         {
2384                 foreach (Era e in _Eras.Values)
2385                         if (e.Covers (date))
2386                                 return e.EraYear (out era, date);
2387
2388                 throw new ArgumentOutOfRangeException ("date", "Time value was out of era range.");
2389         }
2390
2391         public void CheckDateTime (DateTime time)
2392         {
2393                 int date = CCFixed.FromDateTime (time);
2394
2395                 if (!ValidDate (date))
2396                         throw new ArgumentOutOfRangeException ("time", "Time value was out of era range.");
2397         }
2398                 
2399         public bool ValidDate (int date)
2400         {
2401                 foreach (Era e in _Eras.Values) {
2402                         if (e.Covers (date))
2403                                 return true;
2404                 }
2405                 return false;
2406         }
2407
2408         public bool ValidEra (int era)
2409         {
2410                 return _Eras.Contains (era);
2411         }
2412 }
2413
2414 } // namespace System.Globalization