1 // CalendricalCalculations.cs
3 // (C) Ulrich Kunitz 2002
6 namespace System.Globalization {
8 using System.Collections;
10 /// <summary>A class that provides mathematical functions.</summary>
13 /// We are breaking the .Net
14 /// naming conventions to be compatible to the "Calendrical Calculations"
18 internal class CCMath {
20 /// A static method which rounds a double value.
22 /// <param name="x">The double value to round.</param>
23 /// <returns>The rounded double.</returns>
24 public static double round(double x) {
25 return System.Math.Floor(x+0.5);
29 /// A static method that computes the remainder of the division
32 /// <param name="x">The double value which is divided.</param>
33 /// <param name="y">The divisor.</param>
34 /// <returns>The remainder as double value.</returns>
35 public static double mod(double x, double y) {
36 return x - y * System.Math.Floor(x/y);
40 /// The static method divides two integers.
42 /// <param name="x">The integer x value.</param>
43 /// <param name="y">The integer y value.</param>
44 /// <returns>The qotient of x and y defined by floor(x/y).
47 /// Please notify that the function is not compatible to the standard
48 /// integer divide operation /.
50 public static int div(int x, int y) {
51 return (int)System.Math.Floor((double)x/(double)y);
55 /// The static method computes the remainder of two integers.
57 /// <param name="x">The integer value which will be divided.</param>
58 /// <param name="y">The divisor integer value.</param>
59 /// <returns> The remainder as integer value.</returns>
61 /// Please notify that the method is not compatible to the C#
62 /// remainder operation %.
64 public static int mod(int x, int y) {
65 return x - y * div(x, y);
69 /// A static method that combines integer division and remainder
72 /// <param name="remainder">Remainder integer output value.
74 /// <param name="x">Integer to be divided.</param>
75 /// <param name="y">Divisor integer value.</param>
76 /// <returns>The quotient as integer.</returns>
77 /// <seealso cref="M:div"/>
78 /// <seealso cref="M:mod"/>
79 public static int div_mod(out int remainder, int x, int y) {
81 remainder = x - y * d;
86 /// A static method returning the sign of the argument.
88 /// <param name="x">The double argument.</param>
89 /// <returns>An integer value: -1 for a negative argument;
90 /// 0 for a zero argument, and 1 for a positive argument.
92 public static int signum(double x) {
101 /// A static method returning the sign of the integer
104 /// <param name="x">The integer argument.</param>
105 /// <returns>An integer value: -1 for a negative argument;
106 /// 0 for a zero argument, and 1 for a positive argument.
108 public static int signum(int x) {
117 /// An adjusted remainder function as defined in "Calendrical
120 /// <param name="x">The double x argument.</param>
121 /// <param name="y">The double y argument, the divisor.</param>
122 /// <returns>A double value representing remainder; but instead 0.0
123 /// the divisor y is returned.
125 public static double amod(double x, double y) {
126 double d = mod(x, y);
127 return (d == 0.0) ? y : d;
131 /// The adjusted remainder functions for integers as defined in
132 /// "Calendrical Calculations".
134 /// <param name="x">The integer argument to be divided.</param>
135 /// <param name="y">The integer divisor argument.</param>
136 /// <returns>The remainder as an integer; however instead 0
137 /// is the divisor y returned.
139 public static int amod(int x, int y) {
141 return (i == 0) ? y : i;
145 /// <summary>The class implements methods to handle the fixed date value from
146 /// the "Calendrical Calculations" books.
150 /// For implementing the Calendar classes I used the algorithms from the
151 /// book "Calendrical Calculations" by Nachum Dershowitz and Edward M.
152 /// Rheingold, second reprint 1998. Trying to prevent the introduction of new
153 /// bugs, I implemented their algorithms in the
154 /// <see cref="N:CalendricalCalculations"/>
155 /// namespace and wrapped it in the calendar classes.
158 /// The fixed day number is also known as R.D. - rata die.
159 /// Midnight at the onset of Monday,
160 /// January 1, year 1 (Gregorian) is R.D. 1.
162 /// <para>Here are all my references:</para>
163 /// <list type="table">
164 /// <item><description>
165 /// [1] Nachum Dershowitz and Edward M. Rheingold: "Calendrical Calculations";
166 /// Cambridge University Press; second reprint 1998.
167 /// </description></item>
168 /// <item><description>
169 /// [2] P. Kenneth Seidelmann (ed.): "Explanatory Supplement to the Astronomical
170 /// Almanac"; University Science Books, Sausalito; 1992
171 /// </description></item>
172 /// <item><description>
173 /// [3] F. Richard Stephenson: "Historical Eclipses and Earth Rotation";
174 /// Cambridge University Press; 1997
175 /// </description></item>
178 internal class CCFixed {
179 /// <summary>The method computes the
180 /// <see cref="T:System.DateTime"/>
181 /// from a fixed day number.
183 /// <param name="date">A integer representing the fixed day number.
185 /// <returns>The <see cref="T:System.DateTime"/> representing
188 public static System.DateTime ToDateTime(int date) {
189 long ticks = (date - 1) * System.TimeSpan.TicksPerDay;
190 return new System.DateTime(ticks);
193 /// <summary>The method computes the
194 /// <see cref="T:System.DateTime"/>
195 /// from a fixed day number and time arguments.
197 /// <param name="date">An integer representing the fixed day number.
199 /// <param name="hour">An integer argument specifying the hour.
201 /// <param name="minute">An integer argument specifying the minute.
203 /// <param name="second">An integer argument giving the second.
205 /// <param name="milliseconds">An double argument specifying
206 /// the milliseconds. Notice that
207 /// <see cref="T:System.DateTime"/> has 100 nanosecond resolution.
209 /// <returns>The <see cref="T:System.DateTime"/> representing
212 public static System.DateTime ToDateTime(int date,
213 int hour, int minute, int second, double milliseconds)
215 System.DateTime time = ToDateTime(date);
216 time = time.AddHours(hour);
217 time = time.AddMinutes(minute);
218 time = time.AddSeconds(second);
219 return time.AddMilliseconds(milliseconds);
223 /// A static method computing the fixed day number from a
224 /// <see cref="T:System.DateTime"/> value.
226 /// <param name="time">A
227 /// <see cref="T:System.DateTime"/> value representing the date.
229 /// <returns>The fixed day number as integer representing the date.
231 public static int FromDateTime(System.DateTime time) {
232 return 1 + (int)(time.Ticks / System.TimeSpan.TicksPerDay);
236 /// The static method computes the <see cref="T:DayOfWeek"/>.
238 /// <param name="date">An integer representing the fixed day number.
240 /// <returns>The day of week.</returns>
241 public static DayOfWeek day_of_week(int date) {
242 return (DayOfWeek)CCMath.mod(date, 7);
246 /// The static method computes the date of a day of week on or before
247 /// a particular date.
249 /// <param name="date">An integer representing the date as
250 /// fixed day number.
252 /// <param name="k">An integer representing the day of the week,
253 /// starting with 0 for sunday.
255 /// <returns>The fixed day number of the day of week specified by k
256 /// on or before the given date.
258 public static int kday_on_or_before(int date, int k) {
259 return date - (int)day_of_week(date-k);
263 /// The static method computes the date of a day of week on or after
264 /// a particular date.
266 /// <param name="date">An integer representing the date as
267 /// fixed day number.
269 /// <param name="k">An integer representing the day of the week,
270 /// starting with 0 for sunday.
272 /// <returns>The fixed day number of the day of week specified by k
273 /// on or after the given date.
275 public static int kday_on_or_after(int date, int k) {
276 return kday_on_or_before(date+6, k);
280 /// The static method computes the date of a day of week that is
281 /// nearest to a particular date.
283 /// <param name="date">An integer representing the date as
284 /// fixed day number.
286 /// <param name="k">An integer representing the day of the week,
287 /// starting with 0 for sunday.
289 /// <returns>The fixed day number of the day of week neares to the
292 public static int kd_nearest(int date, int k) {
293 return kday_on_or_before(date+3, k);
297 /// The static method computes the date of a day of week after
298 /// a particular date.
300 /// <param name="date">An integer representing the date as
301 /// fixed day number.
303 /// <param name="k">An integer representing the day of the week,
304 /// starting with 0 for sunday.
306 /// <returns>The fixed day number of the day of week specified by k
307 /// after the given date.
309 public static int kday_after(int date, int k) {
310 return kday_on_or_before(date+7, k);
314 /// The static method computes the date of a day of week before
315 /// a particular date.
317 /// <param name="date">An integer representing the date as
318 /// fixed day number.
320 /// <param name="k">An integer representing the day of the week,
321 /// starting with 0 for sunday.
323 /// <returns>The fixed day number of the day of week specified by k
324 /// before the given date.
326 public static int kday_before(int date, int k) {
327 return kday_on_or_before(date-1, k);
332 /// A class encapsulating the functions of the Gregorian calendar as static
337 /// This class is not compatible to
338 /// <see cref="T:System.Globalization.GregorianCalendar"/>.
341 /// The fixed day number is also known as R.D. - rata die.
342 /// Midnight at the onset of Monday,
343 /// January 1, year 1 (Gregorian) is R.D. 1.
345 /// <seealso cref="T:CCFixed"/>
347 internal class CCGregorianCalendar {
348 /// <summary>An integer defining the epoch of the Gregorian calendar
349 /// as fixed day number.</summary>
350 /// <remarks>The epoch is January 3, 1 C.E. (Julian).</remarks>
353 /// <summary>The enumeration defines the months of the Gregorian
409 /// The method tells whether the year is a leap year.
411 /// <param name="year">An integer representing the Gregorian year.
413 /// <returns>A boolean which is true if <paramref name="year"/> is
416 public static bool is_leap_year(int year) {
417 if (CCMath.mod(year, 4) != 0)
419 switch (CCMath.mod(year, 400)) {
431 /// The method returns the fixed day number of the given Gregorian
434 /// <param name="day">An integer representing the day of the month,
437 /// <param name="month">An integer representing the month in the
440 /// <param name="year">An integer representing the Gregorian year.
441 /// Non-positive values are allowed also.
443 /// <returns>An integer value representing the fixed day number.
445 public static int fixed_from_dmy(int day, int month, int year) {
448 k += CCMath.div(year-1, 4);
449 k -= CCMath.div(year-1, 100);
450 k += CCMath.div(year-1, 400);
451 k += CCMath.div(367*month-362, 12);
453 k += is_leap_year(year) ? -1 : -2;
462 /// The method computes the Gregorian year from a fixed day number.
464 /// <param name="date">The fixed day number.
466 /// <returns>An integer value giving the Gregorian year of the date.
468 public static int year_from_fixed(int date) {
469 int d = date - epoch;
470 int n_400 = CCMath.div_mod(out d, d, 146097);
471 int n_100 = CCMath.div_mod(out d, d, 36524);
472 int n_4 = CCMath.div_mod(out d, d, 1461);
473 int n_1 = CCMath.div(d, 365);
475 int year = 400*n_400 + 100*n_100 + 4*n_4 + n_1;
476 return (n_100 == 4 || n_1 == 4) ? year : year + 1;
480 /// The method computes the Gregorian year and month from a fixed day
483 /// <param name="month">The output value giving the Gregorian month.
485 /// <param name="year">The output value giving the Gregorian year.
487 /// <param name="date">An integer value specifying the fixed day
489 public static void my_from_fixed(out int month, out int year,
492 year = year_from_fixed(date);
494 int prior_days = date - fixed_from_dmy(1, (int)Month.january,
498 if (date < fixed_from_dmy(1, (int)Month.march, year)) {
500 } else if (is_leap_year(year)) {
506 month = CCMath.div(12 * (prior_days + correction) + 373, 367);
511 /// The method computes the Gregorian year, month, and day from a
512 /// fixed day number.
514 /// <param name="day">The output value returning the day of the
517 /// <param name="month">The output value giving the Gregorian month.
519 /// <param name="year">The output value giving the Gregorian year.
521 /// <param name="date">An integer value specifying the fixed day
523 public static void dmy_from_fixed(out int day, out int month,
527 my_from_fixed(out month, out year, date);
528 day = date - fixed_from_dmy(1, month, year) + 1;
531 /// <summary>A method computing the Gregorian month from a fixed
534 /// <param name="date">An integer specifying the fixed day number.
536 /// <returns>An integer value representing the Gregorian month.
538 public static int month_from_fixed(int date) {
541 my_from_fixed(out month, out year, date);
546 /// A method computing the day of the month from a fixed day number.
548 /// <param name="date">An integer specifying the fixed day number.
550 /// <returns>An integer value representing the day of the month.
552 public static int day_from_fixed(int date) {
553 int day, month, year;
555 dmy_from_fixed(out day, out month, out year, date);
560 /// The method computes the difference between two Gregorian dates.
562 /// <param name="dayA">The integer parameter gives the day of month
563 /// of the first date.
565 /// <param name="monthA">The integer parameter gives the Gregorian
566 /// month of the first date.
568 /// <param name="yearA">The integer parameter gives the Gregorian
569 /// year of the first date.
571 /// <param name="dayB">The integer parameter gives the day of month
572 /// of the second date.
574 /// <param name="monthB">The integer parameter gives the Gregorian
575 /// month of the second date.
577 /// <param name="yearB">The integer parameter gives the Gregorian
578 /// year of the second date.
580 /// <returns>An integer giving the difference of days from the first
583 public static int date_difference(int dayA, int monthA, int yearA,
584 int dayB, int monthB, int yearB)
586 return fixed_from_dmy(dayB, monthB, yearB) -
587 fixed_from_dmy(dayA, monthA, yearA);
591 /// The method computes the number of the day in the year from
592 /// a Gregorian date.
594 /// <param name="day">An integer representing the day of the month,
597 /// <param name="month">An integer representing the month in the
600 /// <param name="year">An integer representing the Gregorian year.
601 /// Non-positive values are allowed also.
603 /// <returns>An integer value giving the number of the day in the
604 /// Gregorian year, counting from 1.
606 public static int day_number(int day, int month, int year) {
607 return date_difference(31, (int)Month.december, year-1,
612 /// The method computes the days remaining in the given Gregorian
613 /// year from a Gregorian date.
615 /// <param name="day">An integer representing the day of the month,
618 /// <param name="month">An integer representing the month in the
621 /// <param name="year">An integer representing the Gregorian year.
622 /// Non-positive values are allowed also.
624 /// <returns>An integer value giving the number of days remaining in
625 /// the Gregorian year.
627 public static int days_remaining(int day, int month, int year) {
628 return date_difference(day, month, year,
629 31, (int)Month.december, year);
632 // Helper functions for the Gregorian calendars.
635 /// Adds months to the given date.
637 /// <param name="time">The
638 /// <see cref="T:System.DateTime"/> to which to add
641 /// <param name="months">The number of months to add.</param>
642 /// <returns>A new <see cref="T:System.DateTime"/> value, that
643 /// results from adding <paramref name="months"/> to the specified
644 /// DateTime.</returns>
645 public static System.DateTime AddMonths(System.DateTime time,
648 int rd = CCFixed.FromDateTime(time);
649 int day, month, year;
650 dmy_from_fixed(out day, out month, out year, rd);
652 rd = fixed_from_dmy(day, month, year);
653 System.DateTime t = CCFixed.ToDateTime(rd);
654 return t.Add(time.TimeOfDay);
658 /// Adds years to the given date.
660 /// <param name="time">The
661 /// <see cref="T:System.DateTime"/> to which to add
664 /// <param name="years">The number of years to add.</param>
665 /// <returns>A new <see cref="T:System.DateTime"/> value, that
666 /// results from adding <paramref name="years"/> to the specified
667 /// DateTime.</returns>
668 public static System.DateTime AddYears(System.DateTime time,
671 int rd = CCFixed.FromDateTime(time);
672 int day, month, year;
673 dmy_from_fixed(out day, out month, out year, rd);
675 rd = fixed_from_dmy(day, month, year);
676 System.DateTime t = CCFixed.ToDateTime(rd);
677 return t.Add(time.TimeOfDay);
681 /// Gets the of the month from <paramref name="time"/>.
683 /// <param name="time">The
684 /// <see cref="T:System.DateTime"/> that specifies a
687 /// <returns>An integer giving the day of months, starting with 1.
689 public static int GetDayOfMonth(System.DateTime time) {
690 return day_from_fixed(CCFixed.FromDateTime(time));
694 /// The method gives the number of the day in the year.
696 /// <param name="time">The
697 /// <see cref="T:System.DateTime"/> that specifies a
700 /// <returns>An integer representing the day of the year,
701 /// starting with 1.</returns>
702 public static int GetDayOfYear(System.DateTime time) {
703 int rd = CCFixed.FromDateTime(time);
704 int year = year_from_fixed(rd);
705 int rd1_1 = fixed_from_dmy(1, 1, year);
706 return rd - rd1_1 + 1;
710 /// A method that gives the number of days of the specified
711 /// month of the <paramref name="year"/>.
713 /// <param name="year">An integer that gives the year in the current
715 /// <param name="month">An integer that gives the month, starting
717 /// <returns>An integer that gives the number of days of the
718 /// specified month.</returns>
719 public static int GetDaysInMonth(int year, int month) {
720 int rd1 = fixed_from_dmy(1, month, year);
721 int rd2 = fixed_from_dmy(1, month+1, year);
726 /// The method gives the number of days in the specified year.
728 /// <param name="year">An integer that gives the year.
730 /// <returns>An integer that gives the number of days of the
731 /// specified year.</returns>
732 public static int GetDaysInYear(int year) {
733 int rd1 = fixed_from_dmy(1, 1, year);
734 int rd2 = fixed_from_dmy(1, 1, year+1);
739 /// The method gives the number of the month of the specified
742 /// <param name="time">The
743 /// <see cref="T:System.DateTime"/> that specifies a
746 /// <returns>An integer representing the month,
747 /// starting with 1.</returns>
748 public static int GetMonth(System.DateTime time) {
749 return month_from_fixed(CCFixed.FromDateTime(time));
753 /// The method gives the number of the year of the specified
756 /// <param name="time">The
757 /// <see cref="T:System.DateTime"/> that specifies a
760 /// <returns>An integer representing the year.
762 public static int GetYear(System.DateTime time) {
763 return year_from_fixed(CCFixed.FromDateTime(time));
767 /// A virtual method that tells whether the given day
770 /// <param name="year">An integer that specifies the year.
772 /// <param name="month">An integer that specifies the month.
774 /// <param name="day">An integer that specifies the day.
776 /// <returns>A boolean that tells whether the given day is a leap
779 public static bool IsLeapDay(int year, int month, int day) {
780 return is_leap_year(year) && month == 2 && day == 29;
784 /// A method that creates the
785 /// <see cref="T:System.DateTime"/> from the parameters.
787 /// <param name="year">An integer that gives the year
789 /// <param name="month">An integer that specifies the month.
791 /// <param name="day">An integer that specifies the day.
793 /// <param name="hour">An integer that specifies the hour.
795 /// <param name="minute">An integer that specifies the minute.
797 /// <param name="second">An integer that gives the second.
799 /// <param name="milliseconds">An integer that gives the
803 /// <see cref="T:system.DateTime"/> representig the date and time.
805 public static System.DateTime ToDateTime(int year, int month, int day,
806 int hour, int minute, int second, int milliseconds)
808 return CCFixed.ToDateTime(fixed_from_dmy(day, month, year),
809 hour, minute, second, milliseconds);
811 } // class CCGregorianCalendar
814 /// A class encapsulating the functions of the Julian calendar as static
818 /// <para>The algorithms don't support a year 0. Years before Common Era
819 /// (B.C.E. or B.C.) are negative and years of Common Era (C.E. or A.D.)
823 /// This class is not compatible to
824 /// <see cref="T:System.Globalization.JulianCalendar"/>.
826 /// <seealso cref="T:CCFixed"/>
828 internal class CCJulianCalendar {
829 /// <summary>An integer defining the epoch of the Julian calendar
830 /// as fixed day number.</summary>
831 /// <remarks>The epoch is December 30, 0 (Gregorian).</remarks>
832 const int epoch = -1; // 30. 12. 0 Gregorian
834 /// <summary>The enumeration defines the months of the Julian
889 /// The method tells whether the year is a leap year.
891 /// <param name="year">An integer representing the Julian year.
893 /// <returns>A boolean which is true if <paramref name="year"/> is
896 public static bool is_leap_year(int year) {
897 return CCMath.mod(year, 4) == (year > 0 ? 0 : 3);
901 /// The method returns the fixed day number of the given Julian
904 /// <param name="day">An integer representing the day of the month,
907 /// <param name="month">An integer representing the month in the
910 /// <param name="year">An integer representing the Julian year.
911 /// Positive and Negative values are allowed.
913 /// <returns>An integer value representing the fixed day number.
915 public static int fixed_from_dmy(int day, int month, int year) {
916 int y = year < 0 ? year+1 : year;
919 k += CCMath.div(y-1, 4);
920 k += CCMath.div(367*month-362, 12);
922 k += is_leap_year(year) ? -1 : -2;
930 /// The method computes the Julian year from a fixed day number.
932 /// <param name="date">The fixed day number.
934 /// <returns>An integer value giving the Julian year of the date.
936 public static int year_from_fixed(int date) {
937 int approx = CCMath.div(4*(date-epoch)+1464, 1461);
938 return approx <= 0 ? approx - 1 : approx;
942 /// The method computes the Julian year and month from a fixed day
945 /// <param name="month">The output value giving the Julian month.
947 /// <param name="year">The output value giving the Julian year.
949 /// <param name="date">An integer value specifying the fixed day
951 public static void my_from_fixed(out int month, out int year, int date)
953 year = year_from_fixed(date);
955 int prior_days = date - fixed_from_dmy(1, (int)Month.january,
959 if (date < fixed_from_dmy(1, (int)Month.march, year)) {
961 } else if (is_leap_year(year)) {
967 month = CCMath.div(12 * (prior_days + correction) + 373, 367);
972 /// The method computes the Julian year, month, and day from a
973 /// fixed day number.
975 /// <param name="day">The output value returning the day of the
978 /// <param name="month">The output value giving the Julian month.
980 /// <param name="year">The output value giving the Julian year.
982 /// <param name="date">An integer value specifying the fixed day
984 public static void dmy_from_fixed(out int day, out int month,
985 out int year, int date)
987 my_from_fixed(out month, out year, date);
988 day = date - fixed_from_dmy(1, month, year) + 1;
991 /// <summary>A method computing the Julian month from a fixed
994 /// <param name="date">An integer specifying the fixed day number.
996 /// <returns>An integer value representing the Julian month.
998 public static int month_from_fixed(int date) {
1001 my_from_fixed(out month, out year, date);
1006 /// A method computing the day of the month from a fixed day number.
1008 /// <param name="date">An integer specifying the fixed day number.
1010 /// <returns>An integer value representing the day of the month.
1012 public static int day_from_fixed(int date) {
1017 dmy_from_fixed(out day, out month, out year, date);
1022 /// The method computes the difference between two Julian dates.
1024 /// <param name="dayA">The integer parameter gives the day of month
1025 /// of the first date.
1027 /// <param name="monthA">The integer parameter gives the Julian
1028 /// month of the first date.
1030 /// <param name="yearA">The integer parameter gives the Julian
1031 /// year of the first date.
1033 /// <param name="dayB">The integer parameter gives the day of month
1034 /// of the second date.
1036 /// <param name="monthB">The integer parameter gives the Julian
1037 /// month of the second date.
1039 /// <param name="yearB">The integer parameter gives the Julian
1040 /// year of the second date.
1042 /// <returns>An integer giving the difference of days from the first
1043 /// the second date.
1045 public static int date_difference(int dayA, int monthA, int yearA,
1046 int dayB, int monthB, int yearB)
1048 return fixed_from_dmy(dayB, monthB, yearB) -
1049 fixed_from_dmy(dayA, monthA, yearA);
1053 /// The method computes the number of the day in the year from
1056 /// <param name="day">An integer representing the day of the month,
1057 /// counting from 1.
1059 /// <param name="month">An integer representing the month in the
1062 /// <param name="year">An integer representing the Julian year.
1063 /// Negative values are allowed also.
1065 /// <returns>An integer value giving the number of the day in the
1066 /// Julian year, counting from 1.
1068 public static int day_number(int day, int month, int year) {
1069 return date_difference(31, (int)Month.december, year-1,
1074 /// The method computes the days remaining in the given Julian
1075 /// year from a Julian date.
1077 /// <param name="day">An integer representing the day of the month,
1078 /// counting from 1.
1080 /// <param name="month">An integer representing the month in the
1083 /// <param name="year">An integer representing the Julian year.
1084 /// Negative values are allowed also.
1086 /// <returns>An integer value giving the number of days remaining in
1087 /// the Julian year.
1089 public static int days_remaining(int day, int month, int year) {
1090 return date_difference(day, month, year,
1091 31, (int)Month.december, year);
1093 } // class CCJulianCalendar
1096 /// A class encapsulating the functions of the Hebrew calendar as static
1101 /// This class is not compatible to
1102 /// <see cref="T:System.Globalization.HebrewCalendar"/>.
1104 /// <seealso cref="T:CCFixed"/>
1106 internal class CCHebrewCalendar {
1107 /// <summary>An integer defining the epoch of the Hebrew calendar
1108 /// as fixed day number.</summary>
1109 /// <remarks>The epoch is October 10, 3761 B.C.E. (Julian).</remarks>
1110 const int epoch = -1373427;
1112 /// <summary>The enumeration defines the months of the Gregorian
1116 /// The enumaration differs from .NET which defines Tishri as month 1.
1168 /// Adar I. Only in years with Adar II.
1172 /// Adar II. Only in years wirh Adar I.
1178 /// The method tells whether the year is a leap year.
1180 /// <param name="year">An integer representing the Hebrew year.
1182 /// <returns>A boolean which is true if <paramref name="year"/> is
1185 public static bool is_leap_year(int year) {
1186 return CCMath.mod(7*year+1, 19) < 7;
1190 /// The Method gives the number of the last month in a year, which
1191 /// is equal with the number of month in a Hebrew year.
1193 /// <param name="year">An integer representing the Hebrew year.
1195 /// <returns>An integer giving the number of the last month of the
1196 /// Hebrew year, which is the same as the numbers of month in the
1199 public static int last_month_of_year(int year) {
1200 return is_leap_year(year) ? 13 : 12;
1204 /// <summary>The method is a helper function.</summary>
1205 /// <param name="year">An integer specifying the Hebrew year.
1207 /// <returns>An integer representing the number of elapsed days
1208 /// until the Hebrew year.</returns>
1209 public static int elapsed_days(int year) {
1210 int months_elapsed = CCMath.div(235*year-234, 19);
1212 int d = CCMath.div_mod(out r, months_elapsed, 1080);
1213 int parts_elapsed = 204 + 793 * r;
1214 int hours_elapsed = 11 + 12 * months_elapsed +
1215 793 * d + CCMath.div(parts_elapsed, 1080);
1217 int day = 29*months_elapsed + CCMath.div(hours_elapsed, 24);
1219 if (CCMath.mod(3*(day+1), 7) < 3) {
1226 /// <summary>A method computing the delay of new year for the given
1229 /// <param name="year">An integer that gives the Hebrew year.
1231 /// <returns>The new year delay in days of the given Hebrew year.
1233 public static int new_year_delay(int year) {
1234 int ny1 = elapsed_days(year);
1235 int ny2 = elapsed_days(year+1);
1237 if (ny2 - ny1 == 356) {
1240 int ny0 = elapsed_days(year-1);
1241 if (ny1 - ny0 == 382) {
1248 /// The method computes the last day of month (nummer of days in a
1249 /// month) of the given Hebrew year.
1251 /// <param name="month">The Hebrew month, allowed value between
1252 /// One and Thirteen.
1254 /// <param name="year">An integer that gives the Hebrew year.
1256 /// <returns>The number of the last day of the month of the given
1257 /// Hebrew year, which gives automatically the number of days in the
1260 /// <exception cref="T:System.ArgumentOutOfRange.Exception">
1261 /// The exception is thrown if month not between One and Thirteen.
1263 public static int last_day_of_month(int month, int year) {
1264 if (month < 1 || month > 13)
1265 throw new System.ArgumentOutOfRangeException("month",
1266 "Month should be between One and Thirteen.");
1272 if (!long_heshvan(year))
1276 if (short_kislev(year))
1281 if (!is_leap_year(year))
1290 /// The functions checks whether the month Heshvan is a long one
1291 /// in the given Hebrew year.
1293 /// <param name="year">An integer that gives the Hebrew year.
1295 /// <returns>A boolean value: true if there is a long Heshvan
1296 /// in the given Hebrew year; false otherwise.
1298 public static bool long_heshvan(int year) {
1299 return CCMath.mod(days_in_year(year), 10) == 5;
1303 /// The functions checks whether the month Kislev is a short one
1304 /// in the given Hebrew year.
1306 /// <param name="year">An integer that gives the Hebrew year.
1308 /// <returns>A boolean value: true if there is a short Kislev
1309 /// in the given Hebrew year; false otherwise.
1311 public static bool short_kislev(int year) {
1312 return CCMath.mod(days_in_year(year), 10) == 3;
1316 /// The functions gives the number of days in the specified Hebrew
1319 /// <param name="year">An integer that gives the Hebrew year.
1321 /// <returns>The days of the Hebrew year as integer.
1323 public static int days_in_year(int year) {
1324 return fixed_from_dmy(1, 7, year+1) -
1325 fixed_from_dmy(1, 7, year);
1329 /// The method returns the fixed day number of the given Hebrew
1332 /// <param name="day">An integer representing the day of the month,
1333 /// counting from 1.
1335 /// <param name="month">An integer representing the month in the
1338 /// <param name="year">An integer representing the Hebrew year.
1339 /// Non-positive values are allowed also.
1341 /// <returns>An integer value representing the fixed day number.
1343 public static int fixed_from_dmy(int day, int month, int year) {
1346 k += elapsed_days(year);
1347 k += new_year_delay(year);
1350 int l = last_month_of_year(year);
1351 for (m = 7; m <= l; m++) {
1352 k += last_day_of_month(m, year);
1354 for (m = 1; m < month; m++) {
1355 k += last_day_of_month(m, year);
1359 for (m = 7; m < month; m++) {
1360 k += last_day_of_month(m, year);
1370 /// The method computes the Hebrew year from a fixed day number.
1372 /// <param name="date">The fixed day number.
1374 /// <returns>An integer value giving the Hebrew year of the date.
1376 public static int year_from_fixed(int date) {
1377 int approx = (int)System.Math.Floor(
1378 ((double)(date - epoch))/(35975351.0/98496.0));
1380 for (y = approx; date >= fixed_from_dmy(1, 7, y); y++) {}
1385 /// The method computes the Hebrew year and month from a fixed day
1388 /// <param name="month">The output value giving the Hebrew month.
1390 /// <param name="year">The output value giving the Hebrew year.
1392 /// <param name="date">An integer value specifying the fixed day
1394 public static void my_from_fixed(out int month, out int year,
1397 year = year_from_fixed(date);
1399 int start = date < fixed_from_dmy(1, 1, year) ? 7 : 1;
1402 date > fixed_from_dmy(last_day_of_month(month, year),
1409 /// The method computes the Hebrew year, month, and day from a
1410 /// fixed day number.
1412 /// <param name="day">The output value returning the day of the
1415 /// <param name="month">The output value giving the Hebrew month.
1417 /// <param name="year">The output value giving the Hebrew year.
1419 /// <param name="date">An integer value specifying the fixed day
1421 public static void dmy_from_fixed(out int day, out int month,
1422 out int year, int date)
1424 my_from_fixed(out month, out year, date);
1425 day = date - fixed_from_dmy(1, month, year) + 1;
1428 /// <summary>A method computing the Hebrew month from a fixed
1431 /// <param name="date">An integer specifying the fixed day number.
1433 /// <returns>An integer value representing the Hebrew month.
1435 public static int month_from_fixed(int date) {
1438 my_from_fixed(out month, out year, date);
1443 /// A method computing the day of the month from a fixed day number.
1445 /// <param name="date">An integer specifying the fixed day number.
1447 /// <returns>An integer value representing the day of the month.
1449 public static int day_from_fixed(int date) {
1450 int day, month, year;
1452 dmy_from_fixed(out day, out month, out year, date);
1457 /// The method computes the difference between two Hebrew dates.
1459 /// <param name="dayA">The integer parameter gives the day of month
1460 /// of the first date.
1462 /// <param name="monthA">The integer parameter gives the Hebrew
1463 /// month of the first date.
1465 /// <param name="yearA">The integer parameter gives the Hebrew
1466 /// year of the first date.
1468 /// <param name="dayB">The integer parameter gives the day of month
1469 /// of the second date.
1471 /// <param name="monthB">The integer parameter gives the Hebrew
1472 /// month of the second date.
1474 /// <param name="yearB">The integer parameter gives the Hebrew
1475 /// year of the second date.
1477 /// <returns>An integer giving the difference of days from the first
1478 /// the second date.
1480 public static int date_difference(int dayA, int monthA, int yearA,
1481 int dayB, int monthB, int yearB)
1483 return fixed_from_dmy(dayB, monthB, yearB) -
1484 fixed_from_dmy(dayA, monthA, yearA);
1488 /// The method computes the number of the day in the year from
1491 /// <param name="day">An integer representing the day of the month,
1492 /// counting from 1.
1494 /// <param name="month">An integer representing the month in the
1497 /// <param name="year">An integer representing the Hebrew year.
1499 /// <returns>An integer value giving the number of the day in the
1500 /// Hebrew year, counting from 1.
1502 public static int day_number(int day, int month, int year) {
1503 return date_difference(1, 7, year,
1504 day, month, year) + 1;
1508 /// The method computes the days remaining in the given Hebrew
1509 /// year from a Hebrew date.
1511 /// <param name="day">An integer representing the day of the month,
1512 /// counting from 1.
1514 /// <param name="month">An integer representing the month in the
1517 /// <param name="year">An integer representing the Hebrew year.
1519 /// <returns>An integer value giving the number of days remaining in
1520 /// the Hebrew year.
1522 public static int days_remaining(int day, int month, int year) {
1523 return date_difference(day, month, year,
1526 } // class HebrewCalendar
1530 /// A class encapsulating the functions of the Islamic calendar as static
1534 /// <para>There is no difference here in using Hijri or Islamic calendar.
1536 /// <para>The epoch of the Islamic calendar isn't fixed, because we cannot
1537 /// surely say today, when the crescent of the new moon has been observed
1538 /// around the July 16, 622 C.E. Julian. Even today the start and end of
1539 /// the month Ramadan is defined by religous authorities. So the calendar
1540 /// can be offset by two days.
1543 /// We don't support the offset here, however we changed the epoch from
1544 /// "Calendrical Calculations" to value, that .Net seems to be using.
1547 /// This class is not compatible to
1548 /// <see cref="T:System.Globalization.HijriCalendar"/>.
1550 /// <seealso cref="T:CCFixed"/>
1552 internal class CCHijriCalendar {
1553 /// <summary>An integer defining the epoch of the Gregorian calendar
1554 /// as fixed day number.</summary>
1557 /// The epoch is given as 16 July 622 C.E. Julian (R.D. 227015)
1558 /// in Calendrical Calculations, the approximate date of
1559 /// the emigration of
1560 /// Muhammed to Medina. However there is no way to determine today
1561 /// the observation of the crescent of the new moon in July 622 C.E.
1562 /// (Julian). So there is some variability in the epoch.
1563 /// Religous authorities determine the epoch by observing the
1564 /// crescent of the new moon for the month Ramadan, so there might
1565 /// be an offsets by two days of the epoch.
1568 /// supports an AddHijriDate parameter in the registry to adapt
1569 /// for it. It seems that the .NET implementation of
1570 /// HijriCalendar uses an epoch of 227014, so we use it here. The
1571 /// ArgumentOutOfRangeException gives July, 18 622 as epoch,
1572 /// which is 227014 supporting our theory.
1575 const int epoch = 227014;
1577 /// <summary>The enumeration defines the months of the Islamic
1632 /// The method tells whether the year is a leap year.
1634 /// <param name="year">An integer representing the Islamic year.
1636 /// <returns>A boolean which is true if <paramref name="year"/> is
1639 public static bool is_leap_year(int year) {
1640 return CCMath.mod(14+11*year, 30) < 11;
1644 /// The method returns the fixed day number of the given Islamic
1647 /// <param name="day">An integer representing the day of the month,
1648 /// counting from 1.
1650 /// <param name="month">An integer representing the month in the
1653 /// <param name="year">An integer representing the Islamic year.
1654 /// Non-positive values are allowed also.
1656 /// <returns>An integer value representing the fixed day number.
1658 public static int fixed_from_dmy(int day, int month, int year) {
1660 k += 354 * (year-1);
1661 k += CCMath.div(3+11*year, 30);
1662 k += (int)System.Math.Ceiling(29.5 * (double)(month-1));
1669 /// The method computes the Islamic year from a fixed day number.
1671 /// <param name="date">The fixed day number.
1673 /// <returns>An integer value giving the Islamic year of the date.
1675 public static int year_from_fixed(int date) {
1676 return CCMath.div(30*(date-epoch)+10646, 10631);
1680 /// The method computes the Islamic year and month from a fixed day
1683 /// <param name="month">The output value giving the Islamic month.
1685 /// <param name="year">The output value giving the Islamic year.
1687 /// <param name="date">An integer value specifying the fixed day
1689 public static void my_from_fixed(out int month, out int year, int date)
1691 year = year_from_fixed(date);
1693 int m = 1+(int)System.Math.Ceiling(
1694 ((double)(date-29-fixed_from_dmy(1,1,year)))/29.5);
1696 month = m < 12 ? m : 12;
1700 /// The method computes the Islamic year, month, and day from a
1701 /// fixed day number.
1703 /// <param name="day">The output value returning the day of the
1706 /// <param name="month">The output value giving the Islamic month.
1708 /// <param name="year">The output value giving the Islamic year.
1710 /// <param name="date">An integer value specifying the fixed day
1712 public static void dmy_from_fixed(out int day, out int month,
1713 out int year, int date)
1715 my_from_fixed(out month, out year, date);
1716 day = date - fixed_from_dmy(1, month, year) + 1;
1719 /// <summary>A method computing the Islamic month from a fixed
1722 /// <param name="date">An integer specifying the fixed day number.
1724 /// <returns>An integer value representing the Islamic month.
1726 public static int month_from_fixed(int date) {
1729 my_from_fixed(out month, out year, date);
1734 /// A method computing the day of the month from a fixed day number.
1736 /// <param name="date">An integer specifying the fixed day number.
1738 /// <returns>An integer value representing the day of the month.
1740 public static int day_from_fixed(int date) {
1745 dmy_from_fixed(out day, out month, out year, date);
1750 /// The method computes the difference between two Islamic dates.
1752 /// <param name="dayA">The integer parameter gives the day of month
1753 /// of the first date.
1755 /// <param name="monthA">The integer parameter gives the Islamic
1756 /// month of the first date.
1758 /// <param name="yearA">The integer parameter gives the Islamic
1759 /// year of the first date.
1761 /// <param name="dayB">The integer parameter gives the day of month
1762 /// of the second date.
1764 /// <param name="monthB">The integer parameter gives the Islamic
1765 /// month of the second date.
1767 /// <param name="yearB">The integer parameter gives the Islamic
1768 /// year of the second date.
1770 /// <returns>An integer giving the difference of days from the first
1771 /// the second date.
1773 public static int date_difference(int dayA, int monthA, int yearA,
1774 int dayB, int monthB, int yearB)
1776 return fixed_from_dmy(dayB, monthB, yearB) -
1777 fixed_from_dmy(dayA, monthA, yearA);
1781 /// The method computes the number of the day in the year from
1784 /// <param name="day">An integer representing the day of the month,
1785 /// counting from 1.
1787 /// <param name="month">An integer representing the month in the
1790 /// <param name="year">An integer representing the Islamic year.
1792 /// <returns>An integer value giving the number of the day in the
1793 /// Islamic year, counting from 1.
1795 public static int day_number(int day, int month, int year) {
1796 return date_difference(31, 12, year-1, day, month, year);
1800 /// The method computes the days remaining in the given Islamic
1801 /// year from a Islamic date.
1803 /// <param name="day">An integer representing the day of the month,
1804 /// counting from 1.
1806 /// <param name="month">An integer representing the month in the
1809 /// <param name="year">An integer representing the Islamic year.
1810 /// Non-positive values are allowed also.
1812 /// <returns>An integer value giving the number of days remaining in
1813 /// the Islamic year.
1815 public static int days_remaining(int day, int month, int year) {
1816 return date_difference(day, month, year,31, 12, year);
1818 } // class CCHijriCalendar
1821 /// A class that supports the Gregorian based calendars with other eras
1822 /// (e.g. <see cref="T:System.Gloablization.JapaneseCalendar"/>).
1824 [System.Serializable]
1825 internal class CCGregorianEraHandler {
1827 /// A struct that represents a single era.
1829 [System.Serializable]
1832 /// The integer number identifying the era.
1837 /// A get-only property that gives the era integer number.
1839 public int Nr { get { return _nr; } }
1841 /// <summary>This integer gives the first day of the era as
1842 /// fixed day number.
1844 private int _start; // inclusive
1846 /// This integer gives the gregorian year of the
1847 /// <see cref="M:_start"/> value.
1849 private int _gregorianYearStart;
1851 /// This integer gives the last day of the era as fixed day
1854 private int _end; // inclusive
1856 /// This integer gives the largest year number of this era.
1858 private int _maxYear;
1861 /// This constructor creates the era structure.
1863 /// <param name="nr">The integer number of the era.
1865 /// <param name="start">The fixed day number defining the
1866 /// first day of the era.
1868 /// <param name="end">The fixed day number that defines the
1869 /// last day of the era.
1871 public Era(int nr, int start, int end) {
1873 throw new System.ArgumentException(
1874 "Era number shouldn't be zero.");
1877 throw new System.ArgumentException(
1878 "Era should start before end.");
1883 _gregorianYearStart =
1884 CCGregorianCalendar.year_from_fixed(_start);
1885 int gregorianYearEnd =
1886 CCGregorianCalendar.year_from_fixed(_end);
1887 _maxYear = gregorianYearEnd - _gregorianYearStart + 1;
1891 /// This method computes the Gregorian year from the year
1894 /// <param name="year">An integer giving the year in the
1898 /// The Gregorian year as integer.
1900 /// <exception cref="T:System.ArgumentOutOfRangeException">
1901 /// The exception is thrown if the year isn't valid in this
1904 public int GregorianYear(int year) {
1905 if (year < 1 || year > _maxYear) {
1906 System.IO.StringWriter sw =
1907 new System.IO.StringWriter();
1909 "Valid Values are between " +
1910 "{0} and {1}, inclusive.",
1912 throw new System.ArgumentOutOfRangeException(
1913 "year", sw.ToString());
1915 return year + _gregorianYearStart - 1;
1919 /// This function checks wether the given fixed day number is
1920 /// ion the time span of the era.
1922 /// <param name="date">An integer giving the fixed day
1925 /// <returns>A boolean: true if the argument is in the time
1926 /// span of the era.
1928 public bool Covers(int date) {
1929 return _start <= date && date <= _end;
1933 /// This function returns the year of the era and sets
1934 /// the era in an output parameter.
1936 /// <param name="era">An output parameter returning the
1939 /// <param name="date">An integer giving the fixed day
1942 /// <returns>An integer giving the year of the era.
1944 /// <exception cref="T:System.ArgumentOutOfRangeException">
1945 /// The exception is thrown if date is outside of the time
1946 /// span of the era.
1948 public int EraYear(out int era, int date) {
1950 throw new System.ArgumentOutOfRangeException(
1952 "Time was out of Era range.");
1954 CCGregorianCalendar.year_from_fixed(date);
1956 return gregorianYear - _gregorianYearStart + 1;
1961 /// A private member storing the eras in a
1962 /// <see cref="T:System.Collections.SortedList"/>.
1964 private SortedList _Eras;
1967 /// The property returns the era numbers as an array of integers.
1971 int[] a = new int[_Eras.Count];
1973 for (int i = 0; i < _Eras.Count; i++) {
1974 Era e = (Era)_Eras.GetByIndex(i);
1985 public CCGregorianEraHandler() {
1986 _Eras = new SortedList();
1990 /// Method adds an era to the GregorianEraHandler instance.
1992 /// <param name="nr">The integer number of the era.
1994 /// <param name="rd_start">The fixed day number defining the
1995 /// first day of the era.
1997 /// <param name="rd_end">The fixed day number that defines the
1998 /// last day of the era.
2000 public void appendEra(int nr, int rd_start, int rd_end) {
2001 Era era = new Era(nr, rd_start, rd_end);
2002 _Eras[(System.Object)nr] = era;
2005 /// Method adds a yet not-ended era to the GregorianEraHandler
2008 /// <param name="nr">The integer number of the era.
2010 /// <param name="rd_start">The fixed day number defining the
2011 /// first day of the era.
2013 public void appendEra(int nr, int rd_start) {
2014 appendEra(nr, rd_start,
2015 CCFixed.FromDateTime(DateTime.MaxValue));
2019 /// This method computes the Gregorian year from the year
2020 /// of the given era.
2022 /// <param name="year">An integer giving the year in the
2025 /// <param name="era">An integer giving the era number.
2028 /// The Gregorian year as integer.
2030 /// <exception cref="T:System.ArgumentOutOfRangeException">
2031 /// The exception is thrown if the year isn't valid in this
2034 public int GregorianYear(int year, int era) {
2035 Era e = (Era)_Eras[(System.Object)era];
2036 return e.GregorianYear(year);
2040 /// This function returns the year of the era and sets
2041 /// the era in an output parameter.
2043 /// <param name="era">An output parameter returning the
2046 /// <param name="date">An integer giving the fixed day
2049 /// <returns>An integer giving the year of the era.
2051 /// <exception cref="T:System.ArgumentOutOfRangeException">
2052 /// The exception is thrown if the fixed day number is outside of the
2053 /// time spans of all eras.
2055 public int EraYear(out int era, int date)
2057 IList list = _Eras.GetValueList();
2059 foreach (Era e in list) {
2061 return e.EraYear(out era, date);
2064 throw new System.ArgumentOutOfRangeException("date",
2065 "Time value was out of era range.");
2069 /// The method checks whether a given
2070 /// <see cref="T:System.DateTime"/> is covered by any era.
2072 /// <param name="time">A
2073 /// <see cref="T:System.DateTime"/> giving the date and time.
2075 /// <exception cref="T:System.ArgumentOutOfRangeException">
2076 /// The exception is thrown if the argument isn't inside the time
2077 /// span of any era.
2079 public void CheckDateTime(System.DateTime time) {
2080 int date = CCFixed.FromDateTime(time);
2082 if (!ValidDate(date))
2083 throw new System.ArgumentOutOfRangeException("time",
2084 "Time value was out of era range.");
2088 /// The method tests whether a given
2089 /// fixed day number is covered by any era.
2091 /// <param name="date">An integer representing the fixed day number.
2093 /// <returns> A boolean is returned: true if the argument is inside
2094 /// the time span of one era; false otherwise.
2096 public bool ValidDate(int date) {
2097 IList list = _Eras.GetValueList();
2099 foreach (Era e in list) {
2108 /// The method tests, whether the era number does exist.
2110 /// <param name="era">An integer giving the era number.
2112 /// <returns>A boole value: True if the era number does exist;
2113 /// false otherwise.
2115 public bool ValidEra(int era) {
2116 return _Eras.Contains((System.Object)era);
2118 } // class CCGregorianEraHandler
2120 } // namespace System.Globalization