// 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]
[MonoLimitation ("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;
}
public override int GetLeapMonth (int year, int era)
{
return IsLeapMonth (year, 7, era) ? 7 : 0;
}
///
/// 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_1
public override CalendarAlgorithmType AlgorithmType {
get {
return CalendarAlgorithmType.LunisolarCalendar;
}
}
#endif
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;
}
}
} // class HebrewCalendar
} // namespace System.Globalization