Skip to content

Commit

Permalink
Add JD constructor; save TAI offset in struct
Browse files Browse the repository at this point in the history
  • Loading branch information
helgee committed Aug 28, 2018
1 parent 3d5e8f6 commit 35a369b
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 33 deletions.
97 changes: 77 additions & 20 deletions src/Epochs.jl
Expand Up @@ -20,15 +20,18 @@ export Epoch,
JULIAN_EPOCH, J2000_EPOCH, MODIFIED_JULIAN_EPOCH,
FIFTIES_EPOCH, GALILEO_EPOCH, GPS_EPOCH, CCSDS_EPOCH,
PAST_INFINITY, FUTURE_INFINITY, UNIX_EPOCH,
julian, j2000, julian_split, modified_julian
julian, j2000, julian_split, modified_julian, now

struct Epoch{S, T} <: Dates.AbstractDateTime
epoch::Int64
offset::T
Epoch{S}(epoch::Int64, offset::T) where {S, T} = new{S::TimeScale, T}(epoch, offset)
ts_offset::T
function Epoch{S}(epoch::Int64, offset::T, ts_offset::T) where {S, T}
new{S::TimeScale, T}(epoch, offset, ts_offset)
end
end

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

if !isfinite(sum)
Expand All @@ -45,11 +48,45 @@ function Epoch{S}(epoch::Int64, offset, Δt) where S
epoch′ = epoch + dl
end

Epoch{S}(epoch′, offset′)
Epoch{S}(epoch′, offset′, ts_offset)
end

function Epoch{S}(jd1::T, jd2::T=zero(T); epoch=:j2000) where {S, T}
if jd2 > jd1
jd1, jd2 = jd2, jd1
end

if epoch == :j2000
# pass
elseif epoch == :julian
jd1 -= J2000_TO_JULIAN
elseif epoch == :mjd
jd1 -= J2000_TO_MJD
else
throw(ArgumentError("Unknown Julian epoch: $epoch"))
end

jd1 *= SECONDS_PER_DAY
jd2 *= SECONDS_PER_DAY

sum = jd1 + jd2

o′ = sum - jd2
d′ = sum - o′
Δ0 = jd1 - o′
Δd = jd2 - d′
residual = Δ0 + Δd
epoch = floor(Int64, sum)
offset = (sum - epoch) + residual

ftype = float(T)

ts_offset = tai_offset(S, Epoch{TAI}(epoch, ftype(offset), zero(ftype)))
Epoch{S}(epoch, offset, ts_offset)
end

"""
Epoch{S}(ep::Epoch, Δt) where S
Epoch{S}(ep::Epoch{S}, Δt) where S
Construct a new `Epoch` with time scale `S` which is `ep` shifted by `Δt`
seconds.
Expand All @@ -64,25 +101,30 @@ julia> UTCEpoch(ep, 20.0)
2018-02-06T20:45:20.000 UTC
```
"""
Epoch{S}(ep::Epoch, Δt) where {S} = Epoch{S}(ep.epoch, ep.offset, Δt)
Epoch{S}(ep::Epoch{S}, Δt) where {S} = Epoch{S}(ep.epoch, ep.offset, ep.ts_offset, Δt)

function j2000(scale, ep::Epoch)
(ep.offset + tai_offset(scale, ep) + ep.epoch) / SECONDS_PER_DAY
function j2000(ep::Epoch, tai_offset)
(ep.offset + tai_offset + ep.epoch) / SECONDS_PER_DAY
end
julian(scale, ep::Epoch) = j2000(scale, ep) + J2000_TO_JULIAN
modified_julian(scale, ep::Epoch) = j2000(scale, ep) + J2000_TO_MJD
julian(ep::Epoch, tai_offset) = j2000(ep, tai_offset) + J2000_TO_JULIAN
modified_julian(ep::Epoch, tai_offset) = j2000(ep, tai_offset) + J2000_TO_MJD

function julian_split(scale, ep::Epoch)
jd = julian(scale, ep)
function julian_split(ep::Epoch, tai_offset)
jd = julian(ep, tai_offset)
jd1 = trunc(jd)
jd2 = jd - jd1
jd1, jd2
end

j2000(ep::Epoch{S}) where {S} = j2000(S, ep)
julian(ep::Epoch{S}) where {S} = julian(S, ep)
modified_julian(ep::Epoch{S}) where {S} = modified_julian(S, ep)
julian_split(ep::Epoch{S}) where {S} = julian_split(S, ep)
j2000(ep::Epoch) = j2000(ep, ep.ts_offset)
julian(ep::Epoch) = julian(ep, ep.ts_offset)
modified_julian(ep::Epoch) = modified_julian(ep, ep.ts_offset)
julian_split(ep::Epoch) = julian_split(ep, ep.ts_offset)

j2000(scale, ep::Epoch) = j2000(ep, tai_offset(scale, ep))
julian(scale, ep::Epoch) = julian(ep, tai_offset(scale, ep))
modified_julian(scale, ep::Epoch) = modified_julian(ep, tai_offset(scale, ep))
julian_split(scale, ep::Epoch) = julian_split(ep, tai_offset(scale, ep))

include("offsets.jl")
include("accessors.jl")
Expand All @@ -104,21 +146,30 @@ function Epoch{S}(date::Date, time::Time) where S
offset = (sum - dl) + residual
epoch = Int64(60) * ((j2000(date) * Int64(24) + hour(time)) * Int64(60)
+ minute(time) - Int64(720)) + dl
Epoch{S}(epoch, offset)
from_tai = tai_offset(S, Epoch{TAI}(epoch, offset, 0.0))
Epoch{S}(epoch, offset, from_tai)
end

Epoch(str::AbstractString, df::Dates.DateFormat=ISOEpochFormat) = parse(Epoch, str, df)
Epoch(str::AbstractString, format::Dates.DateFormat=ISOEpochFormat) = parse(Epoch, str, format)

Epoch(str::AbstractString, format::AbstractString) = Epoch(str, Dates.DateFormat(format))

Epoch{S}(str::AbstractString,
df::Dates.DateFormat=Dates.default_format(Epoch{S})) where {S} = parse(Epoch{S}, str, df)
format::Dates.DateFormat=Dates.default_format(Epoch{S})) where {S} = parse(Epoch{S}, str, format)

Epoch{S}(str::AbstractString, format::AbstractString) where {S} = Epoch{S}(str, Dates.DateFormat(format))

Epoch{S}(d::Date) where {S} = Epoch{S}(d, AstroDates.H00)

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

"""
now()
Get the current date and time as a `UTCEpoch`.
"""
now() = UTCEpoch(Dates.now())

function Epoch{S}(year::Int, month::Int, day::Int, hour::Int=0,
minute::Int=0, second::Float64=0.0) where S
Expand All @@ -136,7 +187,13 @@ function Epoch(year::Int, month::Int, day::Int, hour::Int,
Epoch{scale}(Date(year, month, day), Time(hour, minute, second + 1e-3milliseconds))
end

Epoch{S2}(ep::Epoch{S1}) where {S1, S2} = Epoch{S2}(ep.epoch, ep.offset)
function Epoch{S2}(ep::Epoch{S1}, ts_offset) where {S1, S2}
Epoch{S2}(ep.epoch, ep.offset, ts_offset)
end

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

function isapprox(a::Epoch, b::Epoch)
a.epoch == b.epoch && a.offset b.offset
Expand Down
8 changes: 3 additions & 5 deletions src/accessors.jl
Expand Up @@ -17,12 +17,11 @@ function DateTime(ep::Epoch)
end
end

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

carry = floor(Int64, sum)
Expand Down Expand Up @@ -65,5 +64,4 @@ date(ep::Epoch) = date(DateTime(ep))
fractionofday(ep::Epoch) = fractionofday(time(ep))

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

8 changes: 3 additions & 5 deletions src/leapseconds.jl
@@ -1,4 +1,3 @@
import Dates
using LeapSeconds

export insideleap, getleap
Expand Down Expand Up @@ -52,10 +51,9 @@ const DRIFT_RATES = [LeapSeconds.DRIFT_RATES;
zeros(length(LeapSeconds.LS_EPOCHS))]

for (ep, offset, dep, rate) in zip(EPOCHS, OFFSETS, DRIFT_EPOCHS, DRIFT_RATES)
dt = DateTime(Dates.julian2datetime(ep + LeapSeconds.MJD_EPOCH))
tai = TAIEpoch(dt)
previous = isempty(TAI_OFFSETS) ? 0.0 : getoffset(last(TAI_OFFSETS), date(dt), AstroDates.H00)
ref = TAIEpoch(TAIEpoch(Dates.julian2datetime(dep + LeapSeconds.MJD_EPOCH)), offset)
tai = TAIEpoch(ep, epoch=:mjd)
previous = isempty(TAI_OFFSETS) ? 0.0 : getoffset(last(TAI_OFFSETS), date(tai), AstroDates.H00)
ref = TAIEpoch(TAIEpoch(dep, epoch=:mjd), offset)
start = TAIEpoch(tai, previous)
start_offset = offset + (ep - dep) * rate
stop = TAIEpoch(tai, start_offset)
Expand Down
6 changes: 3 additions & 3 deletions src/offsets.jl
Expand Up @@ -8,7 +8,7 @@ const OFFSET_TAI_TT = 32.184
const LG_RATE = 6.969290134e-10
const LB_RATE = 1.550519768e-8

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

tai_offset(::InternationalAtomicTime, ep) = 0.0
tai_offset(::TerrestrialTime, ep) = OFFSET_TAI_TT
Expand Down Expand Up @@ -129,8 +129,8 @@ tai_offset(::InternationalAtomicTime, date, time) = 0.0

@inline function tai_offset(::CoordinatedUniversalTime, date, time)
minute_in_day = hour(time) * 60 + minute(time)
correction = minute_in_day < 0 ? (minute_in_day - 1439) ÷ 1440 : minute_in_day ÷ 1440
offset = findoffset(AstroDates.julian(date) + correction)
correction = minute_in_day < 0 ? (minute_in_day - 1439) ÷ 1440 : minute_in_day ÷ 1440
offset = findoffset(julian(date) + correction)
offset === nothing && return 0.0

getoffset(offset, date, time)
Expand Down
7 changes: 7 additions & 0 deletions test/epochs.jl
Expand Up @@ -51,12 +51,19 @@

@test before.epoch == 394372833
@test before.offset == 0.0
@test before.ts_offset == -34.0

@test start.epoch == 394372834
@test start.offset == 0.0
@test start.ts_offset == -35.0

@test during.epoch == 394372834
@test during.offset == 0.5
@test during.ts_offset == -35.0

@test after.epoch == 394372835
@test after.offset == 0.0
@test after.ts_offset == -35.0

@test !insideleap(before)
@test insideleap(start)
Expand Down

0 comments on commit 35a369b

Please sign in to comment.