// System.Globalization.HebrewCalendar.cs // // (C) Ulrich Kunitz 2002 // // // Copyright (C) 2004 Novell, Inc (http://www.novell.com) // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // namespace System.Globalization { using System; using System.IO; using System.Runtime.InteropServices; /// /// This is the Hebrew calendar. /// /// /// The Hebrew calendar supports only years between 5343 A.M. and /// 6000 A.M. This has been done to be compatible with .NET. /// /// The implementation uses the /// namespace. /// /// [Serializable] #if NET_2_0 [ComVisible (true)] #endif [MonoTODO ("Serialization format not compatible with.NET")] public class HebrewCalendar : Calendar { /// /// Constructor. /// public HebrewCalendar() { M_AbbrEraNames = new string[] {"A.M."}; M_EraNames = new string[] {"Anno Mundi"}; if (twoDigitYearMax == 99) twoDigitYearMax = 5790; } /// /// The era number for the Anno Mundi (A.M.) era, called /// plain HebrewEra. /// public static readonly int HebrewEra = 1; /// /// The /// ticks for first day of year /// 5343 A.M. /// internal const long M_MinTicks = 499147488000000000L; /// /// The number of /// ticks for the last day of year /// 6000 A.M. /// internal const long M_MaxTicks = 706783967999999999L; /// /// The minimum year in the A.M. era supported. /// internal const int M_MinYear = 5343; /// /// The maximum year supported in the A.M. era. /// internal override int M_MaxYear { get { return 6000; } } /// Overridden. Gives the eras supported by the Gregorian /// calendar as an array of integers. /// public override int[] Eras { get { return new int[] { HebrewEra }; } } public override int TwoDigitYearMax { get { return twoDigitYearMax; } set { CheckReadOnly (); M_ArgumentInRange ("value", value, M_MinYear, M_MaxYear); twoDigitYearMax = value; } } /// /// A protected member checking a /// value. /// /// The /// /// to check. /// /// /// The exception is thrown if the /// parameter is not in the years /// between 5343 A.M. and 6000 A.M., inclusive. /// internal void M_CheckDateTime(DateTime time) { if (time.Ticks < M_MinTicks || time.Ticks > M_MaxTicks) throw new ArgumentOutOfRangeException( "time", "Only hebrew years between 5343 and 6000," + " inclusive, are supported."); } /// /// A protected method checking the era number. /// /// The era number. /// /// The exception is thrown if the era is not equal /// . /// internal void M_CheckEra(ref int era) { if (era == CurrentEra) era = HebrewEra; if (era != HebrewEra) throw new ArgumentException("Era value was not valid."); } /// /// A protected method checking calendar year and the era number. /// /// An integer representing the calendar year. /// /// The era number. /// /// The exception is thrown if the era is not equal /// . /// /// /// The exception is thrown if the calendar year is outside of /// the allowed range. /// internal override void M_CheckYE(int year, ref int era) { M_CheckEra(ref era); if (year < M_MinYear || year > M_MaxYear) throw new ArgumentOutOfRangeException( "year", "Only hebrew years between 5343 and 6000," + " inclusive, are supported."); } /// /// A protected method checking the calendar year, month, and /// era number. /// /// An integer representing the calendar year. /// /// An integer giving the calendar month. /// /// The era number. /// /// The exception is thrown if the era is not equal /// . /// /// /// The exception is thrown if the calendar year or month is /// outside of the allowed range. /// internal void M_CheckYME(int year, int month, ref int era) { M_CheckYE(year, ref era); int l = CCHebrewCalendar.last_month_of_year(year); if (month < 1 || month > l) { StringWriter sw = new StringWriter(); sw.Write("Month must be between 1 and {0}.", l); throw new ArgumentOutOfRangeException("month", sw.ToString()); } } /// /// A protected method checking the calendar day, month, and year /// and the era number. /// /// An integer representing the calendar year. /// /// An integer giving the calendar month. /// /// An integer giving the calendar day. /// /// The era number. /// /// The exception is thrown if the era is not equal /// . /// /// /// The exception is thrown if the calendar year, month, or day is /// outside of the allowed range. /// internal void M_CheckYMDE(int year, int month, int day, ref int era) { M_CheckYME(year, month, ref era); M_ArgumentInRange("day", day, 1, GetDaysInMonth(year, month, era)); } /// /// Overrideden. Adds months to a given date. /// /// The /// to which to add /// months. /// /// The number of months to add. /// A new value, that /// results from adding to the specified /// DateTime. /// /// The exception is thrown if the /// return value is not in the years /// between 5343 A.M. and 6000 A.M., inclusive. /// public override DateTime AddMonths(DateTime time, int months) { int y, m, d; DateTime t; if (months == 0) { t = time; } else { int rd = CCFixed.FromDateTime(time); CCHebrewCalendar.dmy_from_fixed( out d, out m, out y, rd); m = M_Month(m, y); if (months < 0) { while (months < 0) { if (m+months > 0) { m += months; months = 0; } else { months += m; y -= 1; m = GetMonthsInYear(y); } } } else { while (months > 0) { int my = GetMonthsInYear(y); if (m+months <= my) { m += months; months = 0; } else { months -= my-m+1; m = 1; y += 1; } } } t = ToDateTime(y, m, d, 0, 0, 0, 0); t = t.Add(time.TimeOfDay); } M_CheckDateTime(t); return t; } /// /// Overridden. Adds years to a given date. /// /// The /// to which to add /// years. /// /// The number of years to add. /// A new value, that /// results from adding to the specified /// DateTime. /// /// The exception is thrown if the /// return value is not in the years /// between 5343 A.M. and 6000 A.M., inclusive. /// public override DateTime AddYears(DateTime time, int years) { int rd = CCFixed.FromDateTime(time); int day, month, year; CCHebrewCalendar.dmy_from_fixed( out day, out month, out year, rd); year += years; rd = CCHebrewCalendar.fixed_from_dmy(day, month, year); DateTime t = CCFixed.ToDateTime(rd); t = t.Add(time.TimeOfDay); M_CheckDateTime(t); return t; } /// /// Overriden. Gets the day of the month from /// . /// /// The /// that specifies a /// date. /// /// An integer giving the day of months, starting with 1. /// /// /// The exception is thrown if the /// parameter is not in the years /// between 5343 A.M. and 6000 A.M., inclusive. /// public override int GetDayOfMonth(DateTime time) { M_CheckDateTime(time); int rd = CCFixed.FromDateTime(time); return CCHebrewCalendar.day_from_fixed(rd); } /// /// Overriden. Gets the day of the week from the specified date. /// /// The /// that specifies a /// date. /// /// An integer giving the day of months, starting with 1. /// /// /// The exception is thrown if the /// parameter is not in the years /// between 5343 A.M. and 6000 A.M., inclusive. /// public override DayOfWeek GetDayOfWeek(DateTime time) { M_CheckDateTime(time); int rd = CCFixed.FromDateTime(time); return (DayOfWeek)CCFixed.day_of_week(rd); } /// /// Overridden. Gives the number of the day in the year. /// /// The /// that specifies a /// date. /// /// An integer representing the day of the year, /// starting with 1. /// /// The exception is thrown if the /// parameter is not in the years /// between 5343 A.M. and 6000 A.M., inclusive. /// public override int GetDayOfYear(DateTime time) { M_CheckDateTime(time); int rd = CCFixed.FromDateTime(time); int year = CCHebrewCalendar.year_from_fixed(rd); int rd1_7 = CCHebrewCalendar.fixed_from_dmy(1, 7, year); return rd - rd1_7 + 1; } /// /// The method maps a .NET Hebrew month to a Calencdrical /// Calculations Hebrew month. /// /// An integer representing a month in .NET /// counting (starting with Tishri). /// /// An integer representing the Hebrew year. /// /// The Hebrew month in Calendrical Calculations counting, /// staring with the Hebrew month Nisan. /// /// /// /// In .NET the month counting starts with the Hebrew month Tishri. /// Calendrical Calculations starts with the month Nisan. So we must /// map here. /// /// internal int M_CCMonth(int month, int year) { if (month <= 6) { return 6+month; } else { int l = CCHebrewCalendar.last_month_of_year(year); if (l == 12) { return month-6; } else { return month <= 7 ? 6+month : month-7; } } } /// /// The method maps a Calendrical Calculations Hebrew month /// to a .NET Hebrew month. /// /// An integer representing a month in /// Calendrical Calculations counting, starting with Nisan. /// /// An integer representing the Hebrew year. /// /// The Hebrew month in .NET counting, /// staring with the Hebrew month Tishri. /// /// /// /// In .NET the month counting starts with the Hebrew month Tishri. /// Calendrical Calculations starts with the month Tisan. So we must /// map here. /// /// internal int M_Month(int ccmonth, int year) { if (ccmonth >= 7) { return ccmonth - 6; } else { int l = CCHebrewCalendar.last_month_of_year(year); return ccmonth + (l == 12 ? 6 : 7); } } /// /// Overridden. Gives the number of days in the specified month /// of the given year and era. /// /// An integer that gives the year. /// /// An integer that gives the month, starting /// with 1. /// An integer that gives the era of the specified /// year. /// An integer that gives the number of days of the /// specified month. /// /// The exception is thrown, if , /// ,or is outside /// the allowed range. /// public override int GetDaysInMonth(int year, int month, int era) { M_CheckYME(year, month, ref era); int ccmonth = M_CCMonth(month, year); return CCHebrewCalendar.last_day_of_month(ccmonth, year); } /// /// Overridden. Gives the number of days of the specified /// year of the given era. /// /// An integer that specifies the year. /// /// An ineger that specifies the era. /// /// An integer that gives the number of days of the /// specified year. /// /// The exception is thrown, if /// or are outside the /// allowed range. /// public override int GetDaysInYear(int year, int era) { M_CheckYE(year, ref era); int rd1 = CCHebrewCalendar.fixed_from_dmy(1, 7, year); int rd2 = CCHebrewCalendar.fixed_from_dmy(1, 7, year+1); return rd2 - rd1; } /// /// Overridden. Gives the era of the specified date. /// /// The /// that specifies a /// date. /// /// An integer representing the era of the calendar. /// /// /// The exception is thrown if the /// parameter is not in the years /// between 5343 A.M. and 6000 A.M., inclusive. /// public override int GetEra(DateTime time) { M_CheckDateTime(time); return HebrewEra; } #if NET_2_0 public override int GetLeapMonth (int year, int era) { return IsLeapMonth (year, 7, era) ? 7 : 0; } #endif /// /// Overridden. Gives the number of the month of the specified /// date. /// /// The /// that specifies a /// date. /// /// An integer representing the month, /// starting with 1. /// /// The exception is thrown if the /// parameter is not in the years /// between 5343 A.M. and 6000 A.M., inclusive. /// public override int GetMonth(DateTime time) { M_CheckDateTime(time); int rd = CCFixed.FromDateTime(time); int ccmonth, year; CCHebrewCalendar.my_from_fixed(out ccmonth, out year, rd); return M_Month(ccmonth, year); } /// /// Overridden. Gives the number of months in the specified year /// and era. /// /// An integer that specifies the year. /// /// An integer that specifies the era. /// /// An integer that gives the number of the months in the /// specified year. /// /// The exception is thrown, if the year or the era are not valid. /// public override int GetMonthsInYear(int year, int era) { M_CheckYE(year, ref era); return CCHebrewCalendar.last_month_of_year(year); } /// /// Overridden. Gives the number of the year of the specified /// date. /// /// The /// that specifies a /// date. /// /// An integer representing the year, /// starting with 1. /// /// The exception is thrown if the /// parameter is not in the years /// between 5343 A.M. and 6000 A.M., inclusive. /// public override int GetYear(DateTime time) { M_CheckDateTime(time); int rd = CCFixed.FromDateTime(time); return CCHebrewCalendar.year_from_fixed(rd); } /// /// Overridden. Tells whether the given day /// is a leap day. /// /// An integer that specifies the year in the /// given era. /// /// An integer that specifies the month. /// /// An integer that specifies the day. /// /// An integer that specifies the era. /// /// A boolean that tells whether the given day is a leap /// day. /// /// /// The exception is thrown, if the year, month, day, or era is not /// valid. /// /// All days in Adar II are viewed as leap days and the /// last day of Adar I. /// public override bool IsLeapDay(int year, int month, int day, int era) { M_CheckYMDE(year, month, day, ref era); return IsLeapYear(year) && (month == 7 || (month == 6 && day == 30)); } /// /// Overridden. Tells whether the given month /// is a leap month. /// /// An integer that specifies the year in the /// given era. /// /// An integer that specifies the month. /// /// An integer that specifies the era. /// /// A boolean that tells whether the given month is a leap /// month. /// /// /// The exception is thrown, if the year, month, or era is not /// valid. /// /// /// Adar II is viewed as leap month. /// public override bool IsLeapMonth(int year, int month, int era) { M_CheckYME(year, month, ref era); return IsLeapYear(year) && month == 7; } /// /// Overridden. Tells whether the given year /// is a leap year. /// /// An integer that specifies the year in the /// given era. /// /// An integer that specifies the era. /// /// A boolean that tells whether the given year is a leap /// year. /// /// /// The exception is thrown, if the year or era is not /// valid. /// public override bool IsLeapYear(int year, int era) { M_CheckYE(year, ref era); return CCHebrewCalendar.is_leap_year(year); } /// /// Overridden. Creates the /// from the parameters. /// /// An integer that gives the year in the /// . /// /// An integer that specifies the month. /// /// An integer that specifies the day. /// /// An integer that specifies the hour. /// /// An integer that specifies the minute. /// /// An integer that gives the second. /// /// An integer that gives the /// milliseconds. /// /// An integer that specifies the era. /// /// A /// representig the date and time. /// /// /// The exception is thrown, if at least one of the parameters /// is out of range. /// public override DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era) { M_CheckYMDE(year, month, day, ref era); M_CheckHMSM(hour, minute, second, millisecond); int ccm = M_CCMonth(month, year); int rd = CCHebrewCalendar.fixed_from_dmy(day, ccm, year); return CCFixed.ToDateTime(rd, hour, minute, second, millisecond); } public override int ToFourDigitYear (int year) { M_ArgumentInRange ("year", year, 0, M_MaxYear - 1); int baseExtra = this.twoDigitYearMax % 100; int baseCentury = this.twoDigitYearMax - baseExtra; if (year >= 100) return year; if (year <= baseExtra) return baseCentury + year; else return baseCentury + year - 100; } #if NET_2_0 public override CalendarAlgorithmType AlgorithmType { get { return CalendarAlgorithmType.LunisolarCalendar; } } static DateTime Min = new DateTime (1583, 1, 1, 0, 0, 0); static DateTime Max = new DateTime (2239, 9, 29, 11, 59, 59); public override DateTime MinSupportedDateTime { get { return Min; } } public override DateTime MaxSupportedDateTime { get { return Max; } } #endif } // class HebrewCalendar } // namespace System.Globalization