// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. namespace System.Globalization { using System; using System.Diagnostics; using System.Diagnostics.Contracts; internal class CalendricalCalculationsHelper { const double FullCircleOfArc = 360.0; // 360.0; const int HalfCircleOfArc = 180; const double TwelveHours = 0.5; // half a day const double Noon2000Jan01 = 730120.5; internal const double MeanTropicalYearInDays = 365.242189; const double MeanSpeedOfSun = MeanTropicalYearInDays / FullCircleOfArc; const double LongitudeSpring = 0.0; const double TwoDegreesAfterSpring = 2.0; const int SecondsPerDay = 24 * 60 * 60; // 24 hours * 60 minutes * 60 seconds const int DaysInUniformLengthCentury = 36525; const int SecondsPerMinute = 60; const int MinutesPerDegree = 60; static long StartOf1810 = GetNumberOfDays(new DateTime(1810, 1, 1)); static long StartOf1900Century = GetNumberOfDays(new DateTime(1900, 1, 1)); static double[] Coefficients1900to1987 = new double[] { -0.00002, 0.000297, 0.025184, -0.181133, 0.553040, -0.861938, 0.677066, -0.212591 }; static double[] Coefficients1800to1899 = new double[] { -0.000009, 0.003844, 0.083563, 0.865736, 4.867575, 15.845535, 31.332267, 38.291999, 28.316289, 11.636204, 2.043794 }; static double[] Coefficients1700to1799 = new double[] { 8.118780842, -0.005092142, 0.003336121, -0.0000266484 }; static double[] Coefficients1620to1699 = new double[] { 196.58333, -4.0675, 0.0219167 }; static double[] LambdaCoefficients = new double[] { 280.46645, 36000.76983, 0.0003032 }; static double[] AnomalyCoefficients = new double[] { 357.52910, 35999.05030, -0.0001559, -0.00000048 }; static double[] EccentricityCoefficients = new double[] { 0.016708617, -0.000042037, -0.0000001236 }; static double[] Coefficients = new double[] { Angle(23, 26, 21.448), Angle(0, 0, -46.8150), Angle(0, 0, -0.00059), Angle(0, 0, 0.001813) }; static double[] CoefficientsA = new double[] { 124.90, -1934.134, 0.002063 }; static double[] CoefficientsB = new double[] { 201.11, 72001.5377, 0.00057 }; static double RadiansFromDegrees(double degree) { return degree * Math.PI / 180; } static double SinOfDegree(double degree) { return Math.Sin(RadiansFromDegrees(degree)); } static double CosOfDegree(double degree) { return Math.Cos(RadiansFromDegrees(degree)); } static double TanOfDegree(double degree) { return Math.Tan(RadiansFromDegrees(degree)); } public static double Angle(int degrees, int minutes, double seconds) { return ((seconds / SecondsPerMinute + minutes) / MinutesPerDegree) + degrees; } static double Obliquity(double julianCenturies) { return PolynomialSum(Coefficients, julianCenturies); } internal static long GetNumberOfDays(DateTime date) { return date.Ticks / GregorianCalendar.TicksPerDay; } static int GetGregorianYear(double numberOfDays) { return new DateTime(Math.Min((long)(Math.Floor(numberOfDays) * GregorianCalendar.TicksPerDay), DateTime.MaxValue.Ticks)).Year; } enum CorrectionAlgorithm { Default, Year1988to2019, Year1900to1987, Year1800to1899, Year1700to1799, Year1620to1699 } struct EphemerisCorrectionAlgorithmMap { public EphemerisCorrectionAlgorithmMap(int year, CorrectionAlgorithm algorithm) { _lowestYear = year; _algorithm = algorithm; } internal int _lowestYear; internal CorrectionAlgorithm _algorithm; }; static EphemerisCorrectionAlgorithmMap[] EphemerisCorrectionTable = new EphemerisCorrectionAlgorithmMap[] { // lowest year that starts algorithm, algorithm to use new EphemerisCorrectionAlgorithmMap(2020, CorrectionAlgorithm.Default), new EphemerisCorrectionAlgorithmMap(1988, CorrectionAlgorithm.Year1988to2019), new EphemerisCorrectionAlgorithmMap(1900, CorrectionAlgorithm.Year1900to1987), new EphemerisCorrectionAlgorithmMap(1800, CorrectionAlgorithm.Year1800to1899), new EphemerisCorrectionAlgorithmMap(1700, CorrectionAlgorithm.Year1700to1799), new EphemerisCorrectionAlgorithmMap(1620, CorrectionAlgorithm.Year1620to1699), new EphemerisCorrectionAlgorithmMap(int.MinValue, CorrectionAlgorithm.Default) // default must be last }; static double Reminder(double divisor, double dividend) { double whole = Math.Floor(divisor / dividend); return divisor - (dividend * whole); } static double NormalizeLongitude(double longitude) { longitude = Reminder(longitude, FullCircleOfArc); if (longitude < 0) { longitude += FullCircleOfArc; } return longitude; } static public double AsDayFraction(double longitude) { return longitude / FullCircleOfArc; } static double PolynomialSum(double[] coefficients, double indeterminate) { double sum = coefficients[0]; double indeterminateRaised = 1; for (int i=1; i