Space Library
Home
>
Algorithms
>
Julian Days
>
Source Code
Home
Algorithms
Julian Days
Source Code
Western Church Holy Days
Source Code
Sidereal Time
Sun Rise and Set
Moon Rise and Set
About Us
0.15 seconds
Julian Days Source Code
Source Code (last updated: 26-Jul-2007)
#region Copyright (c) 2007 Larry D. Hunt /****************************************************************************** ' ' License: MIT License (also called the X11 License) ' ' Copyright (c) 2007 Larry D. Hunt ' ' Permission is hereby granted, free of charge, to any person obtaining a copy ' of this software and associated documentation files (the "Software"), to deal ' in the Software without restriction, including without limitation the rights ' to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ' copies of the Software, and to permit persons to whom the Software is ' furnished to do so, subject to the following conditions: ' ' The above copyright notice and this permission notice shall be included in ' all copies or substantial portions of the Software. ' ' THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ' IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ' FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ' AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ' LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ' OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ' THE SOFTWARE. ' '*****************************************************************************/ #endregion using System; using System.Collections.Generic; using System.Text; using SpaceLib.Tools; namespace SpaceLib.Algorithms { // Julian Day Algorithms. // Reference: Astronomical Algorithms (2nd edition) by Jean Meeus, ISBN: 0-943396-61-1; Chapter 7. public class JulianDay { #region Properties private int _year = 0; public int Year { get { return _year; } set { _year = value; } } private int _month = 0; public int Month { get { return _month; } set { _month = value; } } private double _day = 0; public double Day { get { return _day; } set { _day = value; } } public DateTime DateTime { get { double dayReal = _day; int dayInteger = (int)_day; double hourReal = ((dayReal - dayInteger) * 24.0d); int hourInteger = (int)hourReal; double minuteReal = (hourReal - hourInteger) * 60d; int minuteInteger = (int)minuteReal; double secondReal = (minuteReal - minuteInteger) * 60d; int secondInteger = (int)secondReal; double millisecondReal = (secondReal - secondInteger) * 60d; int millisecondInteger = (int)millisecondReal; return new DateTime(_year, _month, dayInteger, hourInteger, minuteInteger, secondInteger, millisecondInteger); } set { SetDateTime(value); } } #endregion public JulianDay() { SetDateTime(0, 0, 0.0d); } public JulianDay(int year, int month, double day) { SetDateTime(year, month, day); } public JulianDay(int year, int month, int day, int hour, int minute, double second) { SetDateTime(year, month, day, hour, minute, second); } public JulianDay(DateTime aDate) { SetDateTime(aDate); } public double GetJulianDays() { return GetJulianDays(_year, _month, _day); } private double GetJulianDays(int year, int month, double day) { // Note; use one character variable names to match equation in Meeus book. if (year < -4712) throw new System.ArgumentOutOfRangeException("Year must be greater than -4713."); if (month >= 13) throw new System.ArgumentOutOfRangeException("Month must be less than 13."); if (day >= 32) throw new System.ArgumentOutOfRangeException("Day must be less than 32."); if (month <= 2) { year -= 1; month += 12; } int b = 0; if (IsGregorianDateRange(year, month, day)) { int a = (int)Math.Floor((double)year / 100.0d); b = 2 - a + (int)Math.Floor((double)a / 4.0d); } return Math.Floor(365.25d * (year + 4716)) + Math.Floor(30.6001d * (month + 1)) + day + b - 1524.5d; } public int GetDayOfWeek() { // Return day of week; Sunday = 0, Saturday = 6. if (_month >= 13) throw new System.ArgumentOutOfRangeException("Month must be less than 13."); if (_day >= 32) throw new System.ArgumentOutOfRangeException("Day must be less than 32."); double dayAtUTZero = Math.Floor(_day); int days = (int)GetJulianDays(_year, _month, dayAtUTZero + 1.5d); return days % 7; } public int GetDayOfYear() { if (_month >= 13) throw new System.ArgumentOutOfRangeException("Month must be less than 13."); if (_day >= 32) throw new System.ArgumentOutOfRangeException("Day must be less than 32."); int k = (IsLeapYear(_year)) ? 1 : 2; return (int)(Math.Floor((275d * _month) / 9d) - (k * Math.Floor((_month + 9d) / 12d)) + Math.Floor(_day) - 30d); } public bool IsGregorianDateRange() { return IsGregorianDateRange(_year, _month, _day); } private bool IsGregorianDateRange(int year, int month, double day) { // The day following 1582 October 4 (Julian calendar) is 1582 October 15 (Gregorian calendar). if (year > 1582) return true; // Do greater year test first since this will happen more often. if (year < 1582) return false; if (month > 10) return true; if (month < 10) return false; if (day < 15) return false; return true; } public bool IsLeapYear() { return IsLeapYear(_year); } private bool IsLeapYear(int year) { bool isLeapYear = false; if (year % 4 == 0) isLeapYear = true; if (isLeapYear && (IsGregorianDateRange(year, 1, 1d))) { // A Gregorian date is not a leap year if century is divible by 400. if (year % 400 == 0) isLeapYear = false; } return isLeapYear; } public void SetDateTime(int year, int month, double day) { _year = year; _month = month; _day = day; } public void SetDateTime(int year, int month, int day, int hour, int minute, double second) { _year = year; _month = month; _day = day + (hour / 24.0d) + (minute / 1440.0d) + (second / 86400.0d); } public void SetDateTime(DateTime aDate) { _year = aDate.Year; _month = aDate.Month; _day = aDate.Day + (aDate.Hour / 24.0d) + (aDate.Minute / 1440.0d) + (aDate.Second / 86400.0d) + (aDate.Millisecond / 86400000.0d); } public void SetDateTime(int year, int dayOfYear) { int k = (IsLeapYear(year)) ? 1 : 2; _month = (dayOfYear < 32) ? 1 : (int)Math.Floor(((9d * (k + dayOfYear)) / 275d) + 0.98d); _day = dayOfYear - Math.Floor((275d * _month) / 9d) + (k * Math.Floor((_month + 9d) / 12d)) + 30; } public void SetJulianDays(double julianDays) { // Note; use int when possible, from test results this improves performance by 50%. // Note; use one character variable names to match equation in Meeus book. julianDays += 0.5d; int z = (int) Math.Floor(julianDays); // For f trim off least significant digits which is introduced by floating-point math. double f = Mathematics.Round(julianDays - z, 6); int a = z; if (z >= 2299161) { int alpha = (int) Math.Floor((z - 1867216.25d) / 36524.25d); a = z + 1 + alpha - (int) Math.Floor(alpha / 4.0d); } int b = a + 1524; int c = (int) Math.Floor((b - 122.1d) / 365.25d); int d = (int) Math.Floor(365.25d * c); int e = (int) Math.Floor((b - d) / 30.6001d); _day = b - d - (int) Math.Floor(30.6001d * e) + f; _month = (e < 14) ? e - 1 : e - 13; _year = (_month > 2) ? c - 4716 : c - 4715; } } }
Helper Code (last updated: 25-Jul-2007)
using System; using System.Collections.Generic; using System.Text; namespace SpaceLib.Tools { public class Mathematics { static public double Round(double value, int decimals) { return Math.Round(value, decimals, MidpointRounding.AwayFromZero); } } } using System; using System.Collections.Generic; using System.Text; using System.Globalization; namespace SpaceLib.Tools { public class Strings { static public bool IsNumeric(string value) { double result; return double.TryParse(Convert.ToString(value, CultureInfo.InvariantCulture), NumberStyles.Any, NumberFormatInfo.InvariantInfo, out result); } } }
Unit Test Code (last updated: 26-Jul-2007)
[TestFixture] public class JulianDayTest { [Test] public void s001_GregorianDateRange() { // The day following 1582 October 4 (Julian calendar) is 1582 October 15 (Gregorian calendar). JulianDay julianDay = new JulianDay(1582, 10, 14); Assert.IsFalse(julianDay.IsGregorianDateRange(), "IsGregorianDateRange not correct."); } [Test] public void s002_GregorianDateRange() { // The day following 1582 October 4 (Julian calendar) is 1582 October 15 (Gregorian calendar). JulianDay julianDay = new JulianDay(1582, 10, 15); Assert.IsTrue(julianDay.IsGregorianDateRange(), "IsGregorianDateRange not correct."); } [Test] public void s003_JulianDay_JulianDate() { // Check with date of January 27th at 12 hours of the year 333. JulianDay julianDay = new JulianDay(333, 1, 27.5); Assert.AreEqual(1842713.0d, julianDay.GetJulianDays(), "Days not correct."); } [Test] public void s004_JulianDay_GregorianDate() { // Check with date of the launch of Sputnik 1. JulianDay julianDay = new JulianDay(1957, 10, 4.81); Assert.AreEqual(2436116.31d, julianDay.GetJulianDays(), "Days not correct."); } [Test] public void s005_JulianDay_EarliestDate() { // Check with earliest date algorithm can handle. JulianDay julianDay = new JulianDay(-4712, 1, 1.5); Assert.AreEqual(0d, julianDay.GetJulianDays(), "Days not correct."); } [Test] public void s007_JulianDay_KnownDate_Instantiation() { // Check with known date. JulianDay julianDay = new JulianDay(2000, 1, 1.5); Assert.AreEqual(2451545.0d, julianDay.GetJulianDays(), "Days not correct."); } [Test] public void s008_JulianDay_KnownDate_SetDateTime() { // Check with known date. JulianDay julianDay = new JulianDay(); julianDay.SetDateTime(2000, 1, 1.5); Assert.AreEqual(2451545.0d, julianDay.GetJulianDays(), "Days not correct."); } [Test] public void s010_JulianDay_KnownDates() { // Check with known dates found in Astronomical Algorithms (2nd edition) by Jean Meeus, ISBN: 0-943396-61-1 page 62. JulianDay julianDay = new JulianDay(); julianDay.SetDateTime(2000, 1, 1.5); Assert.AreEqual(2451545.0, julianDay.GetJulianDays(), "Days not correct."); julianDay.SetDateTime(1999, 1, 1.0); Assert.AreEqual(2451179.5, julianDay.GetJulianDays(), "Days not correct."); julianDay.SetDateTime(1987, 1, 27.0); Assert.AreEqual(2446822.5, julianDay.GetJulianDays(), "Days not correct."); julianDay.SetDateTime(1987, 6, 19.5); Assert.AreEqual(2446966.0, julianDay.GetJulianDays(), "Days not correct."); julianDay.SetDateTime(1988, 1, 27.0); Assert.AreEqual(2447187.5, julianDay.GetJulianDays(), "Days not correct."); julianDay.SetDateTime(1988, 6, 19.5); Assert.AreEqual(2447332.0, julianDay.GetJulianDays(), "Days not correct."); julianDay.SetDateTime(1900, 1, 1.0); Assert.AreEqual(2415020.5, julianDay.GetJulianDays(), "Days not correct."); julianDay.SetDateTime(1600, 1, 1.0); Assert.AreEqual(2305447.5, julianDay.GetJulianDays(), "Days not correct."); julianDay.SetDateTime(1600, 12, 31.0); Assert.AreEqual(2305812.5, julianDay.GetJulianDays(), "Days not correct."); julianDay.SetDateTime(837, 4, 10.3); Assert.AreEqual(2026871.8, julianDay.GetJulianDays(), "Days not correct."); julianDay.SetDateTime(-123, 12, 31.0); Assert.AreEqual(1676496.5, julianDay.GetJulianDays(), "Days not correct."); julianDay.SetDateTime(-122, 1, 1.0); Assert.AreEqual(1676497.5, julianDay.GetJulianDays(), "Days not correct."); julianDay.SetDateTime(-1000, 7, 12.5); Assert.AreEqual(1356001.0, julianDay.GetJulianDays(), "Days not correct."); julianDay.SetDateTime(-1000, 2, 29.0); Assert.AreEqual(1355866.5, julianDay.GetJulianDays(), "Days not correct."); julianDay.SetDateTime(-1001, 8, 17.9); Assert.AreEqual(1355671.4, julianDay.GetJulianDays(), "Days not correct."); julianDay.SetDateTime(-4712, 1, 1.5); Assert.AreEqual(0.0, julianDay.GetJulianDays(), "Days not correct."); } [Test] public void s030_JulianDay_EarliestDate_Overload() { JulianDay julianDay = new JulianDay(-4712, 1, 1, 12, 0, 0d); Assert.AreEqual(0d, julianDay.GetJulianDays(), "Days not correct."); } [Test] public void s031_JulianDay_KnownDate_Overload() { JulianDay julianDay = new JulianDay(2000, 1, 1, 12, 0, 0d); Assert.AreEqual(2451545.0d, julianDay.GetJulianDays(), "Days not correct."); } [Test] public void s032_JulianDay_KnownDate_Overload() { JulianDay julianDay = new JulianDay(new DateTime(333, 1, 27, 12, 0, 0)); Assert.AreEqual(1842713.0d, julianDay.GetJulianDays(), "Days not correct."); } [Test] public void s033_JulianDay_KnownDate_Overload() { JulianDay julianDay = new JulianDay(new DateTime(2000, 1, 1, 12, 0, 0)); Assert.AreEqual(2451545.0d, julianDay.GetJulianDays(), "Days not correct."); } [Test] public void s040_JulianDay_Compare_Overloads() { JulianDay julianDay1 = new JulianDay(new DateTime(2000, 1, 1, 12, 0, 0, 1)); JulianDay julianDay2 = new JulianDay(2000, 1, 1, 12, 0, 0.001d); Assert.AreEqual(julianDay1.GetJulianDays(), julianDay2.GetJulianDays(), "Compare is not correct."); } [Test] public void s041_JulianDay_Compare_PropertyToConstruct() { JulianDay julianDay1 = new JulianDay(); julianDay1.Year = 2000; julianDay1.Month = 1; julianDay1.Day = 1.5; JulianDay julianDay2 = new JulianDay(2000, 1, 1, 12, 0, 0.0d); Assert.AreEqual(julianDay1.GetJulianDays(), julianDay2.GetJulianDays(), "Compare is not correct."); } [Test] public void s042_JulianDay_Compare_PropertyToConstruct() { JulianDay julianDay1 = new JulianDay(); julianDay1.DateTime = new DateTime(2000, 1, 1, 12, 0, 0, 1); JulianDay julianDay2 = new JulianDay(2000, 1, 1, 12, 0, 0.001d); Assert.AreEqual(julianDay1.GetJulianDays(), julianDay2.GetJulianDays(), "Compare is not correct."); } [Test] [ExpectedException(typeof(ArgumentOutOfRangeException))] public void s050_JulianDay_ExpectAnException() { JulianDay julianDay = new JulianDay(-4713, 12, 31); Assert.AreEqual(0d, julianDay.GetJulianDays(), "Days not correct."); } [Test] public void s100_JulianDay_SetJulianDays() { JulianDay julianDay = new JulianDay(); julianDay.SetJulianDays(2436116.31); Assert.AreEqual(1957, julianDay.Year, "Year is not correct."); Assert.AreEqual(10, julianDay.Month, "Month is not correct."); Assert.AreEqual(4.81d, MathLib.Round(julianDay.Day, 4), "Day is not correct."); } [Test] public void s101_JulianDay_SetJulianDays() { JulianDay julianDay = new JulianDay(); julianDay.SetJulianDays(1842713.0d); Assert.AreEqual(333, julianDay.Year, "Year is not correct."); Assert.AreEqual(1, julianDay.Month, "Month is not correct."); Assert.AreEqual(27.5d, MathLib.Round(julianDay.Day, 4), "Day is not correct."); } [Test] public void s102_JulianDay_SetJulianDays() { JulianDay julianDay = new JulianDay(); julianDay.SetJulianDays(1507900.13d); Assert.AreEqual(-584, julianDay.Year, "Year is not correct."); Assert.AreEqual(5, julianDay.Month, "Month is not correct."); Assert.AreEqual(28.63d, MathLib.Round(julianDay.Day, 4), "Day is not correct."); } [Test] public void s103_JulianDay_SetJulianDays() { // Supnik launch date and time: 1957-10-04 at 19:26:00. Note; some history websites state: 19:12:00. JulianDay julianDay = new JulianDay(); julianDay.SetJulianDays(2436116.31); DateTime aDate = julianDay.DateTime; Assert.AreEqual(1957, aDate.Year, "Year is not correct."); Assert.AreEqual(10, aDate.Month, "Month is not correct."); Assert.AreEqual(4, aDate.Day, "Day is not correct."); Assert.AreEqual(19, aDate.Hour, "Hour is not correct."); Assert.AreEqual(26, aDate.Minute, "Minute is not correct."); } [Test] public void s200_JulianDay_NumberOfDays() { // Check number of days between the appearance of Halley comet. JulianDay julianDay1 = new JulianDay(1986, 2, 9.0); JulianDay julianDay2 = new JulianDay(1910, 4, 20.0); Assert.AreEqual(27689, julianDay1.GetJulianDays() - julianDay2.GetJulianDays(), "Days not correct."); } [Test] public void s201_JulianDay_FutureDate() { // Check the date 10,000 days from July 11, 1991. JulianDay julianDay = new JulianDay(1991, 7, 11.0); double days = julianDay.GetJulianDays() + 10000; julianDay.SetJulianDays(days); Assert.AreEqual(2018, julianDay.Year, "Year is not correct."); Assert.AreEqual(11, julianDay.Month, "Month is not correct."); Assert.AreEqual(26.0d, MathLib.Round(julianDay.Day, 4), "Day is not correct."); } [Test] public void s202_JulianDay_GetDayOfWeek() { JulianDay julianDay = new JulianDay(1954, 6, 30d); Assert.AreEqual(3, julianDay.GetDayOfWeek(), "DayOfWeek not correct."); } [Test] public void s203_JulianDay_GetDayOfWeek() { JulianDay julianDay = new JulianDay(1954, 6, 30.5d); Assert.AreEqual(3, julianDay.GetDayOfWeek(), "DayOfWeek not correct."); } [Test] public void s210_JulianDay_GetDayOfYear() { JulianDay julianDay = new JulianDay(1978, 11, 14); Assert.AreEqual(318, julianDay.GetDayOfYear(), "DayOfYear not correct."); } [Test] public void s211_JulianDay_GetDayOfYear() { JulianDay julianDay = new JulianDay(1988, 4, 22); Assert.AreEqual(113, julianDay.GetDayOfYear(), "DayOfYear not correct."); } [Test] public void s215_JulianDay_SetDateTime() { JulianDay julianDay = new JulianDay(); julianDay.SetDateTime(1978, 318); Assert.AreEqual(11, julianDay.Month, "Month not correct."); Assert.AreEqual(14, julianDay.Day, "Day not correct."); } [Test] public void s216_JulianDay_SetDateTime() { JulianDay julianDay = new JulianDay(); julianDay.SetDateTime(1988, 113); Assert.AreEqual(4, julianDay.Month, "Month not correct."); Assert.AreEqual(22, julianDay.Day, "Day not correct."); } [Test] public void s220_JulianDay_LeapYear() { JulianDay julianDay = new JulianDay(400,1,1); Assert.AreEqual(true, julianDay.IsLeapYear(), "IsLeapYear not correct."); } [Test] public void s221_JulianDay_LeapYear() { JulianDay julianDay = new JulianDay(401, 1, 1); Assert.AreEqual(false, julianDay.IsLeapYear(), "IsLeapYear not correct."); } [Test] public void s222_JulianDay_LeapYear() { JulianDay julianDay = new JulianDay(1996, 1, 1); Assert.AreEqual(true, julianDay.IsLeapYear(), "IsLeapYear not correct."); } public void s223_JulianDay_LeapYear() { JulianDay julianDay = new JulianDay(1997, 1, 1); Assert.AreEqual(false, julianDay.IsLeapYear(), "IsLeapYear not correct."); } [Test] public void s224_JulianDay_LeapYear() { JulianDay julianDay = new JulianDay(2000, 1, 1); Assert.AreEqual(false, julianDay.IsLeapYear(), "IsLeapYear not correct."); }