Skip to content
Open
Show file tree
Hide file tree
Changes from 9 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
1 change: 1 addition & 0 deletions .JuliaFormatter.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
style = "yas"
9 changes: 7 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
name = "TimeSpans"
uuid = "bb34ddd2-327f-4c4a-bfb0-c98fc494ece1"
authors = ["Beacon Biosignals, Inc."]
version = "0.3.1"
version = "0.4.0"
Copy link
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
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]
ArrowTypes = "31f734f8-188a-4ce0-8406-c8a06bd891cd"
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"

[compat]
julia = "1.6"
Arrow = "1.6"
ArrowTypes = "1.1.0"

[extras]
Arrow = "69666777-d1a9-59fb-9406-91d4454c9d45"
Tables = "bd369af6-aec1-5ad0-b16a-f7cc5008161c"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[targets]
test = ["Test"]
test = ["Arrow", "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. In addition to `TimeSpan`, this package implements the TimeSpans API for `Period`s and `NamedTuple`s that have `:start` and `:stop` keys.
12 changes: 11 additions & 1 deletion src/TimeSpans.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ module TimeSpans
using Base.Iterators
using Dates
using Statistics
using ArrowTypes

export TimeSpan, start, stop, istimespan, translate, overlaps,
shortest_timespan_containing, duration, index_from_time,
time_from_index, merge_spans!, merge_spans, invert_spans


const NS_IN_SEC = Dates.value(Nanosecond(Second(1))) # Number of nanoseconds in one second

#####
Expand Down Expand Up @@ -101,6 +101,7 @@ Types that overload `TimeSpans.start`/`TimeSpans.stop` should also overload `ist
istimespan(::Any) = false
istimespan(::TimeSpan) = true
istimespan(::Period) = true
istimespan(::T) where T <: NamedTuple = hasfield(T, :start) && hasfield(T, :stop)

"""
start(span)
Expand All @@ -109,6 +110,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::NamedTuple) = Nanosecond(x.start)

"""
stop(span)
Expand All @@ -117,6 +119,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::NamedTuple) = Nanosecond(x.stop)

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

# Support arrow serialization of timespans

const TIME_SPAN_ARROW_NAME = Symbol("JuliaLang.TimeSpan")

ArrowTypes.arrowname(::Type{TimeSpan}) = TIME_SPAN_ARROW_NAME
ArrowTypes.JuliaType(::Val{TIME_SPAN_ARROW_NAME}) = TimeSpan

end # module
38 changes: 37 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,39 @@ end
@test length(i_spans) == 6
@test all(duration.(i_spans) .== Second(8))
end

ntspan(a, b) = (;start=Nanosecond(a), stop=Nanosecond(b))
@testset "support named tuples" begin
@test index_from_time(100, (;start=Second(3), stop=Second(6))) == 301:600

for t in [(;start=Nanosecond(1), stop=Nanosecond(2)), (;stop=Second(1), start=Second(0))]
@test istimespan(t)
@test start(t) == Nanosecond(t.start)
@test stop(t) == Nanosecond(t.stop)
@test contains(t, t)
@test overlaps(t, t)
@test shortest_timespan_containing([t]) == TimeSpan(t)
@test duration(t) == Nanosecond(t.stop - t.start)
by = Second(rand(1:10))
@test translate(t, by) === TimeSpan(start(t) + Nanosecond(by), stop(t) + Nanosecond(by))
end

spans = [ntspan(0, 10), ntspan(6, 12), ntspan(15, 20),
ntspan(21, 30), ntspan(29, 31)]
# this could be fixed by defining
# Base.convert(::Type{<:NamedTuple}, x::TimeSpan) = (;start=start(x), stop=stop(x))
@test_broken merge_spans!(overlaps, 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
cols = (;span=TimeSpan(1, 2))
io = Arrow.tobuffer([cols])
spancol = first(Tables.columns(Arrow.Table(io)))
@test spancol isa AbstractVector{<:TimeSpan}
@test spancol == [cols.span]
end