Esempio n. 1
0
        /* Analysation of algorithm of Hồ Ngọc Đức
         * ---------------------------------------
         * double off = LocalToJD(31, 12, Y) - 2415021.076998695;
         *              ^ returns Julian Date of 31st December #Year, 00:00:00 UTC+7
         *                    i.e. 30th December #Year, 17:00:00 UTC
         * int k = INT(off / 29.530588853);
         * double jd = NewMoon(k);
         *             ^ returns the new moon date *time* in Julian Dater, *UTC*
         * int[] ret = LocalFromJD(jd);
         *             ^ converts (jd + timezone/24) back to Calendar Date,
         *                   disregrading the time (i.e. the begining of day in local time zone
         *                   [00:00:00 local] that contains the new moon.)
         *
         * // sun longitude at local midnight
         * double sunLong = SunLongitude(LocalToJD(ret[0], ret[1], ret[2]));
         * if (sunLong > 3 * PI / 2)
         * {
         *     jd = NewMoon(k - 1);
         * }
         * return LocalFromJD(jd);
         * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         * e.g.:
         *       NewMoon(1236) = 2451520.4393767994
         *                     = 7/12/1999 10:32:42 UTC
         *                     = 8/12/1999 17:32:42 UTC+7, thus,
         *
         *  [ Note: UniversalFromJD(2451520.4393767994) = (7, 12, 1999) ]
         *              LocalFromJD(2451520.4393767994) =
         *    UniversalFromJD(JD + LOCAL_TIMEZONE/24.0) = (8, 12, 1999)
         *
         *                       LocalToJD(8, 12, 1999) =
         * UniversalToJD(D, M, Y) - LOCAL_TIMEZONE/24.0 = 8/12/1999 00:00:00 - 7
         * ^                        ^                   = 7/12/1999 17:00:00 UTC <---+
         * |                        +---[ Shift back to local midnight ]             |
         * +---[ Julius Date of D/M/Y 00:00:00 UTC (midnight), 8/12/1999 00:00:00]   |
         *                   [ This value is used to determine the sun longitude ]---+
         */

        /// <summary>
        /// Returns the local date time of the new moon just before
        /// the winter solstice in the given lunar year.
        /// </summary>
        /// <param name="lunarYear"></param>
        /// <param name="timeZone"></param>
        /// <returns></returns>
        public static DateTime GetNewMoon11(int lunarYear, double timeZone)
        {
            // number of days from J1900 to local midnight of 31st December #Year
            // (lunarYear, 12, 31): local
            // (lunarYear, 12, 31, timeZone): universal
            var offset = JulianDateConverter.UniversalDateTimeToJulianDate(lunarYear, 12, 31, timeZone) - Constants.J1900;

            var k = (int)(offset / Constants.SynodicMonth);

            // local date & *time* of new moon
            var newMoonLocalDateTime = JulianDateConverter.JulianDateToUniversalDateTime(GetNewMoon(k)).AddHours(timeZone);
            // beginning of that day (i.e. midnight, i.e. strip off the time)
            var newMoonMidnightLocal = newMoonLocalDateTime.Date;
            // Julian Date at the beginning of that day
            var julianDate =
                newMoonMidnightLocal.AddHours(-timeZone).UniversalDateTimeToJulianDate();

            var sunLongitude = Sun.GetSunLongitudeAtJulianDate(julianDate);

            // Check the winter solstice is after the beginning of that day:
            // If the winter soltice is *before* the beginning of that day,
            //     the previous new moon is the new moon just before winter solstice,
            // else the current new moon is the new moon just before winter solstice.
            if (sunLongitude > (3 * Math.PI / 2))
            {
                newMoonLocalDateTime = JulianDateConverter.JulianDateToUniversalDateTime(GetNewMoon(k - 1)).AddHours(timeZone);
            }

            return(newMoonLocalDateTime);
        }
Esempio n. 2
0
        public static DateTime GetDateTimeOfSolarTerm(int termIndex, int year)
        {
            int[] trialMonths =
            { 3,       4,  4,  5,  5,  6,
              6,   7,  7,  8,  8,  9,
              9,  10, 10, 11, 11, 12,
              12,  1,  1,  2,  2, 3 };
            int[] trialDays =
            { 21,     5, 20, 6, 21, 6,
              21, 7, 23, 7, 23, 8,
              23, 8, 23, 7, 22, 7,
              22, 6, 21, 4, 19, 5 };

            double desiredSunLong = termIndex * (Math.PI / 12);

            DateTime estimatedDateTime = new DateTime(year, trialMonths[termIndex], trialDays[termIndex]);
            double   currentSunLong    = Sun.GetSunLongitudeAtJulianDate(
                estimatedDateTime.UniversalDateTimeToJulianDate());

            currentSunLong = Sun.GetSunLongitudeAtJulianDate(
                estimatedDateTime.UniversalDateTimeToJulianDate());

            var error     = (currentSunLong - desiredSunLong).ToNormalizedArc();
            var direction = 1;

            if (error > Math.PI)
            {
                direction = -1;
            }

            double resolution      = 1; // days
            double previousSunLong = currentSunLong;
            var    count           = 0;

            do
            {
                estimatedDateTime = estimatedDateTime.AddDays(resolution * direction);
                currentSunLong    = Sun.GetSunLongitudeAtJulianDate(estimatedDateTime.UniversalDateTimeToJulianDate());

                double error1 = (currentSunLong - desiredSunLong).ToNormalizedArc();
                double error2 = (desiredSunLong + 2 * Math.PI - currentSunLong).ToNormalizedArc();

                if (error1 > error && error2 > error)
                {
                    direction  = direction * (-1);
                    resolution = resolution / 2;
                }

                error = error1;
                if (error2 > error1)
                {
                    error = error1;
                }
                else
                {
                    error = error2;
                }

                count++;
            } while (resolution > (1f / 86400) && Math.Abs(error) > 0.00001);

            return(estimatedDateTime);
        }