CSharp: SunTimeCalculator
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace GeovinDu.Ticket.Common { /// <summary> /// /// </summary> public static class DateTimeJavaScriptExt { /// <summary> /// Based on a JavaScript library SunCalc for calculating sun/moon position and light phases. ///https://github.com/mourner/suncalc /// </summary> /// <param name="dt"></param> /// <returns></returns> public static double ValueOf(this DateTime dt) // JavaScript Date.valueOf() { dt = dt.Kind == DateTimeKind.Local ? dt.ToUniversalTime() : dt; return (dt - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds; } /// <summary> /// /// </summary> /// <param name="dt"></param> /// <param name="ms"></param> /// <returns></returns> public static DateTime FromJScriptValue(this DateTime dt, double ms) { return new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds(ms); } } /// <summary> /// 计算日出日落时间,月升月落时间 /// /// </summary> public class SunTimeCalculator { #region 辅助函数 /// <summary> /// 历元2000.0,即以2000年第一天开端为计日起始(天文学以第一天为0日而非1日)。 /// 它与UT(就是世界时,格林尼治平均太阳时)1999年末重合。 /// </summary> /// <param name="y"></param> /// <param name="m"></param> /// <param name="d"></param> /// <returns></returns> private static long Days_since_2000_Jan_0(int y, int m, int d) { return (367L * (y) - ((7 * ((y) + (((m) + 9) / 12))) / 4) + ((275 * (m)) / 9) + (d) - 730530L); } /// <summary> /// /// </summary> /// <param name="x"></param> /// <returns></returns> private static double Revolution(double x) { return (x - 360.0 * Math.Floor(x * Inv360)); } /// <summary> /// /// </summary> /// <param name="x"></param> /// <returns></returns> private static double Rev180(double x) { return (x - 360.0 * Math.Floor(x * Inv360 + 0.5)); } /// <summary> /// /// </summary> /// <param name="d"></param> /// <returns></returns> private static double GMST0(double d) { double sidtim0; sidtim0 = Revolution((180.0 + 356.0470 + 282.9404) + (0.9856002585 + 4.70935E-5) * d); return sidtim0; } /// <summary> /// /// </summary> private static double Inv360 = 1.0 / 360.0; #endregion #region 度与弧度转换系数,为球面三角计算作准备 /// <summary> /// /// </summary> /// <param name="x"></param> /// <returns></returns> private static double Sind(double x) { return Math.Sin(x * Degrad); } /// <summary> /// /// </summary> /// <param name="x"></param> /// <returns></returns> private static double Cosd(double x) { return Math.Cos(x * Degrad); } /// <summary> /// /// </summary> /// <param name="x"></param> /// <returns></returns> private static double Tand(double x) { return Math.Tan(x * Degrad); } /// <summary> /// /// </summary> /// <param name="x"></param> /// <returns></returns> private static double Atand(double x) { return Radge * Math.Atan(x); } /// <summary> /// /// </summary> /// <param name="x"></param> /// <returns></returns> private static double Asind(double x) { return Radge * Math.Asin(x); } /// <summary> /// /// </summary> /// <param name="x"></param> /// <returns></returns> private static double Acosd(double x) { return Radge * Math.Acos(x); } /// <summary> /// /// </summary> /// <param name="y"></param> /// <param name="x"></param> /// <returns></returns> private static double Atan2d(double y, double x) { return Radge * Math.Atan2(y, x); } /// <summary> /// /// </summary> private static double Radge = 180.0 / Math.PI; /// <summary> /// /// </summary> private static double Degrad = Math.PI / 180.0; #endregion #region 与日出日落时间相关计算 /// <summary> /// /// </summary> /// <param name="year"></param> /// <param name="month"></param> /// <param name="day"></param> /// <param name="lon"></param> /// <param name="lat"></param> /// <param name="altit"></param> /// <param name="upper_limb"></param> /// <returns></returns> private static double DayLen(int year, int month, int day, double lon, double lat, double altit, int upper_limb) { double d, /* Days since 2000 Jan 0.0 (negative before) */ obl_ecl, /* Obliquity (inclination) of Earth's axis */ //黄赤交角,在2000.0历元下国际规定为23度26分21.448秒,但有很小的时间演化。 sr, /* Solar distance, astronomical units */ slon, /* True solar longitude */ sin_sdecl, /* Sine of Sun's declination */ //太阳赤纬的正弦值。 cos_sdecl, /* Cosine of Sun's declination */ sradius, /* Sun's apparent radius */ t; /* Diurnal arc */ /* Compute d of 12h local mean solar time */ d = Days_since_2000_Jan_0(year, month, day) + 0.5 - lon / 360.0; /* Compute obliquity of ecliptic (inclination of Earth's axis) */ obl_ecl = 23.4393 - 3.563E-7 * d; //这个黄赤交角时变公式来历复杂,很大程度是经验性的,不必追究。 /* Compute Sun's position */ slon = 0.0; sr = 0.0; Sunpos(d, ref slon, ref sr); /* Compute sine and cosine of Sun's declination */ sin_sdecl = Sind(obl_ecl) * Sind(slon); cos_sdecl = Math.Sqrt(1.0 - sin_sdecl * sin_sdecl); //用球面三角学公式计算太阳赤纬。 /* Compute the Sun's apparent radius, degrees */ sradius = 0.2666 / sr; //视半径,同前。 /* Do correction to upper limb, if necessary */ if (upper_limb != 0) altit -= sradius; /* Compute the diurnal arc that the Sun traverses to reach */ /* the specified altitide altit: */ //根据设定的地平高度判据计算周日弧长。 double cost; cost = (Sind(altit) - Sind(lat) * sin_sdecl) / (Cosd(lat) * cos_sdecl); if (cost >= 1.0) t = 0.0; /* Sun always below altit */ //极夜。 else if (cost <= -1.0) t = 24.0; /* Sun always above altit */ //极昼。 else t = (2.0 / 15.0) * Acosd(cost); /* The diurnal arc, hours */ //周日弧换算成小时计。 return t; } /// <summary> /// /// </summary> /// <param name="d"></param> /// <param name="lon"></param> /// <param name="r"></param> private static void Sunpos(double d, ref double lon, ref double r) { double M,//太阳的平均近点角,从太阳观察到的地球(=从地球看到太阳的)距近日点(近地点)的角度。 w, //近日点的平均黄道经度。 e, //地球椭圆公转轨道离心率。 E, //太阳的偏近点角。计算公式见下面。 x, y, v; //真近点角,太阳在任意时刻的真实近点角。 M = Revolution(356.0470 + 0.9856002585 * d);//自变量的组成:2000.0时刻太阳黄经为356.0470度,此后每天约推进一度(360度/365天 w = 282.9404 + 4.70935E-5 * d;//近日点的平均黄经。 e = 0.016709 - 1.151E-9 * d;//地球公转椭圆轨道离心率的时间演化。以上公式和黄赤交角公式一样,不必深究。 E = M + e * Radge * Sind(M) * (1.0 + e * Cosd(M)); x = Cosd(E) - e; y = Math.Sqrt(1.0 - e * e) * Sind(E); r = Math.Sqrt(x * x + y * y); v = Atan2d(y, x); lon = v + w; if (lon >= 360.0) lon -= 360.0; } /// <summary> /// /// </summary> /// <param name="d"></param> /// <param name="RA"></param> /// <param name="dec"></param> /// <param name="r"></param> private static void Sun_RA_dec(double d, ref double RA, ref double dec, ref double r) { double lon, obl_ecl, x, y, z; lon = 0.0; Sunpos(d, ref lon, ref r); //计算太阳的黄道坐标。 x = r * Cosd(lon); y = r * Sind(lon); //计算太阳的直角坐标。 obl_ecl = 23.4393 - 3.563E-7 * d; //黄赤交角,同前。 z = y * Sind(obl_ecl); y = y * Cosd(obl_ecl); //把太阳的黄道坐标转换成赤道坐标(暂改用直角坐标)。 RA = Atan2d(y, x); dec = Atan2d(z, Math.Sqrt(x * x + y * y)); //最后转成赤道坐标。显然太阳的位置是由黄道坐标方便地直接确定的,但必须转换到赤 //道坐标里才能结合地球的自转确定我们需要的白昼长度。 } /// <summary> /// 日出没时刻计算 /// </summary> /// <param name="year">年</param> /// <param name="month">月</param> /// <param name="day">日</param> /// <param name="lon">经度</param> /// <param name="lat">纬度</param> /// <param name="altit"></param> /// <param name="upper_limb"></param> /// <param name="trise">日出时刻</param> /// <param name="tset">日没时刻</param> /// <returns>太阳有出没现象,返回0 极昼,返回+1 极夜,返回-1</returns> private static int SunRiset(int year, int month, int day, double lon, double lat, double altit, int upper_limb, ref double trise, ref double tset) { double d, /* Days since 2000 Jan 0.0 (negative before) */ //以历元2000.0起算的日数。 sr, /* Solar distance, astronomical units */ //太阳距离,以天文单位计算(约1.5亿公里)。 sRA, /* Sun's Right Ascension */ //同前,太阳赤经。 sdec, /* Sun's declination */ //太阳赤纬。 sradius, /* Sun's apparent radius */ //太阳视半径,约16分(受日地距离、大气折射等诸多影响) t, /* Diurnal arc */ //周日弧,太阳一天在天上走过的弧长。 tsouth, /* Time when Sun is at south */ sidtime; /* Local sidereal time */ //当地恒星时,即地球的真实自转周期。比平均太阳日(日常时间)长3分56秒。 int rc = 0; /* Return cde from function - usually 0 */ /* Compute d of 12h local mean solar time */ d = Days_since_2000_Jan_0(year, month, day) + 0.5 - lon / 360.0; //计算观测地当日中午时刻对应2000.0起算的日数。 /* Compute local sideral time of this moment */ sidtime = Revolution(GMST0(d) + 180.0 + lon); //计算同时刻的当地恒星时(以角度为单位)。以格林尼治为基准,用经度差校正。 /* Compute Sun's RA + Decl at this moment */ sRA = 0.0; sdec = 0.0; sr = 0.0; Sun_RA_dec(d, ref sRA, ref sdec, ref sr); //计算同时刻太阳赤经赤纬。 /* Compute time when Sun is at south - in hours UT */ tsouth = 12.0 - Rev180(sidtime - sRA) / 15.0; //计算太阳日的正午时刻,以世界时(格林尼治平太阳时)的小时计。 /* Compute the Sun's apparent radius, degrees */ sradius = 0.2666 / sr; //太阳视半径。0.2666是一天文单位处的太阳视半径(角度)。 /* Do correction to upper limb, if necessary */ if (upper_limb != 0) altit -= sradius; //如果要用上边缘,就要扣除一个视半径。 /* Compute the diurnal arc that the Sun traverses to reach */ //计算周日弧。直接利用球面三角公式。如果碰到极昼极夜问题,同前处理。 /* the specified altitide altit: */ double cost; cost = (Sind(altit) - Sind(lat) * Sind(sdec)) / (Cosd(lat) * Cosd(sdec)); if (cost >= 1.0) { rc = -1; t = 0.0; } else { if (cost <= -1.0) { rc = +1; t = 12.0; /* Sun always above altit */ } else t = Acosd(cost) / 15.0; /* The diurnal arc, hours */ } /* Store rise and set times - in hours UT */ trise = tsouth - t; tset = tsouth + t; return rc; } #endregion /// <summary> /// 计算日出日没时间 /// </summary> /// <param name="date"></param> /// <param name="longitude">经度</param> /// <param name="latitude">纬度</param> /// <returns></returns> public static SunTimeResult GetSunTime(DateTime date, double longitude, double latitude) { double start = 0; double end = 0; SunRiset(date.Year, date.Month, date.Day, longitude, latitude, -35.0 / 60.0, 1, ref start, ref end); DateTime sunrise = ToLocalTime(date, start); DateTime sunset = ToLocalTime(date, end); return new SunTimeResult(sunrise, sunset); } #region moon 月亮计算 private const double dayMs = 86400000; private const double J1970 = 2440588; private const double J2000 = 2451545; private const double PI = Math.PI; private const double rad = Math.PI / 180.0; private const double e = rad * 23.4397; // obliquity of the Earth /// <summary> /// /// </summary> public class SunTime { public double Angle { get; set; } public string MorningName { get; set; } public string EveningName { get; set; } } /// <summary> /// /// </summary> public class SunTimeRiseSet : SunTime { public DateTime RiseTime { get; set; } public DateTime SetTime { get; set; } } /// <summary> /// sun times configuration (angle, morning name, evening name) /// </summary> public static List<SunTime> SunTimes = new List<SunTime>(new SunTime[] { new SunTime { Angle = -0.833, MorningName = "sunrise", EveningName = "sunset" }, new SunTime { Angle = -0.3, MorningName = "sunriseEnd", EveningName = "sunsetStart" }, new SunTime { Angle = -6, MorningName = "dawn", EveningName = "dusk" }, new SunTime { Angle = -12, MorningName = "nauticalDawn", EveningName = "nauticalDusk" }, new SunTime { Angle = -18, MorningName = "nightEnd", EveningName = "night" }, new SunTime { Angle = 6, MorningName = "goldenHourEnd", EveningName = "goldenHour" } }); /// <summary> /// adds a custom time to the times config /// </summary> /// <param name="sunTime"></param> public static void AddTime(SunTime sunTime) { SunTimes.Add(sunTime); } /// <summary> /// /// </summary> public class RaDec { public double ra = 0; public double dec = 0; } /// <summary> /// /// </summary> /// <param name="dt"></param> /// <returns></returns> public static double ToJulianDate(DateTime dt) { dt = dt.Kind == DateTimeKind.Local ? dt.ToUniversalTime() : dt; return (dt - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds / dayMs - 0.5 + J1970; } /// <summary> /// /// </summary> /// <param name="jd"></param> /// <returns></returns> public static DateTime FromJulianDate(double jd) { return double.IsNaN(jd) ? DateTime.MinValue : new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds((jd + 0.5 - J1970) * dayMs); } /// <summary> /// /// </summary> /// <param name="dt"></param> /// <returns></returns> public static double JulianDays(DateTime dt) { dt = dt.Kind == DateTimeKind.Local ? dt.ToUniversalTime() : dt; return ToJulianDate(dt) - J2000; } /// <summary> /// /// </summary> /// <param name="l"></param> /// <param name="b"></param> /// <returns></returns> public static double RightAscension(double l, double b) { return Math.Atan2(Math.Sin(l) * Math.Cos(e) - Math.Tan(b) * Math.Sin(e), Math.Cos(l)); } public static double Declination(double l, double b) { return Math.Asin(Math.Sin(b) * Math.Cos(e) + Math.Cos(b) * Math.Sin(e) * Math.Sin(l)); } /// <summary> /// /// </summary> /// <param name="H"></param> /// <param name="phi"></param> /// <param name="dec"></param> /// <returns></returns> public static double Azimuth(double H, double phi, double dec) { return Math.Atan2(Math.Sin(H), Math.Cos(H) * Math.Sin(phi) - Math.Tan(dec) * Math.Cos(phi)); } /// <summary> /// /// </summary> /// <param name="H"></param> /// <param name="phi"></param> /// <param name="dec"></param> /// <returns></returns> public static double Altitude(double H, double phi, double dec) { return Math.Asin(Math.Sin(phi) * Math.Sin(dec) + Math.Cos(phi) * Math.Cos(dec) * Math.Cos(H)); } /// <summary> /// /// </summary> /// <param name="d"></param> /// <param name="lw"></param> /// <returns></returns> public static double SiderealTime(double d, double lw) { return rad * (280.16 + 360.9856235 * d) - lw; } /// <summary> /// /// </summary> /// <param name="h"></param> /// <returns></returns> public static double AstroRefraction(double h) { if (h < 0) // the following formula works for positive altitudes only. { h = 0; // if h = -0.08901179 a div/0 would occur. } // formula 16.4 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998. // 1.02 / tan(h + 10.26 / (h + 5.10)) h in degrees, result in arc minutes -> converted to rad: return 0.0002967 / Math.Tan(h + 0.00312536 / (h + 0.08901179)); } /// <summary> /// general sun calculations /// </summary> /// <param name="d"></param> /// <returns></returns> public static double SolarMeanAnomaly(double d) { return rad * (357.5291 + 0.98560028 * d); } /// <summary> /// /// </summary> /// <param name="dt"></param> /// <param name="h"></param> /// <returns></returns> public static DateTime HoursLater(DateTime dt, double h) { return new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds(dt.ValueOf() + h * dayMs / 24); //ValueOf } /// <summary> /// /// </summary> /// <param name="M"></param> /// <returns></returns> public static double EclipticLongitude(double M) { double C = rad * (1.9148 * Math.Sin(M) + 0.02 * Math.Sin(2 * M) + 0.0003 * Math.Sin(3 * M)); // equation of center double P = rad * 102.9372; // perihelion of the Earth return M + C + P + PI; } /// <summary> /// /// </summary> /// <param name="d"></param> /// <returns></returns> public static RaDec SunCoords(double d) { double M = SolarMeanAnomaly(d); double L = EclipticLongitude(M); return new RaDec { dec = Declination(L, 0), ra = RightAscension(L, 0) }; } /// <summary> /// /// </summary> public class MoonRaDecDist { public double ra = 0; public double dec = 0; public double dist = 0; } /// <summary> /// /// </summary> /// <param name="d"></param> /// <returns></returns> public static MoonRaDecDist MoonCoords(double d) // geocentric ecliptic coordinates of the moon { double L = rad * (218.316 + 13.176396 * d); // ecliptic longitude double M = rad * (134.963 + 13.064993 * d); // mean anomaly double F = rad * (93.272 + 13.229350 * d); // mean distance double l = L + rad * 6.289 * Math.Sin(M); // longitude double b = rad * 5.128 * Math.Sin(F); // latitude double dt = 385001 - 20905 * Math.Cos(M); // distance to the moon in km return new MoonRaDecDist { ra = RightAscension(l, b), dec = Declination(l, b), dist = dt }; } /// <summary> /// /// </summary> public class MoonAzAltDistPa { public double azimuth = 0; public double altitude = 0; public double distance = 0; public double parallacticAngle = 0; } /// <summary> /// /// </summary> public class MoonFracPhaseAngle { public double fraction = 0; public double phase = 0; public double angle = 0; } /// <summary> /// /// </summary> /// <param name="dt"></param> /// <param name="lat"></param> /// <param name="lng"></param> /// <returns></returns> public static MoonAzAltDistPa GetMoonPosition(DateTime dt, double lat, double lng) { double lw = rad * -lng; double phi = rad * lat; double d = JulianDays(dt); MoonRaDecDist c = MoonCoords(d); double H = SiderealTime(d, lw) - c.ra; double h = Altitude(H, phi, c.dec); // formula 14.1 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998. double pa = Math.Atan2(Math.Sin(H), Math.Tan(phi) * Math.Cos(c.dec) - Math.Sin(c.dec) * Math.Cos(H)); h += AstroRefraction(h); // altitude correction for refraction return new MoonAzAltDistPa { azimuth = Azimuth(H, phi, c.dec), altitude = h, distance = c.dist, parallacticAngle = pa }; } /// <summary> /// /// </summary> /// <param name="dt"></param> /// <returns></returns> public static MoonFracPhaseAngle GetMoonIllumination(DateTime dt) { double d = JulianDays(dt); RaDec s = SunCoords(d); MoonRaDecDist m = MoonCoords(d); double sdist = 149598000; // distance from Earth to Sun in km double phi = Math.Acos(Math.Sin(s.dec) * Math.Sin(m.dec) + Math.Cos(s.dec) * Math.Cos(m.dec) * Math.Cos(s.ra - m.ra)); double inc = Math.Atan2(sdist * Math.Sin(phi), m.dist - sdist * Math.Cos(phi)); double angle = Math.Atan2(Math.Cos(s.dec) * Math.Sin(s.ra - m.ra), Math.Sin(s.dec) * Math.Cos(m.dec) - Math.Cos(s.dec) * Math.Sin(m.dec) * Math.Cos(s.ra - m.ra)); return new MoonFracPhaseAngle { fraction = (1 + Math.Cos(inc)) / 2, phase = 0.5 + 0.5 * inc * (angle < 0 ? -1 : 1) / PI, angle = angle }; } /// <summary> /// DateTime.Max = always up, DateTime.Min = always down /// </summary> /// <param name="dt"></param> /// <param name="lat">纬度</param> /// <param name="lng">经度</param> /// <param name="risem"></param> /// <param name="setm"></param> /// <param name="alwaysUp"></param> /// <param name="alwaysDown"></param> public static void MoonRiset(DateTime dt, double lat, double lng, out DateTime risem, out DateTime setm, out bool? alwaysUp, out bool? alwaysDown) { dt = new DateTime(dt.Year, dt.Month, dt.Day, 0, 0, 0, DateTimeKind.Utc); DateTime t = dt; double hc = 0.133 * rad; double h0 = GetMoonPosition(t, lat, lng).altitude - hc; double h1, h2, rise = 0, set = 0, a, b, xe, ye = 0, d, x1, x2, dx; int roots; for (double i = 1.0; i <= 24.0; i += 2.0) { h1 = GetMoonPosition(HoursLater(t, i), lat, lng).altitude - hc; h2 = GetMoonPosition(HoursLater(t, i + 1), lat, lng).altitude - hc; a = (h0 + h2) / 2 - h1; b = (h2 - h0) / 2; xe = -b / (2 * a); ye = (a * xe + b) * xe + h1; d = b * b - 4 * a * h1; roots = 0; if (d >= 0) { dx = Math.Sqrt(d) / (Math.Abs(a) * 2); x1 = xe - dx; x2 = xe + dx; if (Math.Abs(x1) <= 1) { roots++; } if (Math.Abs(x2) <= 1) { roots++; } if (x1 < -1) { x1 = x2; } if (roots == 1) { if (h0 < 0) { rise = i + x1; } else { set = i + x1; } } else if (roots == 2) { rise = i + (ye < 0 ? x2 : x1); set = i + (ye < 0 ? x1 : x2); } if (rise > 0 && set > 0) { break; } h0 = h2; } } risem = DateTime.MinValue; setm = DateTime.MinValue; if (rise > 0) { risem = HoursLater(t, rise); } if (set > 0) { setm = HoursLater(t, set); } alwaysUp = null; alwaysDown = null; if (rise < 0 && set < 0) { if (ye > 0) { alwaysUp = true; alwaysDown = false; risem = DateTime.MaxValue; setm = DateTime.MaxValue; } else { alwaysDown = true; alwaysUp = false; } } } /// <summary> /// /// </summary> /// <param name="year"></param> /// <param name="month"></param> /// <param name="day"></param> /// <param name="lat">纬度</param> /// <param name="lng">经度</param> /// <param name="risem"></param> /// <param name="setm"></param> /// <param name="alwaysUp"></param> /// <param name="alwaysDown"></param> public static void MoonRisetInt(int year, int month, int day, double lat, double lng, out DateTime risem, out DateTime setm, out bool? alwaysUp, out bool? alwaysDown) { DateTime dt = new DateTime(year, month, day, 0, 0, 0, DateTimeKind.Utc); DateTime t = dt; double hc = 0.133 * rad; double h0 = GetMoonPosition(t, lat, lng).altitude - hc; double h1, h2, rise = 0, set = 0, a, b, xe, ye = 0, d, x1, x2, dx; int roots; for (double i = 1.0; i <= 24.0; i += 2.0) { h1 = GetMoonPosition(HoursLater(t, i), lat, lng).altitude - hc; h2 = GetMoonPosition(HoursLater(t, i + 1), lat, lng).altitude - hc; a = (h0 + h2) / 2 - h1; b = (h2 - h0) / 2; xe = -b / (2 * a); ye = (a * xe + b) * xe + h1; d = b * b - 4 * a * h1; roots = 0; if (d >= 0) { dx = Math.Sqrt(d) / (Math.Abs(a) * 2); x1 = xe - dx; x2 = xe + dx; if (Math.Abs(x1) <= 1) { roots++; } if (Math.Abs(x2) <= 1) { roots++; } if (x1 < -1) { x1 = x2; } if (roots == 1) { if (h0 < 0) { rise = i + x1; } else { set = i + x1; } } else if (roots == 2) { rise = i + (ye < 0 ? x2 : x1); set = i + (ye < 0 ? x1 : x2); } if (rise > 0 && set > 0) { break; } h0 = h2; } } risem = DateTime.MinValue; setm = DateTime.MinValue; if (rise > 0) { risem = HoursLater(t, rise); } if (set > 0) { setm = HoursLater(t, set); } alwaysUp = null; //false;// alwaysDown = null; //false;// if (rise < 0 && set < 0) { if (ye > 0) { alwaysUp = true; alwaysDown = false; risem = DateTime.MaxValue; setm = DateTime.MaxValue; } else { alwaysDown = true; alwaysUp = false; } } } #endregion /// <summary> /// 计算月亮升起和降落时间 /// </summary> /// <param name="date"></param> /// <param name="latitude">纬度</param> /// <param name="longitude">经度</param> /// <returns></returns> public static MoonTimeResult GetMoonTime(DateTime date, double latitude, double longitude) { double moonrise = 0; double moonset = 0; DateTime dt = new DateTime(date.Year, date.Month, date.Day, 0, 0, 0, DateTimeKind.Utc); bool? up = null; bool? down = null; DateTime rise; DateTime set; MoonRiset(dt, latitude, longitude, out rise, out set, out up, out down); //, out up, out down DateTime moonriseTime = rise;// ToLocalTime(rise, moonrise);// DateTime moonsetTime = set;//ToLocalTime(set, moonset); // return new MoonTimeResult(moonriseTime, moonsetTime); } /// <summary> /// 私有方法:将 UTC 时间转换为本地时间 /// </summary> /// <param name="time"></param> /// <param name="utTime"></param> /// <returns></returns> private static DateTime ToLocalTime(DateTime time, double utTime) { int hour = Convert.ToInt32(Math.Floor(utTime)); double temp = utTime - hour; hour += 8; // 转换为东8区北京时间 temp = temp * 60; int minute = Convert.ToInt32(Math.Floor(temp)); try { return new DateTime(time.Year, time.Month, time.Day, hour, minute, 0); } catch { return new DateTime(time.Year, time.Month, time.Day, 0, 0, 0); } } } /// <summary> /// 日出日落时间结果类 /// </summary> public class SunTimeResult { /// <summary> /// /// </summary> public DateTime SunriseTime { get; set; } /// <summary> /// /// </summary> public DateTime SunsetTime { get; set; } /// <summary> /// /// </summary> /// <param name="sunrise"></param> /// <param name="sunset"></param> public SunTimeResult(DateTime sunrise, DateTime sunset) { SunriseTime = sunrise; SunsetTime = sunset; } } /// <summary> /// 月亮升起和降落时间结果类 /// </summary> public class MoonTimeResult { /// <summary> /// /// </summary> public DateTime MoonriseTime { get; set; } /// <summary> /// /// </summary> public DateTime MoonsetTime { get; set; } /// <summary> /// /// </summary> /// <param name="moonrise"></param> /// <param name="moonset"></param> public MoonTimeResult(DateTime moonrise, DateTime moonset) { MoonriseTime = moonrise; MoonsetTime = moonset; } } }
哲学管理(学)人生, 文学艺术生活, 自动(计算机学)物理(学)工作, 生物(学)化学逆境, 历史(学)测绘(学)时间, 经济(学)数学金钱(理财), 心理(学)医学情绪, 诗词美容情感, 美学建筑(学)家园, 解构建构(分析)整合学习, 智商情商(IQ、EQ)运筹(学)生存.---Geovin Du(涂聚文)