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