// ------------------------------------------------------------------
        // Fields to time
        // ------------------------------------------------------------------

        /// <summary>
        /// Return the Chinese new year of the given Gregorian year.
        /// </summary>
        ///
        /// <param name="gyear">a Gregorian year</param>
        /// <returns>days after January 1, 1970 0:00 Asia/Shanghai of the Chinese new
        /// year of the given year (this will be a new moon)</returns>
        private int NewYear(int gyear)
        {
            long cacheValue = newYearCache.Get(gyear);

            if (cacheValue == IBM.ICU.Impl.CalendarCache.EMPTY)
            {
                int solsticeBefore = WinterSolstice(gyear - 1);
                int solsticeAfter  = WinterSolstice(gyear);
                int newMoon1       = NewMoonNear(solsticeBefore + 1, true);
                int newMoon2       = NewMoonNear(newMoon1 + SYNODIC_GAP, true);
                int newMoon11      = NewMoonNear(solsticeAfter + 1, false);

                if (SynodicMonthsBetween(newMoon1, newMoon11) == 12 &&
                    (HasNoMajorSolarTerm(newMoon1) || HasNoMajorSolarTerm(newMoon2)))
                {
                    cacheValue = NewMoonNear(newMoon2 + SYNODIC_GAP, true);
                }
                else
                {
                    cacheValue = newMoon2;
                }

                newYearCache.Put(gyear, cacheValue);
            }
            return((int)cacheValue);
        }
Example #2
0
        /// <summary>
        /// Finds the day # of the first day in the given Hebrew year. To do this, we
        /// want to calculate the time of the Tishri 1 new moon in that year.
        /// <p>
        /// The algorithm here is similar to ones described in a number of
        /// references, including:
        /// <ul>
        /// <li>"Calendrical Calculations", by Nachum Dershowitz & Edward Reingold,
        /// Cambridge University Press, 1997, pages 85-91.
        /// <li>Hebrew Calendar Science and Myths, <a
        /// href="http://www.geocities.com/Athens/1584/">
        /// http://www.geocities.com/Athens/1584/</a>
        /// <li>The Calendar FAQ, <a href="http://www.faqs.org/faqs/calendars/faq/">
        /// http://www.faqs.org/faqs/calendars/faq/</a>
        /// </ul>
        /// </summary>
        ///
        private static long StartOfYear(int year)
        {
            long day = cache.Get(year);

            if (day == IBM.ICU.Impl.CalendarCache.EMPTY)
            {
                int months = (235 * year - 234) / 19;       // # of months before year

                long frac = months * MONTH_FRACT + BAHARAD; // Fractional part of
                                                            // day #
                day = months * 29 + (frac / DAY_PARTS);     // Whole # part of
                                                            // calculation
                frac = frac % DAY_PARTS;                    // Time of day

                int wd = (int)(day % 7);                    // Day of week (0 == Monday)

                if (wd == 2 || wd == 4 || wd == 6)
                {
                    // If the 1st is on Sun, Wed, or Fri, postpone to the next day
                    day += 1;
                    wd   = (int)(day % 7);
                }
                if (wd == 1 && frac > 15 * HOUR_PARTS + 204 && !IsLeapYear(year))
                {
                    // If the new moon falls after 3:11:20am (15h204p from the
                    // previous noon)
                    // on a Tuesday and it is not a leap year, postpone by 2 days.
                    // This prevents 356-day years.
                    day += 2;
                }
                else if (wd == 0 && frac > 21 * HOUR_PARTS + 589 &&
                         IsLeapYear(year - 1))
                {
                    // If the new moon falls after 9:32:43 1/3am (21h589p from
                    // yesterday noon)
                    // on a Monday and *last* year was a leap year, postpone by 1
                    // day.
                    // Prevents 382-day years.
                    day += 1;
                }
                cache.Put(year, day);
            }
            return(day);
        }
        // ------------------------------------------------------------------
        // Astronomical computations
        // ------------------------------------------------------------------

        /// <summary>
        /// Return the major solar term on or after December 15 of the given
        /// Gregorian year, that is, the winter solstice of the given year.
        /// Computations are relative to Asia/Shanghai time zone.
        /// </summary>
        ///
        /// <param name="gyear">a Gregorian year</param>
        /// <returns>days after January 1, 1970 0:00 Asia/Shanghai of the winter
        /// solstice of the given year</returns>
        private int WinterSolstice(int gyear)
        {
            long cacheValue = winterSolsticeCache.Get(gyear);

            if (cacheValue == IBM.ICU.Impl.CalendarCache.EMPTY)
            {
                // In books December 15 is used, but it fails for some years
                // using our algorithms, e.g.: 1298 1391 1492 1553 1560. That
                // is, winterSolstice(1298) starts search at Dec 14 08:00:00
                // PST 1298 with a final result of Dec 14 10:31:59 PST 1299.
                long ms = DaysToMillis(ComputeGregorianMonthStart(gyear, IBM.ICU.Util.Calendar.DECEMBER)
                                       + 1 - IBM.ICU.Util.Calendar.EPOCH_JULIAN_DAY);
                astro.SetTime(ms);

                // Winter solstice is 270 degrees solar longitude aka Dongzhi
                long solarLong = astro.GetSunTime(
                    IBM.ICU.Impl.CalendarAstronomer.WINTER_SOLSTICE, true);
                cacheValue = MillisToDays(solarLong);
                winterSolsticeCache.Put(gyear, cacheValue);
            }
            return((int)cacheValue);
        }