Skip to content

Commit

Permalink
Allow additional parameters for custom time scales
Browse files Browse the repository at this point in the history
  • Loading branch information
helgee committed Feb 2, 2019
1 parent 3954604 commit 9da7878
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 40 deletions.
1 change: 1 addition & 0 deletions REQUIRE
@@ -1,5 +1,6 @@
julia 0.7
EarthOrientation 0.4.0
LeapSeconds 0.2.0
MacroTools 0.4.4
MuladdMacro 0.0.2
Reexport 0.1.0
58 changes: 43 additions & 15 deletions src/AstroTime.jl
Expand Up @@ -4,6 +4,7 @@ using EarthOrientation
using Reexport

import Dates
import MacroTools

export @timescale

Expand Down Expand Up @@ -116,33 +117,61 @@ function __init__()
end

"""
@timescale scale
@timescale scale epoch [args...] body
Define a new timescale and the corresponding `Epoch` type alias.
Define a new time scale, the corresponding `Epoch` type alias, and a function that calculates
the offset from TAI for the new time scale.
### Arguments ###
- `scale`: The name of the time scale
- `epoch`: The name of the `Epoch` parameter that is passed to the `tai_offset` function
- `args`: Optional additional parameters that are passed to the `tai_offset` function
- `body`: The body of the `tai_offset` function
# Example
```jldoctest
julia> @timescale GMT ep tai_offset(UTC, ep)
julia> GMT <: TimeScale
julia> GMT isa TimeScale
true
julia> GMTEpoch
Epoch{GMT,T} where T
```
"""
macro timescale(scale::Symbol, ep::Symbol, args...)
epoch = Expr(:escape, Symbol(scale, "Epoch"))
sc = Expr(:escape, scale)
scale_type = Symbol(scale, "Type")
epoch_type = Symbol(scale, "Epoch")
name = String(scale)
return quote
struct $sc <: TimeScale end
const $epoch = Epoch{$sc()}
Base.show(io::IO, $sc) = print(io, string(typeof($sc)))
AstroTime.TimeScales.tryparse(::Val{Symbol($name)}) = $sc()

Dates.CONVERSION_TRANSLATIONS[$epoch] = (
arglist = [
(nothing, scale_type, false, nothing),
(ep, Epoch, false, nothing),
]
body = args[end]
append!(arglist, MacroTools.splitarg.(args[1:end-1]))
args = map(x->MacroTools.combinearg(x...), arglist)
def = Dict{Symbol, Any}(
:name => :((AstroTime.Epochs).tai_offset),
:args => map(x->MacroTools.combinearg(x...), arglist),
:body => body,
:kwargs => Any[],
:whereparams => (),
)
func = esc(MacroTools.combinedef(def))

MacroTools.@esc scale scale_type epoch_type

MacroTools.@q begin
struct $scale_type <: TimeScale end
const $scale = $scale_type()
const $epoch_type = Epoch{$scale}
Base.show(io::IO, ::$scale_type) = print(io, $name)
AstroTime.TimeScales.tryparse(::Val{Symbol($name)}) = $scale

Dates.CONVERSION_TRANSLATIONS[$epoch_type] = (
Dates.Year,
Dates.Month,
Dates.Day,
Expand All @@ -151,10 +180,9 @@ macro timescale(scale::Symbol, ep::Symbol, args...)
Dates.Second,
Dates.Millisecond,
)
Dates.default_format(::Type{$epoch}) = Dates.ISODateTimeFormat
function AstroTime.Epochs.tai_offset(::$sc, $ep)
$(args[end])
end
Dates.default_format(::Type{$epoch_type}) = Dates.ISODateTimeFormat

$func

nothing
end
Expand Down
30 changes: 10 additions & 20 deletions src/Epochs.jl
Expand Up @@ -116,7 +116,7 @@ julia> Epoch{UTC}(2.451545e6, origin=:julian)
2000-01-01T12:00:00.000 UTC
```
"""
function Epoch{S}(jd1::T, jd2::T=zero(T); origin=:j2000) where {S, T<:Number}
function Epoch{S}(jd1::T, jd2::T=zero(T), args...; origin=:j2000) where {S, T<:Number}
if jd2 > jd1
jd1, jd2 = jd2, jd1
end
Expand Down Expand Up @@ -146,7 +146,7 @@ function Epoch{S}(jd1::T, jd2::T=zero(T); origin=:j2000) where {S, T<:Number}

ftype = float(T)
tai = Epoch{TAI}(epoch, ftype(offset), zero(ftype))
ts_offset = tai_offset(S, tai)
ts_offset = tai_offset(S, tai, args...)
ep = Epoch{TAI}(tai, -ts_offset)
Epoch{S}(ep.epoch, ep.offset, ts_offset)
end
Expand Down Expand Up @@ -285,9 +285,9 @@ include("accessors.jl")

show(io::IO, ep::Epoch{S}) where {S} = print(io, DateTime(ep), " ", S)

function Epoch{S}(date::Date, time::Time) where S
function Epoch{S}(date::Date, time::Time, args...) where S
seconds = second(Float64, time)
ts_offset = tai_offset(S, date, time)
ts_offset = tai_offset(S, date, time, args...)

sum = seconds + ts_offset
s′ = sum - ts_offset
Expand All @@ -300,7 +300,7 @@ 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
from_tai = tai_offset(S, Epoch{TAI}(epoch, offset, 0.0))
from_tai = tai_offset(S, Epoch{TAI}(epoch, offset, 0.0), args...)
Epoch{S}(epoch, offset, from_tai)
end

Expand Down Expand Up @@ -389,8 +389,8 @@ julia> Epoch{UTC}(2018, 2, 6)
```
"""
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))
minute::Int=0, second::Float64=0.0, args...) where S
Epoch{S}(Date(year, month, day), Time(hour, minute, second), args...)
end

function Epoch{S}(year::Int64, month::Int64, day::Int64, dayofyear::Int64,
Expand Down Expand Up @@ -419,7 +419,7 @@ function Epoch(year::Int64, month::Int64, day::Int64, dayofyear::Int64,
Epoch{scale}(date, Time(hour, minute, second + 1e-3milliseconds))
end

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

Expand All @@ -439,8 +439,8 @@ julia> TAIEpoch(ep)
1999-12-31T23:59:27.816 TAI
```
"""
function Epoch{S2}(ep::Epoch{S1}) where {S1, S2}
Epoch{S2}(ep.epoch, ep.offset, tai_offset(S2, ep))
function Epoch{S2}(ep::Epoch{S1}, args...) where {S1, S2}
Epoch{S2}(ep.epoch, ep.offset, tai_offset(S2, ep, args...))
end

Epoch{S, T}(ep::Epoch{S, T}) where {S, T} = ep
Expand Down Expand Up @@ -548,16 +548,6 @@ for scale in TimeScales.ACRONYMS
end
end

function TDBEpoch(ep::TTEpoch, ut, elong, u, v)
offset = tai_offset(TDB, ep, ut, elong, u, v)
TDBEpoch(ep, offset)
end

function TTEpoch(ep::TDBEpoch, ut, elong, u, v)
offset = tai_offset(TDB, ep, ut, elong, u, v)
TTEpoch(ep, offset)
end

include("leapseconds.jl")
include("range.jl")

Expand Down
10 changes: 5 additions & 5 deletions src/offsets.jl
Expand Up @@ -133,9 +133,9 @@ function tai_offset(::BarycentricDynamicalTime, ep, elong, u, v)
tai_offset(TT, ep) + w
end

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

@inline function tai_offset(::CoordinatedUniversalTime, date, time)
@inline function tai_offset(::CoordinatedUniversalTime, date::Date, time::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(julian(date) + correction)
Expand All @@ -144,12 +144,12 @@ tai_offset(::InternationalAtomicTime, date, time) = 0.0
getoffset(offset, date, time)
end

@inline function tai_offset(scale, date, time)
@inline function tai_offset(scale, date::Date, time::Time, args...)
ref = Epoch{TAI}(date, time)
offset = 0.0
# Maybe replace this with a simple convergence check
# TODO: Maybe replace this with a simple convergence check
for _ in 1:8
offset = -tai_offset(scale, Epoch{TAI}(ref, offset))
offset = -tai_offset(scale, Epoch{TAI}(ref, offset), args...)
end
offset
end
24 changes: 24 additions & 0 deletions test/runtests.jl
Expand Up @@ -4,9 +4,33 @@ using ERFA

AstroTime.update()

const speed_of_light = 299792458.0 # m/s
const astronomical_unit = 149597870700.0 # m

@timescale GMT ep tai_offset(UTC, ep)

@timescale SCET ep distance begin
tai_offset(UTC, ep) + distance / speed_of_light
end

@testset "AstroTime" begin
include("periods.jl")
include("astrodates.jl")
include("offsets.jl")
include("epochs.jl")
@testset "Custom Time Scales" begin
utc = UTCEpoch(2000, 1, 1, 0, 0, 0.1)
gmt = GMTEpoch(2000, 1, 1, 0, 0, 0.1)
@test utc == gmt

@test string(GMT) == "GMT"
@test typeof(GMT) == GMTType
@test string(gmt) == "2000-01-01T00:00:00.100 GMT"

@test string(SCET) == "SCET"
@test typeof(SCET) == SCETType
scet = SCETEpoch(2000, 1, 1, 0, 8, 19.10478383615643, astronomical_unit)
@test SCETEpoch(2000, 1, 1, 0, 8, 19.10478383615643, astronomical_unit) utc
@test SCETEpoch(value(j2000(scet)), 0.0, astronomical_unit) scet
end
end

0 comments on commit 9da7878

Please sign in to comment.