Skip to content

Commit

Permalink
Add accessors and conversions to other time types
Browse files Browse the repository at this point in the history
  • Loading branch information
helgee committed Aug 6, 2018
1 parent 03edb1e commit 572eea0
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 34 deletions.
56 changes: 55 additions & 1 deletion src/AstroDates.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ module AstroDates

using ..TimeScales: TimeScale

import Base: time
import Dates

export Date, Time, DateTime,
year, month, day, j2000day, calendar,
hour, minute, second
hour, minute, second, date, time

abstract type Calendar end

Expand Down Expand Up @@ -137,6 +140,10 @@ function Date(offset)
Date{calendar}(year, month, day)
end

function Date(epoch, offset)
Date(j2000day(epoch) + offset)
end

function Date(year, month, day)
check = Date(j2000day(year, month, day))
if check.year != year || check.month != month || check.day != day
Expand All @@ -150,6 +157,9 @@ month(s::Date) = s.month
day(s::Date) = s.day
calendar(s::Date{C}) where {C} = C

Date(d::Dates.Date) = Date(Dates.year(d), Dates.month(d), Dates.day(d))
Dates.Date(d::Date) = Dates.Date(year(d), month(d), day(d))

function j2000day(calendar::Calendar, year, month, day)
last_j2000_dayofyear(calendar, year - 1) + finddayinyear(month, day, isleap(calendar, year))
end
Expand All @@ -168,6 +178,8 @@ const CCSDS_EPOCH = Date(1958, 1, 1)
const GALILEO_EPOCH = Date(1999, 8, 22)
const GPS_EPOCH = Date(1980, 1, 6)
const J2000_EPOCH = Date(2000, 1, 1)
const MIN_EPOCH = Date(typemin(Int64))
const MAX_EPOCH = Date(typemax(Int64))

struct Time
hour::Int
Expand All @@ -187,6 +199,29 @@ struct Time
end
end

function Time(second_in_day_a, second_in_day_b)
carry = floor(Int, second_in_day_b)
wholeseconds = second_in_day_a + carry
fractional = second_in_day_b - carry

# range check
if wholeseconds < 0 || wholeseconds > 86400
throw(ArgumentError("Seconds are out of range"))
end

# extract the time components
hour = wholeseconds ÷ 3600
wholeseconds -= 3600 * hour
minute = wholeseconds ÷ 60
wholeseconds -= 60 * minute
second = wholeseconds + fractional

Time(hour, minute, second)
end

Time(t::Dates.Time) = Time(Dates.hour(t), Dates.minute(t), Dates.second(t))
Dates.Time(t::Time) = Dates.Time(hour(t), minute(t), second(t))

const H00 = Time(0, 0, 0.0)
const H12 = Time(12, 0, 0.0)

Expand All @@ -199,5 +234,24 @@ struct DateTime{C}
time::Time
end

date(dt::DateTime) = dt.date
time(dt::DateTime) = dt.time

function DateTime(year, month, day, hour=0, minute=0, second=0.0)
DateTime(Date(year, month, day), Time(hour, minute, second))
end

year(dt::DateTime) = year(date(dt))
month(dt::DateTime) = month(date(dt))
day(dt::DateTime) = day(date(dt))
hour(dt::DateTime) = hour(time(dt))
minute(dt::DateTime) = minute(time(dt))
second(dt::DateTime) = second(time(dt))

DateTime(dt::Dates.DateTime) = DateTime(Dates.year(dt), Dates.month(dt), Dates.day(dt),
Dates.hour(dt), Dates.minute(dt), Dates.second(dt))
Dates.DateTime(dt::DateTime) = Dates.DateTime(year(dt), month(dt), day(dt),
hour(dt), minute(dt), second(dt))

end

51 changes: 18 additions & 33 deletions src/Epochs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ using ..TimeScales
using ..AstroDates
using ..Periods

export Epoch, -, julian, j2000,
JULIAN_EPOCH, J2000_EPOCH, MODIFIED_JULIAN_EPOCH, FIFTIES_EPOCH,
GALILEO_EPOCH, GPS_EPOCH, CCSDS_EPOCH
export Epoch,
JULIAN_EPOCH, J2000_EPOCH, MODIFIED_JULIAN_EPOCH,
FIFTIES_EPOCH, GALILEO_EPOCH, GPS_EPOCH, CCSDS_EPOCH

const OFFSET_TAI_TT = 32.184
const LG_RATE = 6.969290134e-10
Expand All @@ -24,6 +24,14 @@ struct Epoch{S, T}
Epoch{S}(epoch::Int64, offset::T) where {S, T} = new{S::TimeScale, T}(epoch, offset)
end

for scale in TimeScales.acronyms
epoch = Symbol(scale, "Epoch")
@eval begin
const $epoch = Epoch{$scale}
export $epoch
end
end

function Epoch{S}(epoch::Int64, offset, Δt) where S
sum = offset + Δt

Expand All @@ -44,6 +52,11 @@ function Epoch{S}(epoch::Int64, offset, Δt) where S
Epoch{S}(epoch′, offset′)
end

Epoch{S}(ep::Epoch{S}, Δt) where {S} = Epoch{S}(ep.epoch, ep.offset, Δt)

include("offsets.jl")
include("accessors.jl")

function Epoch{S}(date::Date, time::Time) where S
seconds = second(time)
ts_offset = tai_offset(S, date, time)
Expand All @@ -62,45 +75,17 @@ function Epoch{S}(date::Date, time::Time) where S
Epoch{S}(epoch, offset)
end

Epoch{S}(dt::DateTime) where {S} = Epoch{S}(date(dt), time(dt))

function Epoch{S}(year::Int, month::Int, day::Int, hour::Int=0, minute::Int=0, second::Float64=0.0) where S
Epoch{S}(Date(year, month, day), Time(hour, minute, second))
end

Epoch{S}(ep::Epoch{S}, Δt) where {S} = Epoch{S}(ep.epoch, ep.offset, Δt)

function Epoch{S2}(ep::Epoch{S1}) where {S1, S2}
Δt = tai_offset(S2, ep) - tai_offset(S1, ep)
Epoch{S2}(ep.epoch, ep.offset, Δt)
end

julian(ep::Epoch) = get(days(ep - JULIAN_EPOCH))
j2000(ep::Epoch) = get(days(ep - J2000_EPOCH))

tai_offset(::InternationalAtomicTime, ep) = 0.0
tai_offset(::TerrestrialTime, ep) = OFFSET_TAI_TT
tai_offset(::CoordinatedUniversalTime, ep) = offset_tai_utc(julian(ep))
tai_offset(::UniversalTime, ep) = tai_offset(UTC, ep) + getΔUT1(julian(ep))
tai_offset(::GeocentricCoordinateTime, ep) = tai_offset(TT, ep) + LG_RATE * get(ep - EPOCH_77)
tai_offset(::BarycentricCoordinateTime, ep) = tai_offset(TT, ep) + LB_RATE * get(ep - EPOCH_77)
function tai_offset(::BarycentricDynamicalTime, ep)
dt = get(days(ep - J2000_EPOCH))
g = 357.53 + 0.9856003dt
tai_offset(TT, ep) + 0.001658sind(g) + 0.000014sind(2g)
end

tai_offset(ep::Epoch{S}) where {S} = tai_offset(S, ep)

tai_offset(::InternationalAtomicTime, date, time) = 0.0

function tai_offset(scale, date, time)
ref = Epoch{TAI}(date, time)
offset = 0.0
for _ in 1:8
offset = -tai_offset(scale, Epoch{TAI}(ref, offset))
end
offset
end

function isapprox(a::Epoch, b::Epoch)
a.epoch == b.epoch && a.offset b.offset
end
Expand Down
63 changes: 63 additions & 0 deletions src/accessors.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import Dates

import ..AstroDates: DateTime, year, month, day, hour, minute, second

export julian, j2000, timescale

timescale(ep::Epoch{S}) where {S} = S

julian(ep::Epoch) = get(days(ep - JULIAN_EPOCH))
j2000(ep::Epoch) = get(days(ep - J2000_EPOCH))

function DateTime(ep::Epoch)
if !isfinite(ep.offset)
if ep.offset < 0
DateTime(AstroDates.MIN_EPOCH, AstroDates.H00)
else
DateTime(AstroDates.MAX_EPOCH, Time(23, 59, 59.999))
end
end

ts_offset = tai_offset(ep)
sum = ep.offset + ts_offset
o′ = sum - ts_offset
d′ = sum - o′
Δo = ep.offset - o′
Δd = ts_offset - d′
residual = Δo + Δd

carry = floor(Int64, sum)
offset2000B = (sum - carry) + residual
offset2000A = ep.epoch + carry + Int64(43200)
if offset2000B < 0
offset2000A -= 1
offset2000B += 1
end
time = offset2000A % Int64(86400)
if time < Int64(0)
time += Int64(86400)
end
date = Int((offset2000A - time) ÷ Int64(86400))

date_comp = Date(AstroDates.J2000_EPOCH, date)
time_comp = Time(time, offset2000B)

#= if (timeScale.insideLeap(this)) { =#
#= // fix the seconds number to take the leap into account =#
#= timeComponents = new TimeComponents(timeComponents.getHour(), timeComponents.getMinute(), =#
#= timeComponents.getSecond() + timeScale.getLeap(this)) =#
#= } =#

DateTime(date_comp, time_comp)
end

year(ep::Epoch) = year(DateTime(ep))
month(ep::Epoch) = month(DateTime(ep))
day(ep::Epoch) = day(DateTime(ep))
hour(ep::Epoch) = hour(DateTime(ep))
minute(ep::Epoch) = minute(DateTime(ep))
second(ep::Epoch) = second(DateTime(ep))

Dates.DateTime(ep::Epoch) = Dates.DateTime(DateTime(ep))
Epoch{S}(dt::Dates.DateTime) where {S} = Epoch{S}(DateTime(dt))

24 changes: 24 additions & 0 deletions src/offsets.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
tai_offset(::InternationalAtomicTime, ep) = 0.0
tai_offset(::TerrestrialTime, ep) = OFFSET_TAI_TT
tai_offset(::CoordinatedUniversalTime, ep) = offset_tai_utc(julian(ep))
tai_offset(::UniversalTime, ep) = tai_offset(UTC, ep) + getΔUT1(julian(ep))
tai_offset(::GeocentricCoordinateTime, ep) = tai_offset(TT, ep) + LG_RATE * get(ep - EPOCH_77)
tai_offset(::BarycentricCoordinateTime, ep) = tai_offset(TT, ep) + LB_RATE * get(ep - EPOCH_77)
function tai_offset(::BarycentricDynamicalTime, ep)
dt = get(days(ep - J2000_EPOCH))
g = 357.53 + 0.9856003dt
tai_offset(TT, ep) + 0.001658sind(g) + 0.000014sind(2g)
end

tai_offset(ep::Epoch{S}) where {S} = tai_offset(S, ep)

tai_offset(::InternationalAtomicTime, date, time) = 0.0

function tai_offset(scale, date, time)
ref = Epoch{TAI}(date, time)
offset = 0.0
for _ in 1:8
offset = -tai_offset(scale, Epoch{TAI}(ref, offset))
end
offset
end

0 comments on commit 572eea0

Please sign in to comment.