public static void GetSunRiseSet(TimeZoneInfo tz, DateTime dt, double longitude, double latitude, out float sunRiseStart, out float sunRiseEnd, out float sunSetStart, out float sunSetEnd)
        {
            // get julian day at noon
            var    utcNoon  = TimeZoneInfo.ConvertTimeToUtc(new DateTime(dt.Year, dt.Month, dt.Day, 12, 0, 0, DateTimeKind.Unspecified), tz);
            double jdayNoon = GetJulianDayFromGregorianDateTime(utcNoon);

            float sunUpperLimb = -0.833f;
            float sunLowerLimb = 3f; // more than lower limb at horizon to look better

            // magic
            double d = jdayNoon - 2451543.5;
            double w = 282.9404 + 4.70935E-5 * d;
            double e = 0.016709 - 1.151E-9 * d;
            double M = Degrees.Normalize(356.0470 + 0.9856002585 * d);
            double E = Degrees.Normalize(M + Radians.ToDegrees(e) * Degrees.Sin(M) * (1 + e * Degrees.Cos(M)));

            double xv  = Degrees.Cos(E) - e;
            double yv  = Degrees.Sin(E) * Math.Sqrt(1 - e * e);
            double lon = Degrees.Atan2(yv, xv) + w;
            double lat = 0;

            double rasc, decl;

            ConvertEclipticToEquatorial(jdayNoon, lon, lat, out rasc, out decl);

            double Ls           = Degrees.Normalize(w + M);
            double GMST         = Degrees.Normalize(Ls + 180);
            double UTSunInSouth = Degrees.Normalize(rasc - GMST - longitude) / 15.0f;

            var noonUtc = new DateTime(dt.Year, dt.Month, dt.Day, 12, 0, 0, DateTimeKind.Utc);
            var offset  = tz.GetUtcOffset(noonUtc);

            double cosLHA = (Degrees.Sin(sunUpperLimb) - Degrees.Sin(latitude) * Degrees.Sin(decl)) / (Degrees.Cos(latitude) * Degrees.Cos(decl));

            if (cosLHA < -1)
            {
                // never set
                sunRiseStart = 0;
                sunSetEnd    = 24;
            }
            else if (cosLHA > 1)
            {
                // never rise
                sunRiseStart = 24;
                sunSetEnd    = 0;
            }
            else
            {
                double LHA     = Degrees.Acos(cosLHA);
                double convert = LHA / 15f;

                sunRiseStart = (float)(UTSunInSouth - convert + offset.TotalHours);
                sunSetEnd    = (float)(UTSunInSouth + convert + offset.TotalHours);
            }

            cosLHA = (Degrees.Sin(sunLowerLimb) - Degrees.Sin(latitude) * Degrees.Sin(decl)) / (Degrees.Cos(latitude) * Degrees.Cos(decl));
            if (cosLHA < -1)
            {
                // never set
                sunRiseEnd  = 0;
                sunSetStart = 24;
            }
            else if (cosLHA > 1)
            {
                // never rise
                sunRiseEnd  = 24;
                sunSetStart = 0;
            }
            else
            {
                double LHA     = Degrees.Acos(cosLHA);
                double convert = LHA / 15f;

                sunRiseEnd  = (float)(UTSunInSouth - convert + offset.TotalHours);
                sunSetStart = (float)(UTSunInSouth + convert + offset.TotalHours);
            }
        }