Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
6 changes: 4 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
name = "TimeSpans"
uuid = "bb34ddd2-327f-4c4a-bfb0-c98fc494ece1"
authors = ["Beacon Biosignals, Inc."]
version = "0.3.1"
version = "0.4.0"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I don't think this is breaking?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Based on the slack conversation we do want to be careful about how this is introduced re the pirated methods removed in beacon-biosignals/Onda.jl#126


[deps]
Arrow = "69666777-d1a9-59fb-9406-91d4454c9d45"
Comment thread
haberdashPI marked this conversation as resolved.
Outdated
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"

Expand All @@ -12,6 +13,7 @@ julia = "1.6"

[extras]
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
Tables = "bd369af6-aec1-5ad0-b16a-f7cc5008161c"

[targets]
test = ["Test"]
test = ["Test", "Tables"]
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
[![](https://img.shields.io/badge/docs-stable-blue.svg)](https://beacon-biosignals.github.io/TimeSpans.jl/stable)
[![](https://img.shields.io/badge/docs-dev-blue.svg)](https://beacon-biosignals.github.io/TimeSpans.jl/dev)

TimeSpans.jl provides a simple `TimeSpan` type for representing a continuous span between two points in time, along with generic utility functions for common operations on `TimeSpan`-like types. Importantly, the package exposes a minimal interface (`TimeSpans.start` and `TimeSpans.stop`) that any type can implement to enable support for the TimeSpans API.
TimeSpans.jl provides a simple `TimeSpan` type for representing a continuous span between two points in time, along with generic utility functions for common operations on `TimeSpan`-like types. Importantly, the package exposes a minimal interface (`TimeSpans.start` and `TimeSpans.stop`) that any type can implement to enable support for the TimeSpans API. NamedTuples of the form `(;start=Nanosecond(1), stop=Nanosecond(2))` are supported in many cases (all those where the function belongs to `TimeSpans`).
Comment thread
haberdashPI marked this conversation as resolved.
Outdated
16 changes: 15 additions & 1 deletion src/TimeSpans.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module TimeSpans
using Base.Iterators
using Dates
using Statistics
using Arrow

export TimeSpan, start, stop, istimespan, translate, overlaps,
shortest_timespan_containing, duration, index_from_time,
Expand Down Expand Up @@ -38,13 +39,16 @@ struct TimeSpan
TimeSpan(start, stop) = TimeSpan(Nanosecond(start), Nanosecond(stop))
end

# you can treat named as time spans for many operations
const NamedTupleTimeSpan = NamedTuple{(:start, :stop),Tuple{Nanosecond,Nanosecond}}
Base.convert(::Type{<:NamedTupleTimeSpan}, x::TimeSpan) = (;start=start(x), stop=stop(x))
Comment thread
haberdashPI marked this conversation as resolved.
Outdated

"""
TimeSpan(x)

Return `TimeSpan(start(x), stop(x))`.
"""
TimeSpan(x) = TimeSpan(start(x), stop(x))

Base.in(x::TimePeriod, y::TimeSpan) = start(y) <= x < stop(y)

# work around <https://github.com/JuliaLang/julia/issues/40311>:
Expand Down Expand Up @@ -101,6 +105,7 @@ Types that overload `TimeSpans.start`/`TimeSpans.stop` should also overload `ist
istimespan(::Any) = false
istimespan(::TimeSpan) = true
istimespan(::Period) = true
istimespan(::NamedTupleTimeSpan) = true

"""
start(span)
Expand All @@ -109,6 +114,7 @@ Return the inclusive lower bound of `span` as a `Nanosecond` value.
"""
start(span::TimeSpan) = span.start
start(t::Period) = convert(Nanosecond, t)
start(x::NamedTupleTimeSpan) = x.start

"""
stop(span)
Expand All @@ -117,6 +123,7 @@ Return the exclusive upper bound of `span` as a `Nanosecond` value.
"""
stop(span::TimeSpan) = span.stop
stop(t::Period) = convert(Nanosecond, t) + Nanosecond(1)
stop(x::NamedTupleTimeSpan) = x.stop

#####
##### generic utilities
Expand Down Expand Up @@ -388,4 +395,11 @@ function invert_spans(spans, parent_span)
return gaps
end

# Support arrow serialization of timespans

const TIME_SPAN_ARROW_NAME = Symbol("JuliaLang.TimeSpan")

Arrow.ArrowTypes.arrowname(::Type{TimeSpan}) = TIME_SPAN_ARROW_NAME
Comment thread
haberdashPI marked this conversation as resolved.
Outdated
ArrowTypes.JuliaType(::Val{TIME_SPAN_ARROW_NAME}) = TimeSpan

end # module
36 changes: 35 additions & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Test, TimeSpans, Dates
using Test, TimeSpans, Dates, Arrow, Tables

using TimeSpans: contains, nanoseconds_per_sample
using Statistics
Expand Down Expand Up @@ -221,3 +221,37 @@ end
@test length(i_spans) == 6
@test all(duration.(i_spans) .== Second(8))
end

ntspan(a, b) = (;start=Nanosecond(a), stop=Nanosecond(b))
Comment thread
haberdashPI marked this conversation as resolved.
Outdated
@testset "support named tuples" begin
t = (;start=Nanosecond(1), stop=Nanosecond(2))
@test index_from_time(100, (;start=Nanosecond(Second(3)), stop=Nanosecond(Second(6)))) == 301:600
@test istimespan(t)
@test start(t) == Nanosecond(1)
@test stop(t) == Nanosecond(2)
@test contains(t, t)
@test overlaps(t, t)
@test shortest_timespan_containing([t]) == TimeSpan(t)
@test duration(t) == Nanosecond(1)
by = Second(rand(1:10))
@test translate(t, by) === TimeSpan(start(t) + Nanosecond(by), stop(t) + Nanosecond(by))
spans = [ntspan(0, 10), ntspan(6, 12), ntspan(15, 20),
ntspan(21, 30), ntspan(29, 31)]
merge_spans!(overlaps, spans)
@test spans == [ntspan(0, 12), ntspan(15, 20), ntspan(21, 31)]

spans = [ntspan(Second(x), Second(x + 1)) for x in 0:10:59]
parent_span = ntspan(Second(0), Second(60))
i_spans = invert_spans(spans, parent_span)
@test length(i_spans) == 6
end

@testset "arrow serialization" begin
mktempdir() do dir
cols = (;span=TimeSpan(1, 2))
Arrow.write(joinpath(dir, "span.arrow"), [cols])
spancol = first(Tables.columns(Arrow.Table(joinpath(dir, "span.arrow"))))
@test spancol isa AbstractVector{<:TimeSpan}
@test spancol == [cols.span]
end
Comment thread
haberdashPI marked this conversation as resolved.
Outdated
end