grokify/mogo

View on GitHub
time/timeutil/slice.go

Summary

Maintainability
A
0 mins
Test Coverage
package timeutil

import (
    "errors"
    "fmt"
    "sort"
    "strings"
    "time"
)

/*
// TimeSlice is used for sorting. e.g.
// sort.Sort(sort.Reverse(timeSlice))
// sort.Sort(timeSlice)
// var times TimeSlice := []time.Time{time.Now()}
type TimeSlice []time.Time

func (s TimeSlice) Less(i, j int) bool { return s[i].Before(s[j]) }
func (s TimeSlice) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
func (s TimeSlice) Len() int           { return len(s) }
*/

func Sort(times []time.Time) []time.Time {
    sort.Slice(
        times,
        func(i, j int) bool { return times[i].Before(times[j]) })
    return times
}

func Earliest(times []time.Time, skipZeroes bool) (time.Time, error) {
    if len(times) == 0 {
        return time.Now(), errors.New("no times")
    }
    sort.Slice(
        times,
        func(i, j int) bool { return times[i].Before(times[j]) })

    first := times[0]
    if skipZeroes && isZeroAny(first) {
        return first, fmt.Errorf("latest time is zero [%s]", first.Format(time.RFC3339))
    }
    return first, nil
}

func Latest(times []time.Time, skipZeroes bool) (time.Time, error) {
    if len(times) == 0 {
        return time.Now(), errors.New("no times")
    }
    sort.Slice(
        times,
        func(i, j int) bool { return times[i].Before(times[j]) })

    last := times[len(times)-1]
    if skipZeroes && isZeroAny(last) {
        return last, fmt.Errorf("latest time is zero [%s]", last.Format(time.RFC3339))
    }
    return last, nil
}

func QuarterSlice(min, max time.Time) []time.Time {
    min, max = MinMax(min, max)
    minQ := quarterStart(min)
    maxQ := quarterStart(max)
    times := []time.Time{}
    cur := minQ
    for cur.Before(maxQ) || cur.Equal(maxQ) {
        times = append(times, cur)
        cur = QuarterAdd(cur, 1)
    }
    return times
}

func FirstNonZeroTimeParsed(format string, times []string) (time.Time, error) {
    if len(times) == 0 {
        return time.Now(), errors.New("no times provided")
    }
    for _, timeString := range times {
        timeString = strings.TrimSpace(timeString)
        if len(timeString) == 0 {
            continue
        }
        t, err := time.Parse(format, timeString)
        if err != nil {
            return t, err
        }
        if !isZeroAny(t) {
            return t, nil
        }
    }
    return time.Now(), errors.New("no times provided")
}

func FirstNonZeroTime(times ...time.Time) (time.Time, error) {
    if len(times) == 0 {
        return time.Now(), errors.New("no times provided")
    }
    for _, t := range times {
        if !isZeroAny(t) {
            return t, nil
        }
    }
    return time.Now(), errors.New("no times provided")
}

func MustFirstNonZeroTime(times ...time.Time) time.Time {
    t, err := FirstNonZeroTime(times...)
    if err != nil {
        return TimeZeroRFC3339()
    }
    return t
}

func TimeSliceMinMax(times []time.Time) (time.Time, time.Time, error) {
    min := TimeZeroRFC3339()
    max := TimeZeroRFC3339()
    if len(times) == 0 {
        return min, max, errors.New("timeutil.TimeSliceMinMax provided with empty slice")
    }
    for i, t := range times {
        if i == 0 {
            min = t
            max = t
        } else {
            if t.Before(min) {
                min = t
            }
            if t.After(max) {
                max = t
            }
        }
    }
    return min, max, nil
}

// Distinct returns a time slice with distinct, or unique, times.
func Distinct(times []time.Time) []time.Time {
    filtered := []time.Time{}
    seen := map[time.Time]int{}
    for _, t := range times {
        if _, ok := seen[t]; !ok {
            seen[t] = 1
            filtered = append(filtered, t)
        }
    }
    return filtered
}