Skip to content

Commit 9a7deb9

Browse files
authored
feat: Relax UnixTime construction from String (#19)
1 parent 73e00e3 commit 9a7deb9

3 files changed

Lines changed: 58 additions & 11 deletions

File tree

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "UnixTimes"
22
uuid = "ab1a18e7-b408-4913-896c-624bb82ed7f4"
33
authors = ["Christian Rorvik <christian.rorvik@gmail.com>"]
4-
version = "1.7.2"
4+
version = "1.8.0"
55

66
[deps]
77
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"

src/UnixTimes.jl

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,21 +63,44 @@ UnixTime(x::Date, y::Time) =
6363
const DATEFORMAT = dateformat"yyyy-mm-ddTHH:MM:SS.sss"
6464

6565
function UnixTime(s::AbstractString)
66-
try
67-
@assert length(s) == 29
68-
dt = DateTime(chop(s; tail=6), DATEFORMAT)
69-
ns = Nanosecond(parse(Int, last(s, 6)))
70-
UnixTime(dt) + ns
71-
catch
72-
throw(ArgumentError("Invalid UnixTime string"))
66+
# Find the decimal point if it exists
67+
dot_idx = findfirst('.', s)
68+
69+
# No fractional seconds, parse as DateTime
70+
isnothing(dot_idx) && return UnixTime(DateTime(s, DATEFORMAT))
71+
72+
# Split into datetime and fractional parts
73+
dt_part = @view s[1:(dot_idx - 1)]
74+
frac_part = @view s[(dot_idx + 1):end]
75+
76+
# Parse the datetime part
77+
dt = DateTime(dt_part, DATEFORMAT)
78+
79+
# Parse fractional seconds (can be 1-9 digits)
80+
if isempty(frac_part) || !all(isdigit, frac_part)
81+
throw(ArgumentError("Invalid fractional seconds in UnixTime string"))
7382
end
83+
84+
# Convert fractional seconds to nanoseconds
85+
# Pad or truncate to 9 digits (nanosecond precision)
86+
frac_digits = length(frac_part)
87+
ns_value = if frac_digits <= 9
88+
parse(Int, frac_part) * 10^(9 - frac_digits)
89+
else
90+
parse(Int, frac_part[1:9])
91+
end
92+
93+
return UnixTime(dt) + Nanosecond(ns_value)
7494
end
7595

7696
function Base.convert(::Type{UnixTime}, x::DateTime)
7797
instant_ns = (Dates.value(x) - Dates.UNIXEPOCH) * 1_000_000
7898
UnixTime(Dates.UTInstant(Nanosecond(instant_ns)))
7999
end
80100

101+
# Promotion rules for comparing UnixTime with DateTime
102+
Base.promote_rule(::Type{UnixTime}, ::Type{DateTime}) = UnixTime
103+
81104
function Base.show(io::IO, x::UnixTime)
82105
xdt = convert(DateTime, x)
83106
print(io, Dates.format(xdt, DATEFORMAT))

test/runtests.jl

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,22 @@ end
4848
x = UnixTime(2020, 1, 2, 3, 4, 5, 6, 7, 8)
4949
@test string(x) == "2020-01-02T03:04:05.006007008"
5050
@test UnixTime(string(x)) == x
51-
@test_throws ArgumentError UnixTime("2025-01-28T15:49:36.5901397023")
52-
@test_throws ArgumentError UnixTime("2025-01-28T15:49:36.59013970")
53-
@test_throws ArgumentError UnixTime(repeat("a", 29))
51+
52+
# Test various string formats
53+
@test UnixTime("2020-01-02T03:04:05") == UnixTime(2020, 1, 2, 3, 4, 5)
54+
@test UnixTime("2020-01-02T03:04:05.1") == UnixTime(2020, 1, 2, 3, 4, 5, 100)
55+
@test UnixTime("2020-01-02T03:04:05.12") == UnixTime(2020, 1, 2, 3, 4, 5, 120)
56+
@test UnixTime("2020-01-02T03:04:05.123") == UnixTime(2020, 1, 2, 3, 4, 5, 123)
57+
@test UnixTime("2020-01-02T03:04:05.1234") == UnixTime(2020, 1, 2, 3, 4, 5, 123, 400)
58+
@test UnixTime("2020-01-02T03:04:05.123456") == UnixTime(2020, 1, 2, 3, 4, 5, 123, 456)
59+
@test UnixTime("2020-01-02T03:04:05.123456789") == UnixTime(2020, 1, 2, 3, 4, 5, 123, 456, 789)
60+
61+
# Test truncation of extra digits
62+
@test UnixTime("2020-01-02T03:04:05.1234567890") == UnixTime(2020, 1, 2, 3, 4, 5, 123, 456, 789)
63+
64+
# Test invalid formats
65+
@test_throws ArgumentError UnixTime("2020-01-02T03:04:05.")
66+
@test_throws ArgumentError UnixTime("2020-01-02T03:04:05.abc")
5467
end
5568

5669
@testset "arithmetic" begin
@@ -102,4 +115,15 @@ end
102115
@test collect(t1:p:t2) isa Vector
103116
end
104117

118+
@testset "comparison with DateTime" begin
119+
ut = UnixTime(2001, 03, 21, 13, 10, 0, 0)
120+
dt = DateTime("2001-03-21T13:10:00")
121+
122+
@test ut == dt
123+
@test ut > DateTime("2001-03-21T13:00:00")
124+
@test ut < DateTime("2001-03-21T13:20:00")
125+
@test DateTime("2001-03-21T13:20:00") > ut
126+
@test UnixTime(2001, 03, 21, 13, 10, 0, 114, 549, 673) > dt
127+
end
128+
105129
end

0 commit comments

Comments
 (0)