private static int GetResult(DateBuffer result, int part) { return(part switch { DatePartYear => result.year, DatePartMonth => result.month, DatePartDay => result.day, _ => throw new InvalidOperationException(SR.InvalidOperation_DateTimeParsing), });
/// <summary> /// Using the Hebrew table (HebrewTable) to get the Hebrew month/day value for Gregorian January 1st /// in a given Gregorian year. /// Greogrian January 1st falls usually in Tevet (4th month). Tevet has always 29 days. /// That's why, there no nead to specify the lunar month in the table. There are exceptions, and these /// are coded by giving numbers above 29 and below 1. /// Actual decoding is takenig place in the switch statement below. /// </summary> /// <returns> /// The Hebrew year type. The value is from 1 to 6. /// normal years : 1 = 353 days 2 = 354 days 3 = 355 days. /// Leap years : 4 = 383 5 384 6 = 385 days. /// </returns> internal static int GetLunarMonthDay(int gregorianYear, DateBuffer lunarDate) { // Get the offset into the LunarMonthLen array and the lunar day // for January 1st. int index = gregorianYear - FirstGregorianTableYear; if (index < 0 || index > TableSize) { throw new ArgumentOutOfRangeException(nameof(gregorianYear)); } index *= 2; lunarDate.day = s_hebrewTable[index]; // Get the type of the year. The value is from 1 to 6 int lunarYearType = s_hebrewTable[index + 1]; // Get the Lunar Month. switch (lunarDate.day) { case 0: // 1/1 is on Shvat 1 lunarDate.month = 5; lunarDate.day = 1; break; case 30: // 1/1 is on Kislev 30 lunarDate.month = 3; break; case 31: // 1/1 is on Shvat 2 lunarDate.month = 5; lunarDate.day = 2; break; case 32: // 1/1 is on Shvat 3 lunarDate.month = 5; lunarDate.day = 3; break; case 33: // 1/1 is on Kislev 29 lunarDate.month = 3; lunarDate.day = 29; break; default: // 1/1 is on Tevet (This is the general case) lunarDate.month = 4; break; } return(lunarYearType); }
private static int GetResult(DateBuffer result, int part) { switch (part) { case DatePartYear: return(result.year); case DatePartMonth: return(result.month); case DatePartDay: return(result.day); } throw new InvalidOperationException(SR.InvalidOperation_DateTimeParsing); }
/// <summary> /// Convert Hebrew date to Gregorian date. /// The algorithm is like this: /// The hebrew year has an offset to the Gregorian year, so we can guess the Gregorian year for /// the specified Hebrew year. That is, GreogrianYear = HebrewYear - FirstHebrewYearOf1AD. /// /// From the Gregorian year and HebrewTable, we can get the Hebrew month/day value /// of the Gregorian date January 1st. Let's call this month/day value [hebrewDateForJan1] /// /// If the requested Hebrew month/day is less than [hebrewDateForJan1], we know the result /// Gregorian date falls in previous year. So we decrease the Gregorian year value, and /// retrieve the Hebrew month/day value of the Gregorian date january 1st again. /// /// Now, we get the answer of the Gregorian year. /// /// The next step is to get the number of days between the requested Hebrew month/day /// and [hebrewDateForJan1]. When we get that, we can create the DateTime by adding/subtracting /// the ticks value of the number of days. /// </summary> private static DateTime HebrewToGregorian(int hebrewYear, int hebrewMonth, int hebrewDay, int hour, int minute, int second, int millisecond) { // Get the rough Gregorian year for the specified hebrewYear. int gregorianYear = hebrewYear - HebrewYearOf1AD; DateBuffer hebrewDateOfJan1 = new DateBuffer(); // year value is unused. int lunarYearType = GetLunarMonthDay(gregorianYear, hebrewDateOfJan1); if ((hebrewMonth == hebrewDateOfJan1.month) && (hebrewDay == hebrewDateOfJan1.day)) { return(new DateTime(gregorianYear, 1, 1, hour, minute, second, millisecond)); } int days = GetDayDifference(lunarYearType, hebrewMonth, hebrewDay, hebrewDateOfJan1.month, hebrewDateOfJan1.day); DateTime gregorianNewYear = new DateTime(gregorianYear, 1, 1); return(new DateTime(gregorianNewYear.Ticks + days * TicksPerDay + TimeToTicks(hour, minute, second, millisecond))); }
/// <summary> /// Returns a given date part of this DateTime. This method is used /// to compute the year, day-of-year, month, or day part. /// </summary> internal virtual int GetDatePart(long ticks, int part) { // The Gregorian year, month, day value for ticks. int gregorianYear, gregorianMonth, gregorianDay; int hebrewYearType; // lunar year type long AbsoluteDate; // absolute date - absolute date 1/1/1600 // Make sure we have a valid Gregorian date that will fit into our // Hebrew conversion limits. CheckTicksRange(ticks); DateTime time = new DateTime(ticks); // Save the Gregorian date values. time.GetDatePart(out gregorianYear, out gregorianMonth, out gregorianDay); DateBuffer lunarDate = new DateBuffer(); // lunar month and day for Jan 1 // From the table looking-up value of HebrewTable[index] (stored in lunarDate.day), we get the // lunar month and lunar day where the Gregorian date 1/1 falls. lunarDate.year = gregorianYear + HebrewYearOf1AD; hebrewYearType = GetLunarMonthDay(gregorianYear, lunarDate); // This is the buffer used to store the result Hebrew date. DateBuffer result = new DateBuffer(); // Store the values for the start of the new year - 1/1. result.year = lunarDate.year; result.month = lunarDate.month; result.day = lunarDate.day; // Get the absolute date from 1/1/1600. AbsoluteDate = GregorianCalendar.GetAbsoluteDate(gregorianYear, gregorianMonth, gregorianDay); // If the requested date was 1/1, then we're done. if ((gregorianMonth == 1) && (gregorianDay == 1)) { return(GetResult(result, part)); } // Calculate the number of days between 1/1 and the requested date. long numDays = AbsoluteDate - GregorianCalendar.GetAbsoluteDate(gregorianYear, 1, 1); // If the requested date is within the current lunar month, then // we're done. if ((numDays + (long)lunarDate.day) <= (long)(s_lunarMonthLen[hebrewYearType * MaxMonthPlusOne + lunarDate.month])) { result.day += (int)numDays; return(GetResult(result, part)); } // Adjust for the current partial month. result.month++; result.day = 1; // Adjust the Lunar Month and Year (if necessary) based on the number // of days between 1/1 and the requested date. // Assumes Jan 1 can never translate to the last Lunar month, which // is true. numDays -= (long)(s_lunarMonthLen[hebrewYearType * MaxMonthPlusOne + lunarDate.month] - lunarDate.day); Debug.Assert(numDays >= 1, "NumDays >= 1"); // If NumDays is 1, then we are done. Otherwise, find the correct Hebrew month // and day. if (numDays > 1) { // See if we're on the correct Lunar month. while (numDays > (long)(s_lunarMonthLen[hebrewYearType * MaxMonthPlusOne + result.month])) { // Adjust the number of days and move to the next month. numDays -= (long)(s_lunarMonthLen[hebrewYearType * MaxMonthPlusOne + result.month++]); // See if we need to adjust the Year. // Must handle both 12 and 13 month years. if ((result.month > 13) || (s_lunarMonthLen[hebrewYearType * MaxMonthPlusOne + result.month] == 0)) { // Adjust the Year. result.year++; hebrewYearType = s_hebrewTable[(gregorianYear + 1 - FirstGregorianTableYear) * 2 + 1]; // Adjust the Month. result.month = 1; } } // Found the right Lunar month. result.day += (int)(numDays - 1); } return(GetResult(result, part)); }