Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 21 additions & 6 deletions Sources/JulianDayNumber/GregorianCalendar.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,20 @@ public struct GregorianCalendar: Calendar {
/// The Gregorian calendar date corresponding to JDN 0.
static let jdnZero: DateType = (-4713, 11, 24)

#if _pointerBitWidth(_64)
// The Gregorian calendar date corresponding to JDN `Int64.max`
static let upperLimit: DateType = (25252734927761842, 6, 20)
// The Gregorian calendar date corresponding to JDN `Int64.min`
static let lowerLimit: DateType = (-25252734927771267, 4, 30)
#elseif _pointerBitWidth(_32)
// The Gregorian calendar date corresponding to JDN `Int32.max`
static let upperLimit: DateType = (5874898, 6, 3)
// The Gregorian calendar date corresponding to JDN `Int32.min`
static let lowerLimit: DateType = (-5884323, 5, 15)
#else
#error("Unsupported pointer bit width")
#endif

// These algorithms are valid for all Gregorian calendar dates
// corresponding to JDN ≥ 0.
//
Expand All @@ -54,8 +68,11 @@ public struct GregorianCalendar: Calendar {
// https://doi.org/10.1145/364096.364097

public static func julianDayNumberFromDate(_ date: DateType) -> JulianDayNumber {
// Years greater than maxY cause arithmetic overflow
// when computing J even when the final result is ≤ .max
// guard date <= upperLimit else { return .max }
// guard date >= lowerLimit else { return .min }

// Years greater than `maxY` cause arithmetic overflow
// when computing `J` even when the final result is ≤ `.max`
// N.B. this is an estimated upper bound
let maxY = .max / 1461 - 4800

Expand All @@ -75,7 +92,6 @@ public struct GregorianCalendar: Calendar {
Y += cycles * recurrenceCycle.years + recurrenceCycle.years
}

// precondition((Y, date.month, date.day) >= minDate)
var J = (1461 * (Y + 4800 + (date.month - 14) / 12)) / 4
+ (367 * (date.month - 2 - 12 * ((date.month - 14) / 12))) / 12
- (3 * ((Y + 4900 + (date.month - 14) / 12) / 100)) / 4
Expand All @@ -94,8 +110,8 @@ public struct GregorianCalendar: Calendar {
}

public static func dateFromJulianDayNumber(_ JD: JulianDayNumber) -> DateType {
// JDN values greater than maxJD cause arithmetic overflow
// when computing L
// JDN values greater than `maxJD` cause arithmetic overflow
// when computing `L`
let maxJD = .max - 68569

var JD = JD
Expand All @@ -109,7 +125,6 @@ public struct GregorianCalendar: Calendar {
JD = recurrenceCycle.days + qr.remainder
}

// precondition(JD >= minJD)
var L = JD + 68569
let N = (4 * L) / 146097
L = L - (146097 * N + 3) / 4
Expand Down
27 changes: 21 additions & 6 deletions Sources/JulianDayNumber/JulianCalendar.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,20 @@ public struct JulianCalendar: Calendar {
/// The Julian calendar date corresponding to JDN 0.
static let jdnZero: DateType = (-4712, 1, 1)

#if _pointerBitWidth(_64)
// The Julian calendar date corresponding to JDN `Int64.max`
static let upperLimit: DateType = (25252216391110348, 5, 22)
// The Julian calendar date corresponding to JDN `Int64.min`
static let lowerLimit: DateType = (-25252216391119773, 8, 11)
#elseif _pointerBitWidth(_32)
// The Julian calendar date corresponding to JDN `Int32.max`
static let upperLimit: DateType = (5874777, 10, 17)
// The Julian calendar date corresponding to JDN `Int32.min`
static let lowerLimit: DateType = (-5884202, 3, 16)
#else
#error("Unsupported pointer bit width")
#endif

// These algorithms are valid for all Julian calendar dates
// corresponding to JDN ≥ 0.
//
Expand All @@ -49,8 +63,11 @@ public struct JulianCalendar: Calendar {
// held at the Jet Propulsion Laboratory in 1970.

public static func julianDayNumberFromDate(_ date: DateType) -> JulianDayNumber {
// Years greater than maxY cause arithmetic overflow
// when computing J even when the final result is ≤ .max
// guard date <= upperLimit else { return .max }
// guard date >= lowerLimit else { return .min }

// Years greater than `maxY` cause arithmetic overflow
// when computing `J` even when the final result is ≤ `.max`
let maxY = .max / 367

var Y = date.year
Expand All @@ -69,7 +86,6 @@ public struct JulianCalendar: Calendar {
Y += cycles * recurrenceCycle.years + recurrenceCycle.years
}

// precondition(Y >= minY)
var J = 367 * Y
- (7 * (Y + 5001 + (date.month - 9) / 7)) / 4
+ (275 * date.month) / 9
Expand All @@ -88,8 +104,8 @@ public struct JulianCalendar: Calendar {
}

public static func dateFromJulianDayNumber(_ JD: JulianDayNumber) -> DateType {
// JDN values greater than maxJD cause arithmetic overflow
// when computing J
// JDN values greater than `maxJD` cause arithmetic overflow
// when computing `J`
let maxJD = .max - 1402

var JD = JD
Expand All @@ -103,7 +119,6 @@ public struct JulianCalendar: Calendar {
JD = recurrenceCycle.days + qr.remainder
}

// precondition(JD >= 0)
var J = JD + 1402
let K = (J - 1) / 1461
let L = J - 1461 * K
Expand Down