internal override LocalInstant SetYear(LocalInstant localInstant, int year) { int thisYear = GetYear(localInstant); int dayOfYear = GetDayOfYear(localInstant, thisYear); long tickOfDay = TimeOfDayCalculator.GetTickOfDay(localInstant); if (dayOfYear > (31 + 28)) { // after Feb 28 if (IsLeapYear(thisYear)) { // Current date is Feb 29 or later. if (!IsLeapYear(year)) { // Moving to a non-leap year, Feb 29 does not exist. dayOfYear--; } } else { // Current date is Mar 01 or later. if (IsLeapYear(year)) { // Moving to a leap year, account for Feb 29. dayOfYear++; } } } long ticks = GetYearMonthDayTicks(year, 1, dayOfYear); return(new LocalInstant(ticks + tickOfDay)); }
override internal LocalInstant AddMonths(LocalInstant localInstant, int months) { if (months == 0) { return(localInstant); } // Save the time part first long timePart = TimeOfDayCalculator.GetTickOfDay(localInstant); // Get the year and month int thisYear = GetYear(localInstant); int thisMonth = GetMonthOfYear(localInstant, thisYear); // Do not refactor without careful consideration. // Order of calculation is important. int yearToUse; // Initially, monthToUse is zero-based int monthToUse = thisMonth - 1 + months; if (monthToUse >= 0) { yearToUse = thisYear + (monthToUse / monthsInYear); monthToUse = (monthToUse % monthsInYear) + 1; } else { yearToUse = thisYear + (monthToUse / monthsInYear) - 1; monthToUse = Math.Abs(monthToUse); int remMonthToUse = monthToUse % monthsInYear; // Take care of the boundary condition if (remMonthToUse == 0) { remMonthToUse = monthsInYear; } monthToUse = monthsInYear - remMonthToUse + 1; // Take care of the boundary condition if (monthToUse == 1) { yearToUse++; } } // End of do not refactor. // Quietly force DOM to nearest sane value. int dayToUse = GetDayOfMonth(localInstant, thisYear, thisMonth); int maxDay = GetDaysInMonth(yearToUse, monthToUse); dayToUse = Math.Min(dayToUse, maxDay); // Get proper date part, and return result long datePart = GetYearMonthDayTicks(yearToUse, monthToUse, dayToUse); return(new LocalInstant(datePart + timePart)); }
internal override LocalInstant AddMonths(LocalInstant localInstant, int months) { // Note: this method gives the same result regardless of the month numbering used // by the instance. The method works in terms of civil month numbers for most of // the time in order to simplify the logic. if (months == 0) { return(localInstant); } long tickOfDay = TimeOfDayCalculator.GetTickOfDay(localInstant); var startDate = HebrewScripturalCalculator.HebrewFromAbsolute(AbsoluteDayFromLocalInstant(localInstant)); int year = startDate.Year; int month = HebrewMonthConverter.ScripturalToCivil(year, startDate.Month); // This arithmetic works the same both backwards and forwards. year += (months / MonthsPerLeapCycle) * YearsPerLeapCycle; months = months % MonthsPerLeapCycle; if (months > 0) { // Add as many months as we need to in order to act as if we'd begun at the start // of the year, for simplicity. months += month - 1; // Add a year at a time while (months >= GetMaxMonth(year)) { months -= GetMaxMonth(year); year++; } // However many months we've got left to add tells us the final month. month = months + 1; } else { // Pretend we were given the month at the end of the years. months -= GetMaxMonth(year) - month; // Subtract a year at a time while (months + GetMaxMonth(year) <= 0) { months += GetMaxMonth(year); year--; } // However many months we've got left to add (which will still be negative...) // tells us the final month. month = GetMaxMonth(year) + months; } // Convert back to scriptural for the last bit month = HebrewMonthConverter.CivilToScriptural(year, month); int day = Math.Min(HebrewScripturalCalculator.DaysInMonth(year, month), startDate.Day); int absoluteDay = HebrewScripturalCalculator.AbsoluteFromHebrew(year, month, day); return(LocalInstantFromAbsoluteDay(absoluteDay, tickOfDay)); }
internal override LocalInstant SetYear(LocalInstant localInstant, int year) { // Optimized implementation of SetYear, due to fixed months. int thisYear = GetYear(localInstant); int dayOfYear = GetDayOfYear(localInstant, thisYear); // Truncate final day of leap year. if (dayOfYear == DaysPerLeapYear && !IsLeapYear(year)) { dayOfYear--; } long tickOfDay = TimeOfDayCalculator.GetTickOfDay(localInstant); return(new LocalInstant(GetYearTicks(year) + ((dayOfYear - 1) * NodaConstants.TicksPerStandardDay) + tickOfDay)); }
internal override LocalInstant SetYear(LocalInstant localInstant, int year) { // Optimized implementation of set, due to fixed months int thisYear = GetYear(localInstant); int dayOfYear = GetDayOfYear(localInstant, thisYear); long tickOfDay = TimeOfDayCalculator.GetTickOfDay(localInstant); if (dayOfYear > 365) { // Current year is leap, and day is leap. if (!IsLeapYear(year)) { // Moving to a non-leap year, leap day doesn't exist. dayOfYear--; } } long ticks = GetYearTicks(year) + (dayOfYear - 1) * NodaConstants.TicksPerStandardDay + tickOfDay; return(new LocalInstant(ticks)); }
/// <summary> /// Change the year, maintaining month and day as well as possible. This doesn't /// work in the same way as other calendars; see http://judaism.stackexchange.com/questions/39053 /// for the reasoning behind the rules. /// </summary> internal override LocalInstant SetYear(LocalInstant localInstant, int year) { long tickOfDay = TimeOfDayCalculator.GetTickOfDay(localInstant); int absoluteSourceDay = AbsoluteDayFromLocalInstant(localInstant); YearMonthDay ymd = HebrewScripturalCalculator.HebrewFromAbsolute(absoluteSourceDay); int targetDay = ymd.Day; int targetScripturalMonth = ymd.Month; if (targetScripturalMonth == 13 && !IsLeapYear(year)) { // If we were in Adar II and the target year is not a leap year, map to Adar. targetScripturalMonth = 12; } else if (targetScripturalMonth == 12 && IsLeapYear(year) && !IsLeapYear(ymd.Year)) { // If we were in Adar (non-leap year), go to Adar II rather than Adar I in a leap year. targetScripturalMonth = 13; } // If we're aiming for the 30th day of Heshvan, Kislev or an Adar, it's possible that the change in year // has meant the day becomes invalid. In that case, roll over to the 1st of the subsequent month. if (targetDay == 30 && (targetScripturalMonth == 8 || targetScripturalMonth == 9 || targetScripturalMonth == 12)) { if (HebrewScripturalCalculator.DaysInMonth(year, targetScripturalMonth) != 30) { targetDay = 1; targetScripturalMonth++; // From Adar, roll to Nisan. if (targetScripturalMonth == 13) { targetScripturalMonth = 1; } } } int absoluteTargetDay = HebrewScripturalCalculator.AbsoluteFromHebrew(year, targetScripturalMonth, targetDay); return(LocalInstantFromAbsoluteDay(absoluteTargetDay, tickOfDay)); }