Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Demote UTC to I/O format and general overhaul #58

Merged
merged 26 commits into from
Apr 19, 2021
Merged

Demote UTC to I/O format and general overhaul #58

merged 26 commits into from
Apr 19, 2021

Conversation

helgee
Copy link
Member

@helgee helgee commented Mar 27, 2021

Boy, that escalated quickly!

I realize that this is a lot to review so I will leave comments inline to highlight the most important changes. Documentation updates will follow in a separate PR.

Fixes #50
Fixes #53

@helgee helgee changed the title [WIP] Demote UTC to I/O format Demote UTC to I/O format and general overhaul Apr 13, 2021
@helgee helgee marked this pull request as ready for review April 13, 2021 20:45
Copy link
Member

@giordano giordano left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked more the implementation than the merit of the changes 🙂


function findyear(calendar, j2000day::Int32)
function findyear(calendar, j2000day)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Am I correct to think we assume j2000day to be Union{Int32,Int64}? Or is it Int? If this is limited to Int32/Int64 it can also be Int64(j2000day) without any if*.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure about this. It seems that Int64(j2000day) allocates and I saw lots jl_box_int64 in my profiles. This is ugly but performance is an order of magnitude better: j2kday = ifelse(j2000day isa Int32, widen(j2000day), j2000day)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And it is Int so changes only with Sys.WORD_SIZE.

src/Epochs/offsets.jl Outdated Show resolved Hide resolved

function findyear(calendar, j2000day::Int32)
function findyear(calendar, j2000day)
j2kday = ifelse(j2000day isa Int32, widen(j2000day), j2000day)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Int64(<literal>) allocates apparently so this has a significant performance impact.

@@ -216,113 +175,235 @@ const UNIX_EPOCH = Date(1970, 1, 1)
struct Time{T}
hour::Int
minute::Int
second::T
second::Int
fraction::T
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed the representation of Time to have the same accuracy characteristics as Epoch. As a result, converting Epoch to AstroTime.DateTime and vice versa is losless. Dates.DateTime on the other hand is still limited to millisecond precision.


const H00 = Time(0, 0, 0.0)
const H12 = Time(12, 0, 0.0)
function subsecond(fraction, n, r)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This stumped me for a while. See also the method below. As a result, we now get sensible values for milli-/micro-/nanoseconds as if they were integral values and hiding the inherent floating point inaccuracies.

julia> subsecond(0.1839999999999975, 9)
0

julia> subsecond(0.1839999999999975, 3)
184

julia> subsecond(0.123456789, 9)
789

julia> subsecond(0.123456789, 3)
123

print(io, timescale(ep))
abstract type FractionOfSecondToken end

@inline function Dates.tryparsenext(d::Dates.DatePart{'f'}, str, i, len, locale)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can now parse timestamps with full Float64 precision by using the f field, e.g. dateformat"yyyy-mm-ddTHH:MM:SS.ffffffff. Thereby circumventing JuliaLang/julia#37579

src/Epochs/offsets.jl Outdated Show resolved Hide resolved
```
"""
@inline function getoffset(::CoordinatedUniversalTime, ::UniversalTime,
@inline function getoffset(::InternationalAtomicTime, ::UniversalTime,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UT1 is linked to TAI now.

const LEAP_TAI = LEAP_J2000 .+ round.(Int, LeapSeconds.LEAP_SECONDS) .- 1
const LEAP_TAI_SET = Set(LEAP_TAI)

function from_utc(str::AbstractString;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the headline change. There is no Epoch{UTC} anymore but we can still convert to/from UTC via the dedicated from_utc and to_utc. The discussion about this is in #50 (comment).

TL;DR: The Epoch data format is incompatible with a discontinuous timescale like UTC (and only UTC 👎 ). Thus, it makes no sense to rewrite the whole library and add a lot of edge cases for UTC. The best way of dealing with UTC and leap seconds is by keeping them on the outer edge of your code or pretend they do not exist like Google (https://github.com/google/unsmear). Friends do not let friends use UTC for mission-critical time keeping.


to_utc(ep, args...) = to_utc(String, ep, args...)

"""
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

now returns actual TAI (from UTC) instead of local time. No idea what will happen during a leap second though 😬

@test step(rng) == 13seconds
@test last(rng) == UTCEpoch(2018, 1, 1, 0, 0, 52.0)
end
@testset "Leap Seconds" begin
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of these become obsolete by removing UTC 😅

@timescale GMT UTC
AstroTime.Epochs.getoffset(::GMTScale, ::CoordinatedUniversalTime, _, _) = 0.0
AstroTime.Epochs.getoffset(::CoordinatedUniversalTime, ::GMTScale, _, _) = 0.0
# TODO: Change me
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These examples are not great anymore and I will try to come up with new ones during the doc update.

@helgee helgee merged commit 8e0936b into master Apr 19, 2021
@helgee helgee deleted the demote-utc branch July 4, 2021 12:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

now() returns local time as UTCEpoch instead of UTC Leap second handling is broken
2 participants