Skip to content

Commit 8963f09

Browse files
authored
perf: do not initialize _LOCAL_TZ in __init__ (#88)
1 parent 2be4ecd commit 8963f09

File tree

4 files changed

+39
-22
lines changed

4 files changed

+39
-22
lines changed

src/JuliaHub.jl

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ import TOML
1313
import URIs
1414
import UUIDs
1515

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

1822
include("utils.jl")
@@ -31,13 +35,6 @@ include("jobs/logging.jl")
3135
include("jobs/logging-kafka.jl")
3236
include("jobs/logging-legacy.jl")
3337

34-
function __init__()
35-
# We'll only attempt to determine the local timezone once, when the package loads,
36-
# and store the result in a global. This way all timestamps will have consistent timezones
37-
# even if something in the environment changes.
38-
_LOCAL_TZ[] = _localtz()
39-
end
40-
4138
# JuliaHub.jl follows the convention that all private names are
4239
# prefixed with an underscore.
4340
function _find_public_names()

src/authentication.jl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,15 @@ end
259259
function _authenticate(
260260
server_uri::URIs.URI; force::Bool, maxcount::Integer, hook::Union{Base.Callable, Nothing}
261261
)
262+
# So this is a bit weird, but we want to ensure that the global _LOCAL_TZ[] is initialized
263+
# in a somewhat reliable way. Generally, constructing the authentication object is the first
264+
# thing that you do in a session, so we just call _localtz() here, even though we don't
265+
# need it. This will ensure that the _LOCAL_TZ[] timezone object "cache" is populated
266+
# as soon as you start using JuliaHub.jl, but _not_ when you load it, due to the effect
267+
# that has on load time -- this function is pretty heavy, so the _localtz() call is not
268+
# significant anyway.
269+
_localtz()
270+
262271
isnothing(hook) || PkgAuthentication.register_open_browser_hook(hook)
263272
try
264273
# _authenticate either returns a valid token, or throws

src/utils.jl

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ end
378378
_utc2localtz(timestamp::Number) = _utc2localtz(Dates.unix2datetime(timestamp))
379379
function _utc2localtz(datetime_utc::Dates.DateTime)::TimeZones.ZonedDateTime
380380
datetimez_utc = TimeZones.ZonedDateTime(datetime_utc, TimeZones.tz"UTC")
381-
return TimeZones.astimezone(datetimez_utc, _LOCAL_TZ[])
381+
return TimeZones.astimezone(datetimez_utc, _localtz())
382382
end
383383
# Special version of _utc2localtz to handle integer ms timestamp
384384
function _ms_utc2localtz(timestamp::Integer)::TimeZones.ZonedDateTime
@@ -427,17 +427,26 @@ function _parse_tz(timestamp_str::AbstractString; msg::Union{AbstractString, Not
427427
end
428428
throw(JuliaHubError(errmsg))
429429
end
430-
return TimeZones.astimezone(timestamp, _LOCAL_TZ[])
430+
return TimeZones.astimezone(timestamp, _localtz())
431431
end
432432

433-
# It's quite easy to make TimeZones.localzone() fail and throw.
434-
# So this wraps it, and adds a UTC fallback (which seems like the sensible
435-
# default) in the case where somehow the local timezone is not configured properly.
436-
function _localtz()
437-
try
438-
TimeZones.localzone()
439-
catch e
440-
@debug "Unable to determine local timezone" exception = (e, catch_backtrace())
441-
TimeZones.tz"UTC"
433+
# This function is internally used where we need to pass the local timezone
434+
# for datetime printing or parsing functions.
435+
function _localtz()::Dates.TimeZone
436+
global _LOCAL_TZ
437+
if isassigned(_LOCAL_TZ)
438+
return _LOCAL_TZ[]
439+
else
440+
# It's quite easy to make TimeZones.localzone() fail and throw.
441+
# So this wraps it, and adds a UTC fallback (which seems like the sensible
442+
# default) in the case where somehow the local timezone is not configured properly.
443+
tz = try
444+
TimeZones.localzone()
445+
catch e
446+
@debug "Unable to determine local timezone" exception = (e, catch_backtrace())
447+
TimeZones.tz"UTC"
448+
end
449+
_LOCAL_TZ[] = tz
450+
return tz
442451
end
443452
end

test/utils.jl

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,26 +52,28 @@ end
5252
end
5353

5454
@testset "_parse_tz" begin
55+
@test JuliaHub._localtz() isa Dates.TimeZone
5556
@test isassigned(JuliaHub._LOCAL_TZ)
57+
@test JuliaHub._localtz() === JuliaHub._LOCAL_TZ[]
5658
let t = JuliaHub._parse_tz("2022-10-12T05:30:31.1+00:00")
5759
@test t isa TimeZones.ZonedDateTime
58-
@test t.timezone == JuliaHub._LOCAL_TZ[]
60+
@test t.timezone == JuliaHub._localtz()
5961
@test Dates.millisecond(t) == 100
6062
end
6163
let t = JuliaHub._parse_tz("2022-10-12T05:30:31.12+00:00")
6264
@test t isa TimeZones.ZonedDateTime
63-
@test t.timezone == JuliaHub._LOCAL_TZ[]
65+
@test t.timezone == JuliaHub._localtz()
6466
@test Dates.millisecond(t) == 120
6567
end
6668
let t = JuliaHub._parse_tz("2022-10-12T05:30:31.123+00:00")
6769
@test t isa TimeZones.ZonedDateTime
68-
@test t.timezone == JuliaHub._LOCAL_TZ[]
70+
@test t.timezone == JuliaHub._localtz()
6971
@test Dates.millisecond(t) == 123
7072
end
7173
@test_throws JuliaHub.JuliaHubError JuliaHub._parse_tz("2022-10-12T05:30:31.+00:00")
7274
let t = JuliaHub._parse_tz("2022-10-12T05:30:31+00:00")
7375
@test t isa TimeZones.ZonedDateTime
74-
@test t.timezone == JuliaHub._LOCAL_TZ[]
76+
@test t.timezone == JuliaHub._localtz()
7577
@test Dates.millisecond(t) == 0
7678
end
7779
@test_throws JuliaHub.JuliaHubError JuliaHub._parse_tz("")

0 commit comments

Comments
 (0)