From dd354c12734900b123c79db627ceff6ebdc53188 Mon Sep 17 00:00:00 2001 From: Morten Piibeleht Date: Mon, 26 Jun 2023 19:17:50 +1200 Subject: [PATCH] fix: fall back to UTC if `localzone()` fails (#7) * fix: fall back to UTC if localzone fails * move _localtz into a separate function * add changelog, set version to 0.1.2 * fix doctest env --- CHANGELOG.md | 8 +++++++- Project.toml | 2 +- docs/make.jl | 2 ++ src/JuliaHub.jl | 9 +++++++++ src/utils.jl | 16 ++++++++++++++-- test/utils.jl | 9 +++++---- 6 files changed, 38 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 524fe75a5..9f31139be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## Unreleased +## Version v0.1.2 - 2023-06-26 + +### Fixed + +* If TimeZones.jl fails to determine the system's timezone, JuliaHub.jl now gracefully falls back to UTC to represent dates and times. (#7) + +## Version v0.1.1 - 2023-06-24 ### Added diff --git a/Project.toml b/Project.toml index 9bf8dfc21..595f1b1cb 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "JuliaHub" uuid = "bc7fa6ce-b75e-4d60-89ad-56c957190b6e" authors = ["JuliaHub Inc."] -version = "0.1.1" +version = "0.1.2" [deps] Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" diff --git a/docs/make.jl b/docs/make.jl index 3bd838d33..a95ee325f 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,9 +1,11 @@ using JuliaHub using Documenter, DocumenterMermaid +import TimeZones # Timestamp printing is dependent on the timezone, so we force a specific (non-UTC) # timezone to make sure that the doctests don't fail because of timezone differences. ENV["TZ"] = "America/New_York" +JuliaHub._LOCAL_TZ[] = TimeZones.localzone() DocMeta.setdocmeta!( JuliaHub, :DocTestSetup, diff --git a/src/JuliaHub.jl b/src/JuliaHub.jl index 178094c55..7c4f8a20c 100644 --- a/src/JuliaHub.jl +++ b/src/JuliaHub.jl @@ -13,6 +13,8 @@ import TOML import URIs import UUIDs +const _LOCAL_TZ = Ref{Dates.TimeZone}() + include("utils.jl") include("authentication.jl") include("restapi.jl") @@ -28,4 +30,11 @@ 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 + end diff --git a/src/utils.jl b/src/utils.jl index 30d05369e..329812b87 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -350,7 +350,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, TimeZones.localzone()) + return TimeZones.astimezone(datetimez_utc, _LOCAL_TZ[]) end # Special version of _utc2localtz to handle integer ms timestamp function _ms_utc2localtz(timestamp::Integer)::TimeZones.ZonedDateTime @@ -397,5 +397,17 @@ function _parse_tz(timestamp_str::AbstractString; msg::Union{AbstractString, Not end throw(JuliaHubError(errmsg)) end - return TimeZones.astimezone(timestamp, TimeZones.localzone()) + return TimeZones.astimezone(timestamp, _LOCAL_TZ[]) +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" + end end diff --git a/test/utils.jl b/test/utils.jl index d571e555e..2bf370177 100644 --- a/test/utils.jl +++ b/test/utils.jl @@ -52,25 +52,26 @@ end end @testset "_parse_tz" begin + @test isassigned(JuliaHub._LOCAL_TZ) let t = JuliaHub._parse_tz("2022-10-12T05:30:31.1+00:00") @test t isa TimeZones.ZonedDateTime - @test t.timezone == TimeZones.localzone() + @test t.timezone == JuliaHub._LOCAL_TZ[] @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 == TimeZones.localzone() + @test t.timezone == JuliaHub._LOCAL_TZ[] @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 == TimeZones.localzone() + @test t.timezone == JuliaHub._LOCAL_TZ[] @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 == TimeZones.localzone() + @test t.timezone == JuliaHub._LOCAL_TZ[] @test Dates.millisecond(t) == 0 end @test_throws JuliaHub.JuliaHubError JuliaHub._parse_tz("")