/// <summary> /// Initializes a new instance of the <see cref="DaylightHours"/> class. /// </summary> /// <param name="location"> /// The location. /// </param> /// <param name="day"> /// The day. /// </param> /// <param name="sunrise"> /// The sunrise time. /// </param> /// <param name="sunset"> /// The sunset time. /// </param> private DaylightHours(GeographicLocation location, DateTimeOffset day, TimeSpan?sunrise, TimeSpan?sunset) { _day = day; _location = location; _sunrise = sunrise; _sunset = sunset; }
private static DaylightHours CalculateCore(DateTimeOffset day, GeographicLocation location) { double jdate = ToJulian(day); double n = Math.Round((jdate - BaseJulianDays - 0.0009D) - (location.LongitudeWest / 360D)); double jnoon = BaseJulianDays + 0.0009D + (location.LongitudeWest / 360D) + n; double m = (EarthDegreesPerYear + (EarthDegreesPerDay * (jnoon - BaseJulianDays))) % 360; double c = (EarthEocCoeff1 * Sin(m)) + (EarthEocCoeff2 * Sin(2 * m)) + (EarthEocCoeff3 * Sin(3 * m)); double sunLon = (m + EarthPerihelion + c + 180D) % 360; double jtransit = jnoon + (EarthTransitJ1 * Sin(m)) + (EarthTransitJ2 * Sin(2 * sunLon)); int iteration = 0; double oldMean; do { oldMean = m; m = (EarthDegreesPerYear + (EarthDegreesPerDay * (jtransit - BaseJulianDays))) % 360; c = (EarthEocCoeff1 * Sin(m)) + (EarthEocCoeff2 * Sin(2 * m)) + (EarthEocCoeff3 * Sin(3 * m)); sunLon = (m + EarthPerihelion + c + 180D) % 360; jtransit = jnoon + (EarthTransitJ1 * Sin(m)) + (EarthTransitJ2 * Sin(2 * sunLon)); }while (iteration++ < 100 && Math.Abs(m - oldMean) > Epsilon); double sunDec = Asin(Sin(sunLon) * Sin(EarthObliquity)); double h = Acos((Sin(EarthSolarDiskDiameter) - Sin(location.Latitude) * Sin(sunDec)) / (Cos(location.Latitude) * Cos(sunDec))); if (Math.Abs(h) < Epsilon || double.IsNaN(h) || double.IsInfinity(h)) { return(new DaylightHours(location, day, null, null)); } double jnoon2 = BaseJulianDays + 0.0009D + ((h + location.LongitudeWest) / 360D) + n; double jset = jnoon2 + (EarthTransitJ1 * Sin(m)) + (EarthTransitJ2 * Sin(2 * sunLon)); double jrise = jtransit - (jset - jtransit); DateTimeOffset sunrise = FromJulian(jrise); Debug.Assert(sunrise.Date == day.Date, "Wrong sunrise", "Sunrise: Expected {0:D} but got {1:D} instead.", day, sunrise.Date); DateTimeOffset sunset = FromJulian(jset); Debug.Assert(sunset.Date == day.Date, "Wrong sunset", "Sunset: Expected {0:D} but got {1:D} instead.", day, sunset.Date); return(new DaylightHours(location, day, sunrise.TimeOfDay, sunset.TimeOfDay)); }
/// <summary> /// Calculates the sunrise and sunset days for the specified date and location. /// </summary> /// <param name="year"> /// The year for which the times are calculated. /// </param> /// <param name="month"> /// The month for which the times are calculated. /// </param> /// <param name="day"> /// The day for which the times are calculated. /// </param> /// <param name="location"> /// The <see cref="GeographicLocation"/> for which the times are calculated. /// </param> /// <returns> /// A <see cref="DaylightHours"/> instance representing the calculated times. /// This value will never be <see langword="null"/>, although the sunrise/sunset times could be. /// </returns> /// <exception cref="ArgumentOutOfRangeException"> /// <para><paramref name="year"/> is less than 1 or greater than 9999.</para> /// <para>-or-</para> /// <para><paramref name="month"/> is less than 1 or greater than 12.</para> /// <para>-or-</para> /// <para><paramref name="day"/> is less than 1 or greater than the number of days in the specified month.</para> /// <para>-or-</para> /// <para>The specified date is earlier than <see cref="DateTimeOffset.MinValue"/> or later than <see cref="DateTimeOffset.MaxValue"/>.</para> /// </exception> /// <exception cref="InvalidOperationException"> /// There was an error with the calculation. /// </exception> public static DaylightHours Calculate(int year, int month, int day, GeographicLocation location) { var date = new DateTimeOffset(year, month, day, 0, 0, 0, TimeSpan.Zero); return(CalculateCore(date, location)); }
/// <summary> /// Calculates the sunrise and sunset days for the specified date and location. /// </summary> /// <param name="day"> /// The date for which the times are calculated. /// </param> /// <param name="location"> /// The <see cref="GeographicLocation"/> for which the times are calculated. /// </param> /// <returns> /// A <see cref="DaylightHours"/> instance representing the calculated times. /// This value will never be <see langword="null"/>, although the sunrise/sunset times could be. /// </returns> /// <exception cref="InvalidOperationException"> /// There was an error with the calculation. /// </exception> public static DaylightHours Calculate(DateTime day, GeographicLocation location) { return(CalculateCore(day.ToUniversalTime().Date, location)); }
/// <summary> /// Calculates the sunrise and sunset days for the specified date and location. /// </summary> /// <param name="day"> /// The date for which the times are calculated. /// </param> /// <param name="location"> /// The <see cref="GeographicLocation"/> for which the times are calculated. /// </param> /// <returns> /// A <see cref="DaylightHours"/> instance representing the calculated times. /// This value will never be <see langword="null"/>, although the sunrise/sunset times could be. /// </returns> /// <exception cref="InvalidOperationException"> /// There was an error with the calculation. /// </exception> public static DaylightHours Calculate(DateTimeOffset day, GeographicLocation location) { return(CalculateCore(day.UtcDateTime.Date, location)); }