time sequence stuff
This commit is contained in:
parent
73e3e439c5
commit
566d798b32
10 changed files with 438 additions and 72 deletions
15
seq/array.go
15
seq/array.go
|
@ -1,5 +1,7 @@
|
|||
package seq
|
||||
|
||||
import "time"
|
||||
|
||||
// NewArray creates a new array.
|
||||
func NewArray(values ...float64) Array {
|
||||
return Array(values)
|
||||
|
@ -17,3 +19,16 @@ func (a Array) Len() int {
|
|||
func (a Array) GetValue(index int) float64 {
|
||||
return a[index]
|
||||
}
|
||||
|
||||
// ArrayOfTimes wraps an array of times as a sequence provider.
|
||||
type ArrayOfTimes []time.Time
|
||||
|
||||
// Len returns the length of the array.
|
||||
func (aot ArrayOfTimes) Len() int {
|
||||
return len(aot)
|
||||
}
|
||||
|
||||
// GetValue returns the time at the given index as a time.Time.
|
||||
func (aot ArrayOfTimes) GetValue(index int) time.Time {
|
||||
return aot[index]
|
||||
}
|
||||
|
|
15
seq/provider.go
Normal file
15
seq/provider.go
Normal file
|
@ -0,0 +1,15 @@
|
|||
package seq
|
||||
|
||||
import "time"
|
||||
|
||||
// Provider is a provider for values for a seq.
|
||||
type Provider interface {
|
||||
Len() int
|
||||
GetValue(int) float64
|
||||
}
|
||||
|
||||
// TimeProvider is a provider for values for a seq.
|
||||
type TimeProvider interface {
|
||||
Len() int
|
||||
GetValue(int) time.Time
|
||||
}
|
|
@ -11,7 +11,7 @@ func RandomValues(count int) []float64 {
|
|||
return Seq{NewRandom().WithLen(count)}.Array()
|
||||
}
|
||||
|
||||
// RandomValuesWithAverage returns an array of random values with a given average.
|
||||
// RandomValuesWithMax returns an array of random values with a given average.
|
||||
func RandomValuesWithMax(count int, max float64) []float64 {
|
||||
return Seq{NewRandom().WithMax(max).WithLen(count)}.Array()
|
||||
}
|
||||
|
|
|
@ -15,12 +15,6 @@ func Values(values ...float64) Seq {
|
|||
return Seq{Provider: Array(values)}
|
||||
}
|
||||
|
||||
// Provider is a provider for values for a seq.
|
||||
type Provider interface {
|
||||
Len() int
|
||||
GetValue(int) float64
|
||||
}
|
||||
|
||||
// Seq is a utility wrapper for seq providers.
|
||||
type Seq struct {
|
||||
Provider
|
||||
|
@ -28,12 +22,13 @@ type Seq struct {
|
|||
|
||||
// Array enumerates the seq into a slice.
|
||||
func (s Seq) Array() (output []float64) {
|
||||
if s.Len() == 0 {
|
||||
slen := s.Len()
|
||||
if slen == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
output = make([]float64, s.Len())
|
||||
for i := 0; i < s.Len(); i++ {
|
||||
output = make([]float64, slen)
|
||||
for i := 0; i < slen; i++ {
|
||||
output[i] = s.GetValue(i)
|
||||
}
|
||||
return
|
||||
|
@ -149,7 +144,43 @@ func (s Seq) Sort() Seq {
|
|||
return s
|
||||
}
|
||||
values := s.Array()
|
||||
sort.Float64s(values)
|
||||
sort.Slice(values, func(i, j int) bool {
|
||||
return values[i] < values[j]
|
||||
})
|
||||
return Seq{Provider: Array(values)}
|
||||
}
|
||||
|
||||
// SortDescending returns the seq sorted in descending order.
|
||||
// This fully enumerates the seq.
|
||||
func (s Seq) SortDescending() Seq {
|
||||
if s.Len() == 0 {
|
||||
return s
|
||||
}
|
||||
values := s.Array()
|
||||
sort.Slice(values, func(i, j int) bool {
|
||||
return values[i] > values[j]
|
||||
})
|
||||
return Seq{Provider: Array(values)}
|
||||
}
|
||||
|
||||
// Reverse reverses the sequence's order.
|
||||
func (s Seq) Reverse() Seq {
|
||||
slen := s.Len()
|
||||
if slen == 0 {
|
||||
return s
|
||||
}
|
||||
|
||||
slen2 := slen >> 1
|
||||
values := s.Array()
|
||||
|
||||
i := 0
|
||||
j := slen - 1
|
||||
for i < slen2 {
|
||||
values[i], values[j] = values[j], values[i]
|
||||
i++
|
||||
j--
|
||||
}
|
||||
|
||||
return Seq{Provider: Array(values)}
|
||||
}
|
||||
|
64
seq/time.go
64
seq/time.go
|
@ -6,21 +6,12 @@ import (
|
|||
"github.com/wcharczuk/go-chart/util"
|
||||
)
|
||||
|
||||
// Time is a utility singleton with helper functions for time seq generation.
|
||||
var Time timeSequence
|
||||
// TimeUtil is a utility singleton with helper functions for time seq generation.
|
||||
var TimeUtil timeUtil
|
||||
|
||||
type timeSequence struct{}
|
||||
type timeUtil struct{}
|
||||
|
||||
// Days generates a seq of timestamps by day, from -days to today.
|
||||
func (ts timeSequence) Days(days int) []time.Time {
|
||||
var values []time.Time
|
||||
for day := days; day >= 0; day-- {
|
||||
values = append(values, time.Now().AddDate(0, 0, -day))
|
||||
}
|
||||
return values
|
||||
}
|
||||
|
||||
func (ts timeSequence) MarketHours(from, to time.Time, marketOpen, marketClose time.Time, isHoliday util.HolidayProvider) []time.Time {
|
||||
func (tu timeUtil) MarketHours(from, to time.Time, marketOpen, marketClose time.Time, isHoliday util.HolidayProvider) []time.Time {
|
||||
var times []time.Time
|
||||
cursor := util.Date.On(marketOpen, from)
|
||||
toClose := util.Date.On(marketClose, to)
|
||||
|
@ -41,7 +32,7 @@ func (ts timeSequence) MarketHours(from, to time.Time, marketOpen, marketClose t
|
|||
return times
|
||||
}
|
||||
|
||||
func (ts timeSequence) MarketHourQuarters(from, to time.Time, marketOpen, marketClose time.Time, isHoliday util.HolidayProvider) []time.Time {
|
||||
func (tu timeUtil) MarketHourQuarters(from, to time.Time, marketOpen, marketClose time.Time, isHoliday util.HolidayProvider) []time.Time {
|
||||
var times []time.Time
|
||||
cursor := util.Date.On(marketOpen, from)
|
||||
toClose := util.Date.On(marketClose, to)
|
||||
|
@ -62,7 +53,7 @@ func (ts timeSequence) MarketHourQuarters(from, to time.Time, marketOpen, market
|
|||
return times
|
||||
}
|
||||
|
||||
func (ts timeSequence) MarketDayCloses(from, to time.Time, marketOpen, marketClose time.Time, isHoliday util.HolidayProvider) []time.Time {
|
||||
func (tu timeUtil) MarketDayCloses(from, to time.Time, marketOpen, marketClose time.Time, isHoliday util.HolidayProvider) []time.Time {
|
||||
var times []time.Time
|
||||
cursor := util.Date.On(marketOpen, from)
|
||||
toClose := util.Date.On(marketClose, to)
|
||||
|
@ -78,7 +69,7 @@ func (ts timeSequence) MarketDayCloses(from, to time.Time, marketOpen, marketClo
|
|||
return times
|
||||
}
|
||||
|
||||
func (ts timeSequence) MarketDayAlternateCloses(from, to time.Time, marketOpen, marketClose time.Time, isHoliday util.HolidayProvider) []time.Time {
|
||||
func (tu timeUtil) MarketDayAlternateCloses(from, to time.Time, marketOpen, marketClose time.Time, isHoliday util.HolidayProvider) []time.Time {
|
||||
var times []time.Time
|
||||
cursor := util.Date.On(marketOpen, from)
|
||||
toClose := util.Date.On(marketClose, to)
|
||||
|
@ -94,7 +85,7 @@ func (ts timeSequence) MarketDayAlternateCloses(from, to time.Time, marketOpen,
|
|||
return times
|
||||
}
|
||||
|
||||
func (ts timeSequence) MarketDayMondayCloses(from, to time.Time, marketOpen, marketClose time.Time, isHoliday util.HolidayProvider) []time.Time {
|
||||
func (tu timeUtil) MarketDayMondayCloses(from, to time.Time, marketOpen, marketClose time.Time, isHoliday util.HolidayProvider) []time.Time {
|
||||
var times []time.Time
|
||||
cursor := util.Date.On(marketClose, from)
|
||||
toClose := util.Date.On(marketClose, to)
|
||||
|
@ -109,7 +100,7 @@ func (ts timeSequence) MarketDayMondayCloses(from, to time.Time, marketOpen, mar
|
|||
return times
|
||||
}
|
||||
|
||||
func (ts timeSequence) Hours(start time.Time, totalHours int) []time.Time {
|
||||
func (tu timeUtil) Hours(start time.Time, totalHours int) []time.Time {
|
||||
times := make([]time.Time, totalHours)
|
||||
|
||||
last := start
|
||||
|
@ -122,13 +113,12 @@ func (ts timeSequence) Hours(start time.Time, totalHours int) []time.Time {
|
|||
}
|
||||
|
||||
// HoursFilled adds zero values for the data bounded by the start and end of the xdata array.
|
||||
func (ts timeSequence) HoursFilled(xdata []time.Time, ydata []float64) ([]time.Time, []float64) {
|
||||
start := Time.Start(xdata)
|
||||
end := Time.End(xdata)
|
||||
func (tu timeUtil) HoursFilled(xdata []time.Time, ydata []float64) ([]time.Time, []float64) {
|
||||
start, end := Times(xdata...).MinAndMax()
|
||||
|
||||
totalHours := util.Math.AbsInt(util.Date.DiffHours(start, end))
|
||||
|
||||
finalTimes := ts.Hours(start, totalHours+1)
|
||||
finalTimes := tu.Hours(start, totalHours+1)
|
||||
finalValues := make([]float64, totalHours+1)
|
||||
|
||||
var hoursFromStart int
|
||||
|
@ -139,33 +129,3 @@ func (ts timeSequence) HoursFilled(xdata []time.Time, ydata []float64) ([]time.T
|
|||
|
||||
return finalTimes, finalValues
|
||||
}
|
||||
|
||||
// Start returns the earliest (min) time in a list of times.
|
||||
func (ts timeSequence) Start(times []time.Time) time.Time {
|
||||
if len(times) == 0 {
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
start := times[0]
|
||||
for _, t := range times[1:] {
|
||||
if t.Before(start) {
|
||||
start = t
|
||||
}
|
||||
}
|
||||
return start
|
||||
}
|
||||
|
||||
// Start returns the earliest (min) time in a list of times.
|
||||
func (ts timeSequence) End(times []time.Time) time.Time {
|
||||
if len(times) == 0 {
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
end := times[0]
|
||||
for _, t := range times[1:] {
|
||||
if t.After(end) {
|
||||
end = t
|
||||
}
|
||||
}
|
||||
return end
|
||||
}
|
||||
|
|
261
seq/time_seq.go
Normal file
261
seq/time_seq.go
Normal file
|
@ -0,0 +1,261 @@
|
|||
package seq
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
// TimeZero is the zero time.
|
||||
TimeZero = time.Time{}
|
||||
)
|
||||
|
||||
// Times returns a new time sequence.
|
||||
func Times(values ...time.Time) TimeSeq {
|
||||
return TimeSeq{TimeProvider: ArrayOfTimes(values)}
|
||||
}
|
||||
|
||||
// TimeSeq is a sequence of times.
|
||||
type TimeSeq struct {
|
||||
TimeProvider
|
||||
}
|
||||
|
||||
// Array converts the sequence to times.
|
||||
func (ts TimeSeq) Array() (output []time.Time) {
|
||||
slen := ts.Len()
|
||||
if slen == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
output = make([]time.Time, slen)
|
||||
for i := 0; i < slen; i++ {
|
||||
output[i] = ts.GetValue(i)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Each applies the `mapfn` to all values in the value provider.
|
||||
func (ts TimeSeq) Each(mapfn func(int, time.Time)) {
|
||||
for i := 0; i < ts.Len(); i++ {
|
||||
mapfn(i, ts.GetValue(i))
|
||||
}
|
||||
}
|
||||
|
||||
// Map applies the `mapfn` to all values in the value provider,
|
||||
// returning a new seq.
|
||||
func (ts TimeSeq) Map(mapfn func(int, time.Time) time.Time) TimeSeq {
|
||||
output := make([]time.Time, ts.Len())
|
||||
for i := 0; i < ts.Len(); i++ {
|
||||
mapfn(i, ts.GetValue(i))
|
||||
}
|
||||
return TimeSeq{ArrayOfTimes(output)}
|
||||
}
|
||||
|
||||
// FoldLeft collapses a seq from left to right.
|
||||
func (ts TimeSeq) FoldLeft(mapfn func(i int, v0, v time.Time) time.Time) (v0 time.Time) {
|
||||
tslen := ts.Len()
|
||||
if tslen == 0 {
|
||||
return TimeZero
|
||||
}
|
||||
|
||||
if tslen == 1 {
|
||||
return ts.GetValue(0)
|
||||
}
|
||||
|
||||
v0 = ts.GetValue(0)
|
||||
for i := 1; i < tslen; i++ {
|
||||
v0 = mapfn(i, v0, ts.GetValue(i))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// FoldRight collapses a seq from right to left.
|
||||
func (ts TimeSeq) FoldRight(mapfn func(i int, v0, v time.Time) time.Time) (v0 time.Time) {
|
||||
tslen := ts.Len()
|
||||
if tslen == 0 {
|
||||
return TimeZero
|
||||
}
|
||||
|
||||
if tslen == 1 {
|
||||
return ts.GetValue(0)
|
||||
}
|
||||
|
||||
v0 = ts.GetValue(tslen - 1)
|
||||
for i := tslen - 2; i >= 0; i-- {
|
||||
v0 = mapfn(i, v0, ts.GetValue(i))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Sort returns the seq in ascending order.
|
||||
func (ts TimeSeq) Sort() TimeSeq {
|
||||
if ts.Len() == 0 {
|
||||
return ts
|
||||
}
|
||||
|
||||
values := ts.Array()
|
||||
sort.Slice(values, func(i, j int) bool {
|
||||
return values[i].Before(values[j])
|
||||
})
|
||||
return TimeSeq{TimeProvider: ArrayOfTimes(values)}
|
||||
}
|
||||
|
||||
// SortDescending returns the seq in descending order.
|
||||
func (ts TimeSeq) SortDescending() TimeSeq {
|
||||
if ts.Len() == 0 {
|
||||
return ts
|
||||
}
|
||||
|
||||
values := ts.Array()
|
||||
sort.Slice(values, func(i, j int) bool {
|
||||
return values[i].After(values[j])
|
||||
})
|
||||
return TimeSeq{TimeProvider: ArrayOfTimes(values)}
|
||||
}
|
||||
|
||||
// Min returns the minimum (or earliest) time in the sequence.
|
||||
func (ts TimeSeq) Min() (min time.Time) {
|
||||
tslen := ts.Len()
|
||||
if tslen == 0 {
|
||||
return
|
||||
}
|
||||
min = ts.GetValue(0)
|
||||
var tv time.Time
|
||||
for i := 1; i < tslen; i++ {
|
||||
tv = ts.GetValue(i)
|
||||
if tv.Before(min) {
|
||||
min = tv
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Start is an alias to `Min`.
|
||||
func (ts TimeSeq) Start() time.Time {
|
||||
return ts.Min()
|
||||
}
|
||||
|
||||
// Max returns the maximum (or latest) time in the sequence.
|
||||
func (ts TimeSeq) Max() (max time.Time) {
|
||||
tslen := ts.Len()
|
||||
if tslen == 0 {
|
||||
return
|
||||
}
|
||||
max = ts.GetValue(0)
|
||||
var tv time.Time
|
||||
for i := 1; i < tslen; i++ {
|
||||
tv = ts.GetValue(i)
|
||||
if tv.After(max) {
|
||||
max = tv
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// End is an alias to `Max`.
|
||||
func (ts TimeSeq) End() time.Time {
|
||||
return ts.Max()
|
||||
}
|
||||
|
||||
// First returns the first value in the sequence.
|
||||
func (ts TimeSeq) First() time.Time {
|
||||
if ts.Len() == 0 {
|
||||
return TimeZero
|
||||
}
|
||||
|
||||
return ts.GetValue(0)
|
||||
}
|
||||
|
||||
// Last returns the last value in the sequence.
|
||||
func (ts TimeSeq) Last() time.Time {
|
||||
if ts.Len() == 0 {
|
||||
return TimeZero
|
||||
}
|
||||
|
||||
return ts.GetValue(ts.Len() - 1)
|
||||
}
|
||||
|
||||
// MinAndMax returns both the earliest and latest value from a sequence in one pass.
|
||||
func (ts TimeSeq) MinAndMax() (min, max time.Time) {
|
||||
tslen := ts.Len()
|
||||
if tslen == 0 {
|
||||
return
|
||||
}
|
||||
min = ts.GetValue(0)
|
||||
max = ts.GetValue(0)
|
||||
var tv time.Time
|
||||
for i := 1; i < tslen; i++ {
|
||||
tv = ts.GetValue(i)
|
||||
if tv.Before(min) {
|
||||
min = tv
|
||||
}
|
||||
if tv.After(max) {
|
||||
max = tv
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// MapDistinct maps values given a map function to their distinct outputs.
|
||||
func (ts TimeSeq) MapDistinct(mapFn func(time.Time) time.Time) TimeSeq {
|
||||
tslen := ts.Len()
|
||||
if tslen == 0 {
|
||||
return TimeSeq{}
|
||||
}
|
||||
|
||||
var output []time.Time
|
||||
hourLookup := SetOfTime{}
|
||||
|
||||
// add the initial value
|
||||
tv := ts.GetValue(0)
|
||||
tvh := mapFn(tv)
|
||||
hourLookup.Add(tvh)
|
||||
output = append(output, tvh)
|
||||
|
||||
for i := 1; i < tslen; i++ {
|
||||
tv = ts.GetValue(i)
|
||||
tvh = mapFn(tv)
|
||||
if !hourLookup.Has(tvh) {
|
||||
hourLookup.Add(tvh)
|
||||
output = append(output, tvh)
|
||||
}
|
||||
}
|
||||
|
||||
return TimeSeq{ArrayOfTimes(output)}
|
||||
}
|
||||
|
||||
// Hours returns times in each distinct hour represented by the sequence.
|
||||
func (ts TimeSeq) Hours() TimeSeq {
|
||||
return ts.MapDistinct(ts.trimToHour)
|
||||
}
|
||||
|
||||
// Days returns times in each distinct day represented by the sequence.
|
||||
func (ts TimeSeq) Days() TimeSeq {
|
||||
return ts.MapDistinct(ts.trimToDay)
|
||||
}
|
||||
|
||||
// Months returns times in each distinct months represented by the sequence.
|
||||
func (ts TimeSeq) Months() TimeSeq {
|
||||
return ts.MapDistinct(ts.trimToMonth)
|
||||
}
|
||||
|
||||
// Years returns times in each distinc year represented by the sequence.
|
||||
func (ts TimeSeq) Years() TimeSeq {
|
||||
return ts.MapDistinct(ts.trimToYear)
|
||||
}
|
||||
|
||||
func (ts TimeSeq) trimToHour(tv time.Time) time.Time {
|
||||
return time.Date(tv.Year(), tv.Month(), tv.Day(), tv.Hour(), 0, 0, 0, tv.Location())
|
||||
}
|
||||
|
||||
func (ts TimeSeq) trimToDay(tv time.Time) time.Time {
|
||||
return time.Date(tv.Year(), tv.Month(), tv.Day(), 0, 0, 0, 0, tv.Location())
|
||||
}
|
||||
|
||||
func (ts TimeSeq) trimToMonth(tv time.Time) time.Time {
|
||||
return time.Date(tv.Year(), tv.Month(), 1, 0, 0, 0, 0, tv.Location())
|
||||
}
|
||||
|
||||
func (ts TimeSeq) trimToYear(tv time.Time) time.Time {
|
||||
return time.Date(tv.Year(), 1, 1, 0, 0, 0, 0, tv.Location())
|
||||
}
|
60
seq/time_seq_test.go
Normal file
60
seq/time_seq_test.go
Normal file
|
@ -0,0 +1,60 @@
|
|||
package seq
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
assert "github.com/blendlabs/go-assert"
|
||||
)
|
||||
|
||||
func TestTimeSeqTimes(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
seq := Times(time.Now(), time.Now(), time.Now())
|
||||
assert.Equal(3, seq.Len())
|
||||
}
|
||||
|
||||
func parseTime(str string) time.Time {
|
||||
tv, _ := time.Parse("2006-01-02 15:04:05", str)
|
||||
return tv
|
||||
}
|
||||
|
||||
func TestTimeSeqSort(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
seq := Times(
|
||||
parseTime("2016-05-14 12:00:00"),
|
||||
parseTime("2017-05-14 12:00:00"),
|
||||
parseTime("2015-05-14 12:00:00"),
|
||||
parseTime("2017-05-13 12:00:00"),
|
||||
)
|
||||
|
||||
sorted := seq.Sort()
|
||||
assert.Equal(4, sorted.Len())
|
||||
min, max := sorted.MinAndMax()
|
||||
assert.Equal(parseTime("2015-05-14 12:00:00"), min)
|
||||
assert.Equal(parseTime("2017-05-14 12:00:00"), max)
|
||||
|
||||
first, last := sorted.First(), sorted.Last()
|
||||
assert.Equal(min, first)
|
||||
assert.Equal(max, last)
|
||||
}
|
||||
|
||||
func TestTimeSeqDays(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
seq := Times(
|
||||
parseTime("2017-05-10 12:00:00"),
|
||||
parseTime("2017-05-10 16:00:00"),
|
||||
parseTime("2017-05-11 12:00:00"),
|
||||
parseTime("2015-05-12 12:00:00"),
|
||||
parseTime("2015-05-12 16:00:00"),
|
||||
parseTime("2017-05-13 12:00:00"),
|
||||
parseTime("2017-05-14 12:00:00"),
|
||||
)
|
||||
|
||||
days := seq.Days()
|
||||
assert.Equal(5, days.Len())
|
||||
assert.Equal(10, days.First().Day())
|
||||
assert.Equal(14, days.Last().Day())
|
||||
}
|
|
@ -12,7 +12,7 @@ func TestTimeMarketHours(t *testing.T) {
|
|||
assert := assert.New(t)
|
||||
|
||||
today := time.Date(2016, 07, 01, 12, 0, 0, 0, util.Date.Eastern())
|
||||
mh := Time.MarketHours(today, today, util.NYSEOpen(), util.NYSEClose(), util.Date.IsNYSEHoliday)
|
||||
mh := TimeUtil.MarketHours(today, today, util.NYSEOpen(), util.NYSEClose(), util.Date.IsNYSEHoliday)
|
||||
assert.Len(mh, 8)
|
||||
assert.Equal(util.Date.Eastern(), mh[0].Location())
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ func TestTimeMarketHours(t *testing.T) {
|
|||
func TestTimeMarketHourQuarters(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
today := time.Date(2016, 07, 01, 12, 0, 0, 0, util.Date.Eastern())
|
||||
mh := Time.MarketHourQuarters(today, today, util.NYSEOpen(), util.NYSEClose(), util.Date.IsNYSEHoliday)
|
||||
mh := TimeUtil.MarketHourQuarters(today, today, util.NYSEOpen(), util.NYSEClose(), util.Date.IsNYSEHoliday)
|
||||
assert.Len(mh, 4)
|
||||
assert.Equal(9, mh[0].Hour())
|
||||
assert.Equal(30, mh[0].Minute())
|
||||
|
@ -39,9 +39,9 @@ func TestTimeHours(t *testing.T) {
|
|||
assert := assert.New(t)
|
||||
|
||||
today := time.Date(2016, 07, 01, 12, 0, 0, 0, time.UTC)
|
||||
seq := Time.Hours(today, 24)
|
||||
seq := TimeUtil.Hours(today, 24)
|
||||
|
||||
end := Time.End(seq)
|
||||
end := Times(seq...).Max()
|
||||
assert.Len(seq, 24)
|
||||
assert.Equal(2016, end.Year())
|
||||
assert.Equal(07, int(end.Month()))
|
||||
|
@ -72,8 +72,8 @@ func TestSequenceHoursFill(t *testing.T) {
|
|||
0.6,
|
||||
}
|
||||
|
||||
filledTimes, filledValues := Time.HoursFilled(xdata, ydata)
|
||||
assert.Len(filledTimes, util.Date.DiffHours(Time.Start(xdata), Time.End(xdata))+1)
|
||||
filledTimes, filledValues := TimeUtil.HoursFilled(xdata, ydata)
|
||||
assert.Len(filledTimes, util.Date.DiffHours(Times(xdata...).Start(), Times(xdata...).End())+1)
|
||||
assert.Equal(len(filledValues), len(filledTimes))
|
||||
|
||||
assert.NotZero(filledValues[0])
|
||||
|
@ -93,7 +93,7 @@ func TestTimeStart(t *testing.T) {
|
|||
time.Now().AddDate(0, 0, -5),
|
||||
}
|
||||
|
||||
assert.InTimeDelta(Time.Start(times), times[4], time.Millisecond)
|
||||
assert.InTimeDelta(Times(times...).Start(), times[4], time.Millisecond)
|
||||
}
|
||||
|
||||
func TestTimeEnd(t *testing.T) {
|
||||
|
@ -107,5 +107,5 @@ func TestTimeEnd(t *testing.T) {
|
|||
time.Now().AddDate(0, 0, -5),
|
||||
}
|
||||
|
||||
assert.InTimeDelta(Time.End(times), times[2], time.Millisecond)
|
||||
assert.InTimeDelta(Times(times...).End(), times[2], time.Millisecond)
|
||||
}
|
||||
|
|
26
seq/util.go
26
seq/util.go
|
@ -1,6 +1,11 @@
|
|||
package seq
|
||||
|
||||
import "math"
|
||||
import (
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"github.com/wcharczuk/go-chart/util"
|
||||
)
|
||||
|
||||
func round(input float64, places int) (rounded float64) {
|
||||
if math.IsNaN(input) {
|
||||
|
@ -30,3 +35,22 @@ func f64i(value float64) int {
|
|||
r := round(value, 0)
|
||||
return int(r)
|
||||
}
|
||||
|
||||
// SetOfTime is a simple hash set for timestamps as float64s.
|
||||
type SetOfTime map[float64]bool
|
||||
|
||||
// Add adds the value to the hash set.
|
||||
func (sot SetOfTime) Add(tv time.Time) {
|
||||
sot[util.Time.ToFloat64(tv)] = true
|
||||
}
|
||||
|
||||
// Has returns if the set contains a given time.
|
||||
func (sot SetOfTime) Has(tv time.Time) bool {
|
||||
_, hasValue := sot[util.Time.ToFloat64(tv)]
|
||||
return hasValue
|
||||
}
|
||||
|
||||
// Remove removes the value from the set.
|
||||
func (sot SetOfTime) Remove(tv time.Time) {
|
||||
delete(sot, util.Time.ToFloat64(tv))
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue