Skip to content

Commit

Permalink
Add constants for calendar cycles
Browse files Browse the repository at this point in the history
  • Loading branch information
sbooth committed Oct 31, 2023
1 parent 1088f9e commit 353c595
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 54 deletions.
42 changes: 24 additions & 18 deletions Sources/JulianDayNumber/JDN+GregorianCalendar.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@

import Foundation

/// The number of years in a cycle of the Gregorian calendar.
///
/// A cycle in the Gregorian calendar consists of 303 common years and 97 leap years.
let gregorianCalendarCycleYears = 400

/// The number of days in a cycle of the Gregorian calendar.
///
/// A cycle in the Gregorian calendar consists of 303 years of 365 days and 97 leap year of 366 days.
let gregorianCalendarCycleDays = 146097

/// Converts a date in the Gregorian calendar to a Julian day number.
///
/// The Julian day number (JDN) is the integer assigned to a whole solar day in the Julian day count starting from noon Universal Time,
Expand All @@ -21,18 +31,16 @@ import Foundation
/// - returns: The JDN corresponding to the requested date.
public func gregorianCalendarDateToJulianDayNumber(year Y: Int, month M: Int, day D: Int) -> Int {
var Y = Y
var ΔleapCycles = 0
var ΔcalendarCycles = 0

// Richards' algorithm is only valid for positive JDNs.
// JDN 0 is -4713-Nov-24 in the proleptic Gregorian calendar.
// Adjust the year of earlier dates forward in time by a multiple of
// 400 (to account for leap years in the Gregorian calendar)
// before calculating the JDN and then translate the result backward
// in time by the period of adjustment.
// the calendar's cycle before calculating the JDN, and then translate
// the result backward in time by the period of adjustment.
if Y < -4713 || (Y == -4713 && (M < 11 || (M == 11 && D < 24))) {
// 400 years * 365.2425 days/year = 146,097 days
ΔleapCycles = (-4714 - Y) / 400 + 1
Y += ΔleapCycles * 400
ΔcalendarCycles = (-4714 - Y) / gregorianCalendarCycleYears + 1
Y += ΔcalendarCycles * gregorianCalendarCycleYears
}

let h = M - m
Expand All @@ -42,8 +50,8 @@ public func gregorianCalendarDateToJulianDayNumber(year Y: Int, month M: Int, da
var J = e + (s * f + t) / u
J = J - (3 * ((g + A) / 100)) / 4 - C

if ΔleapCycles > 0 {
J -= ΔleapCycles * 146097
if ΔcalendarCycles > 0 {
J -= ΔcalendarCycles * gregorianCalendarCycleDays
}

return J
Expand All @@ -66,17 +74,15 @@ let latestSupportedGregorianCalendarJDN = latestSupportedJDN
/// - returns: The calendar date corresponding to `J`.
public func julianDayNumberToGregorianCalendarDate(_ J: Int) -> (year: Int, month: Int, day: Int) {
var J = J
var ΔleapCycles = 0
var ΔcalendarCycles = 0

// Richards' algorithm is only valid for positive JDNs.
// Adjust negative JDNs forward in time by a multiple of
// 400 years (to account for leap years in the Gregorian calendar)
// before calculating the proleptic Gregorian date and then translate
// the result backward in time by the amount of forward adjustment.
// the calendar's cycle before calculating the JDN, and then translate
// the result backward in time by the period of adjustment.
if J < 0 {
// 400 years * 365.2425 days/year = 146,097 days
ΔleapCycles = -J / 146097 + 1
J += ΔleapCycles * 146097
ΔcalendarCycles = -J / gregorianCalendarCycleDays + 1
J += ΔcalendarCycles * gregorianCalendarCycleDays
}

var f = J + j
Expand All @@ -88,8 +94,8 @@ public func julianDayNumberToGregorianCalendarDate(_ J: Int) -> (year: Int, mont
let M = ((h / s + m) % n) + 1
var Y = e / p - y + (n + m - M) / n

if ΔleapCycles > 0 {
Y -= ΔleapCycles * 400
if ΔcalendarCycles > 0 {
Y -= ΔcalendarCycles * gregorianCalendarCycleYears
}

return (Y, M, D)
Expand Down
42 changes: 24 additions & 18 deletions Sources/JulianDayNumber/JDN+IslamicCalendar.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@

import Foundation

/// The number of years in a cycle of the Islamic calendar.
///
/// A cycle in the Islamic calendar consists of 19 common years and 11 leap years.
let islamicCalendarCycleYears = 30

/// The number of days in a cycle of the Islamic calendar.
///
/// A cycle in the Islamic calendar consists of 19 years of 354 days and 11 leap years of 355 days.
let islamicCalendarCycleDays = 10631

/// Converts a date in the Islamic calendar to a Julian day number.
///
/// The Julian day number (JDN) is the integer assigned to a whole solar day in the Julian day count starting from noon Universal Time,
Expand All @@ -22,18 +32,16 @@ import Foundation
/// - returns: The JDN corresponding to the requested date.
public func islamicCalendarDateToJulianDayNumber(year Y: Int, month M: Int, day D: Int) -> Int {
var Y = Y
var ΔleapCycles = 0
var ΔcalendarCycles = 0

// Richards' algorithm is only valid for positive JDNs.
// JDN 0 is -5498-08-16 in the proleptic Islamic calendar.
// Adjust the year of earlier dates forward in time by a multiple of
// 30 (to account for leap years in the Islamic calendar)
// before calculating the JDN and then translate the result backward
// in time by the period of adjustment.
// the calendar's cycle before calculating the JDN, and then translate
// the result backward in time by the period of adjustment.
if Y < -5498 || (Y == -5498 && (M < 8 || (M == 8 && D < 16))) {
// 30 years = 10,631 days (19 years of 354 days and 11 leap years of 355 days)
ΔleapCycles = (-5498 - Y) / 30 + 1
Y += ΔleapCycles * 30
ΔcalendarCycles = (-5498 - Y) / islamicCalendarCycleYears + 1
Y += ΔcalendarCycles * islamicCalendarCycleYears
}

let h = M - m
Expand All @@ -42,8 +50,8 @@ public func islamicCalendarDateToJulianDayNumber(year Y: Int, month M: Int, day
let e = (p * g + q) / r + D - 1 - j
var J = e + (s * f + t) / u

if ΔleapCycles > 0 {
J -= ΔleapCycles * 10631
if ΔcalendarCycles > 0 {
J -= ΔcalendarCycles * islamicCalendarCycleDays
}

return J
Expand All @@ -66,17 +74,15 @@ let latestSupportedIslamicCalendarJDN = 37384751
/// - returns: The calendar date corresponding to `J`.
public func julianDayNumberToIslamicCalendarDate(_ J: Int) -> (year: Int, month: Int, day: Int) {
var J = J
var ΔleapCycles = 0
var ΔcalendarCycles = 0

// Richards' algorithm is only valid for positive JDNs.
// Adjust negative JDNs forward in time by a multiple of
// 30 years (to account for leap years in the Islamic calendar)
// before calculating the proleptic Islamic date and then translate
// the result backward in time by the amount of forward adjustment.
// the calendar's cycle before calculating the JDN, and then translate
// the result backward in time by the period of adjustment.
if J < 0 {
// 30 years = 10,631 days (19 years of 354 days and 11 leap years of 355 days)
ΔleapCycles = -J / 10631 + 1
J += ΔleapCycles * 10631
ΔcalendarCycles = -J / islamicCalendarCycleDays + 1
J += ΔcalendarCycles * islamicCalendarCycleDays
}

let f = J + j
Expand All @@ -87,8 +93,8 @@ public func julianDayNumberToIslamicCalendarDate(_ J: Int) -> (year: Int, month:
let M = ((h / s + m) % n) + 1
var Y = e / p - y + (n + m - M) / n

if ΔleapCycles > 0 {
Y -= ΔleapCycles * 30
if ΔcalendarCycles > 0 {
Y -= ΔcalendarCycles * islamicCalendarCycleYears
}

return (Y, M, D)
Expand Down
42 changes: 24 additions & 18 deletions Sources/JulianDayNumber/JDN+JulianCalendar.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@

import Foundation

/// The number of years in a cycle of the Julian calendar.
///
/// A cycle in the Julian calendar consists of 3 common years and 1 leap year.
let julianCalendarCycleYears = 4

/// The number of days in a cycle of the Julian calendar.
///
/// A cycle in the Julian calendar consists of 3 years of 365 days and 1 leap year of 366 days.
let julianCalendarCycleDays = 1461

/// Converts a date in the Julian calendar to a Julian day number.
///
/// The Julian day number (JDN) is the integer assigned to a whole solar day in the Julian day count starting from noon Universal Time,
Expand All @@ -20,18 +30,16 @@ import Foundation
/// - returns: The JDN corresponding to the requested date.
public func julianCalendarDateToJulianDayNumber(year Y: Int, month M: Int, day D: Int) -> Int {
var Y = Y
var ΔleapCycles = 0
var ΔcalendarCycles = 0

// Richards' algorithm is only valid for positive JDNs.
// JDN 0 is -4712-01-01 in the proleptic Julian calendar.
// Adjust the year of earlier dates forward in time by a multiple of
// 4 (the frequency of leap years in the Julian calendar)
// before calculating the JDN and then translate the result backward
// in time by the period of adjustment.
// the calendar's cycle before calculating the JDN, and then translate
// the result backward in time by the period of adjustment.
if Y < -4712 {
// 4 years * 365.25 days/year = 1,461 days
ΔleapCycles = (-4713 - Y) / 4 + 1
Y += ΔleapCycles * 4
ΔcalendarCycles = (-4713 - Y) / julianCalendarCycleYears + 1
Y += ΔcalendarCycles * julianCalendarCycleYears
}

let h = M - m
Expand All @@ -40,8 +48,8 @@ public func julianCalendarDateToJulianDayNumber(year Y: Int, month M: Int, day D
let e = (p * g + q) / r + D - 1 - j
var J = e + (s * f + t) / u

if ΔleapCycles > 0 {
J -= ΔleapCycles * 1461
if ΔcalendarCycles > 0 {
J -= ΔcalendarCycles * julianCalendarCycleDays
}

return J
Expand All @@ -64,17 +72,15 @@ let latestSupportedJulianCalendarJDN = 38246057
/// - returns: The calendar date corresponding to `J`.
public func julianDayNumberToJulianCalendarDate(_ J: Int) -> (year: Int, month: Int, day: Int) {
var J = J
var ΔleapCycles = 0
var ΔcalendarCycles = 0

// Richards' algorithm is only valid for positive JDNs.
// Adjust negative JDNs forward in time by a multiple of
// 4 years (the frequency of leap years in the Julian calendar)
// before calculating the proleptic Julian date and then translate
// the result backward in time by the amount of forward adjustment.
// the calendar's cycle before calculating the JDN, and then translate
// the result backward in time by the period of adjustment.
if J < 0 {
// 4 years * 365.25 days/year = 1,461 days
ΔleapCycles = -J / 1461 + 1
J += ΔleapCycles * 1461
ΔcalendarCycles = -J / julianCalendarCycleDays + 1
J += ΔcalendarCycles * julianCalendarCycleDays
}

let f = J + j
Expand All @@ -85,8 +91,8 @@ public func julianDayNumberToJulianCalendarDate(_ J: Int) -> (year: Int, month:
let M = ((h / s + m) % n) + 1
var Y = e / p - y + (n + m - M) / n

if ΔleapCycles > 0 {
Y -= ΔleapCycles * 4
if ΔcalendarCycles > 0 {
Y -= ΔcalendarCycles * julianCalendarCycleYears
}

return (Y, M, D)
Expand Down

0 comments on commit 353c595

Please sign in to comment.