Skip to content
Merged
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
11 changes: 4 additions & 7 deletions src/JuliaHub.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ import TOML
import URIs
import UUIDs

# We cache the local timezone in a global, so that we don't have to call
# TimeZones.localzone() every time we do a TZ operation. However, we only
# populate this when we actually call _localtz(). We used to do this in __init_,
# but that caused a noticeable startup lag.
const _LOCAL_TZ = Ref{Dates.TimeZone}()

include("utils.jl")
Expand All @@ -31,13 +35,6 @@ include("jobs/logging.jl")
include("jobs/logging-kafka.jl")
include("jobs/logging-legacy.jl")

function __init__()
# We'll only attempt to determine the local timezone once, when the package loads,
# and store the result in a global. This way all timestamps will have consistent timezones
# even if something in the environment changes.
_LOCAL_TZ[] = _localtz()
end

# JuliaHub.jl follows the convention that all private names are
# prefixed with an underscore.
function _find_public_names()
Expand Down
9 changes: 9 additions & 0 deletions src/authentication.jl
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,15 @@ end
function _authenticate(
server_uri::URIs.URI; force::Bool, maxcount::Integer, hook::Union{Base.Callable, Nothing}
)
# So this is a bit weird, but we want to ensure that the global _LOCAL_TZ[] is initialized
# in a somewhat reliable way. Generally, constructing the authentication object is the first
# thing that you do in a session, so we just call _localtz() here, even though we don't
# need it. This will ensure that the _LOCAL_TZ[] timezone object "cache" is populated
# as soon as you start using JuliaHub.jl, but _not_ when you load it, due to the effect
# that has on load time -- this function is pretty heavy, so the _localtz() call is not
# significant anyway.
_localtz()

isnothing(hook) || PkgAuthentication.register_open_browser_hook(hook)
try
# _authenticate either returns a valid token, or throws
Expand Down
31 changes: 20 additions & 11 deletions src/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ end
_utc2localtz(timestamp::Number) = _utc2localtz(Dates.unix2datetime(timestamp))
function _utc2localtz(datetime_utc::Dates.DateTime)::TimeZones.ZonedDateTime
datetimez_utc = TimeZones.ZonedDateTime(datetime_utc, TimeZones.tz"UTC")
return TimeZones.astimezone(datetimez_utc, _LOCAL_TZ[])
return TimeZones.astimezone(datetimez_utc, _localtz())
end
# Special version of _utc2localtz to handle integer ms timestamp
function _ms_utc2localtz(timestamp::Integer)::TimeZones.ZonedDateTime
Expand Down Expand Up @@ -427,17 +427,26 @@ function _parse_tz(timestamp_str::AbstractString; msg::Union{AbstractString, Not
end
throw(JuliaHubError(errmsg))
end
return TimeZones.astimezone(timestamp, _LOCAL_TZ[])
return TimeZones.astimezone(timestamp, _localtz())
end

# It's quite easy to make TimeZones.localzone() fail and throw.
# So this wraps it, and adds a UTC fallback (which seems like the sensible
# default) in the case where somehow the local timezone is not configured properly.
function _localtz()
try
TimeZones.localzone()
catch e
@debug "Unable to determine local timezone" exception = (e, catch_backtrace())
TimeZones.tz"UTC"
# This function is internally used where we need to pass the local timezone
# for datetime printing or parsing functions.
function _localtz()::Dates.TimeZone
global _LOCAL_TZ
if isassigned(_LOCAL_TZ)
return _LOCAL_TZ[]
else
# It's quite easy to make TimeZones.localzone() fail and throw.
# So this wraps it, and adds a UTC fallback (which seems like the sensible
# default) in the case where somehow the local timezone is not configured properly.
tz = try
TimeZones.localzone()
catch e
@debug "Unable to determine local timezone" exception = (e, catch_backtrace())
TimeZones.tz"UTC"
end
_LOCAL_TZ[] = tz
return tz
end
end
10 changes: 6 additions & 4 deletions test/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -52,26 +52,28 @@ end
end

@testset "_parse_tz" begin
@test JuliaHub._localtz() isa Dates.TimeZone
@test isassigned(JuliaHub._LOCAL_TZ)
@test JuliaHub._localtz() === JuliaHub._LOCAL_TZ[]
let t = JuliaHub._parse_tz("2022-10-12T05:30:31.1+00:00")
@test t isa TimeZones.ZonedDateTime
@test t.timezone == JuliaHub._LOCAL_TZ[]
@test t.timezone == JuliaHub._localtz()
@test Dates.millisecond(t) == 100
end
let t = JuliaHub._parse_tz("2022-10-12T05:30:31.12+00:00")
@test t isa TimeZones.ZonedDateTime
@test t.timezone == JuliaHub._LOCAL_TZ[]
@test t.timezone == JuliaHub._localtz()
@test Dates.millisecond(t) == 120
end
let t = JuliaHub._parse_tz("2022-10-12T05:30:31.123+00:00")
@test t isa TimeZones.ZonedDateTime
@test t.timezone == JuliaHub._LOCAL_TZ[]
@test t.timezone == JuliaHub._localtz()
@test Dates.millisecond(t) == 123
end
@test_throws JuliaHub.JuliaHubError JuliaHub._parse_tz("2022-10-12T05:30:31.+00:00")
let t = JuliaHub._parse_tz("2022-10-12T05:30:31+00:00")
@test t isa TimeZones.ZonedDateTime
@test t.timezone == JuliaHub._LOCAL_TZ[]
@test t.timezone == JuliaHub._localtz()
@test Dates.millisecond(t) == 0
end
@test_throws JuliaHub.JuliaHubError JuliaHub._parse_tz("")
Expand Down
Loading