summaryrefslogtreecommitdiff
path: root/chronos
diff options
context:
space:
mode:
authorKevin Chabowski <kevin@kch42.de>2013-09-15 12:53:11 +0200
committerKevin Chabowski <kevin@kch42.de>2013-09-15 12:53:11 +0200
commit819a2e2c9b15e5167f8af3736905569949306c94 (patch)
treec359490b71fd090c9a3033905e6f32640f67ced3 /chronos
parentc0a06609919d09fbcb6326ff69cc455dd13506ef (diff)
downloadmailremind-819a2e2c9b15e5167f8af3736905569949306c94.tar.gz
mailremind-819a2e2c9b15e5167f8af3736905569949306c94.tar.bz2
mailremind-819a2e2c9b15e5167f8af3736905569949306c94.zip
Changed weird internal terminology
Diffstat (limited to 'chronos')
-rw-r--r--chronos/chronos.go280
-rw-r--r--chronos/chronos_test.go45
2 files changed, 0 insertions, 325 deletions
diff --git a/chronos/chronos.go b/chronos/chronos.go
deleted file mode 100644
index 74fec19..0000000
--- a/chronos/chronos.go
+++ /dev/null
@@ -1,280 +0,0 @@
-package chronos
-
-import (
- "errors"
- "fmt"
- "math"
- "strconv"
- "strings"
- "time"
-)
-
-type TimeUnit int
-
-const timefmt = "2006-01-02 15:04:05"
-
-const (
- Minute TimeUnit = iota
- Hour
- Day
- Week
- Month
- Year
-)
-
-var nilTime time.Time
-
-var tuLookup = map[string]TimeUnit{
- "Minute": Minute,
- "Hour": Hour,
- "Day": Day,
- "Week": Week,
- "Month": Month,
- "Year": Year,
-}
-
-func (tu TimeUnit) String() string {
- switch tu {
- case Minute:
- return "Minute"
- case Hour:
- return "Hour"
- case Day:
- return "Day"
- case Week:
- return "Week"
- case Month:
- return "Month"
- case Year:
- return "Year"
- default:
- return "(Unknown TimeUnit)"
- }
-}
-
-func (tu TimeUnit) minApprox() time.Duration {
- const (
- maMinute = time.Minute
- maHour = time.Hour
- maDay = 24*time.Hour - time.Second
- maWeek = 7 * maDay
- maMonth = 28 * maDay
- maYear = 365 * maDay
- )
-
- switch tu {
- case Minute:
- return maMinute
- case Hour:
- return maHour
- case Day:
- return maDay
- case Week:
- return maWeek
- case Month:
- return maMonth
- case Year:
- return maYear
- default:
- return 0
- }
-}
-
-func (tu TimeUnit) maxApprox() time.Duration {
- const (
- maMinute = time.Minute
- maHour = time.Hour
- maDay = 24*time.Hour + time.Second
- maWeek = 7 * maDay
- maMonth = 31 * maDay
- maYear = 366 * maDay
- )
-
- switch tu {
- case Minute:
- return maMinute
- case Hour:
- return maHour
- case Day:
- return maDay
- case Week:
- return maWeek
- case Month:
- return maMonth
- case Year:
- return maYear
- default:
- return 0
- }
-}
-
-type Frequency struct {
- Unit TimeUnit
- Count uint
-}
-
-func (f Frequency) String() string {
- return fmt.Sprintf("%d %s", f.Count, f.Unit)
-}
-
-func (f Frequency) addTo(t time.Time, mul uint) time.Time {
- sec := t.Second()
- min := t.Minute()
- hour := t.Hour()
- day := t.Day()
- month := t.Month()
- year := t.Year()
- loc := t.Location()
-
- fq := int(f.Count * mul)
-
- switch f.Unit {
- case Minute:
- return t.Add(time.Minute * time.Duration(fq))
- case Hour:
- return t.Add(time.Hour * time.Duration(fq))
- case Day:
- return time.Date(year, month, day+fq, hour, min, sec, 0, loc)
- case Week:
- return time.Date(year, month, day+fq*7, hour, min, sec, 0, loc)
- case Month:
- return time.Date(year, month+time.Month(fq), day, hour, min, sec, 0, loc)
- case Year:
- return time.Date(year+fq, month, day, hour, min, sec, 0, loc)
- default:
- return nilTime
- }
-}
-
-func (f Frequency) minApprox() time.Duration { return time.Duration(f.Count) * f.Unit.minApprox() }
-func (f Frequency) maxApprox() time.Duration { return time.Duration(f.Count) * f.Unit.maxApprox() }
-
-// Chronos describes a time schedule. It has a start and optional end point and an optional frequency.
-type Chronos struct {
- Start, End time.Time
- Freq Frequency
-}
-
-// NextAfter calculates the next time in the schedule after t. If no such time exists, nil is returned (test with Time.IsZero()).
-func (c Chronos) NextAfter(t time.Time) time.Time {
- if !t.After(c.Start) {
- return c.Start
- }
- if c.Freq.Count == 0 {
- return nilTime
- }
-
- d := t.Sub(c.Start)
-
- fmin := uint(math.Floor(float64(d) / float64(c.Freq.maxApprox())))
- fmax := uint(math.Ceil(float64(d) / float64(c.Freq.minApprox())))
-
- for f := fmin; f <= fmax; f++ {
- t2 := c.Freq.addTo(c.Start, f)
- if t2.Before(c.Start) || t2.Before(t) {
- continue
- }
- if (!c.End.IsZero()) && t2.After(c.End) {
- return nilTime
- }
- return t2
- }
-
- return nilTime // Should actually never happen...
-}
-
-func (c Chronos) String() string {
- s := c.Start.UTC().Format(timefmt)
- if c.Freq.Count > 0 {
- s += " +" + c.Freq.String()
- if !c.End.IsZero() {
- s += " !" + c.End.UTC().Format(timefmt)
- }
- }
- return s
-}
-
-func ParseChronos(s string) (c Chronos, err error) {
- elems := strings.Split(s, " ")
-
- switch len(elems) {
- case 6: // Everything specified
- _end := elems[4] + " " + elems[5]
- if c.End, err = time.ParseInLocation(timefmt, _end[1:], time.UTC); err != nil {
- return
- }
- fallthrough
- case 4: // start time and frequency
- var count uint64
- if count, err = strconv.ParseUint(elems[2][1:], 10, 32); err != nil {
- return
- }
- c.Freq.Count = uint(count)
-
- var ok bool
- if c.Freq.Unit, ok = tuLookup[elems[3]]; !ok {
- err = fmt.Errorf("Unknown timeunit %s", elems[3])
- return
- }
- fallthrough
- case 2: // Only start time
- if c.Start, err = time.ParseInLocation(timefmt, elems[0]+" "+elems[1], time.UTC); err != nil {
- return
- }
- default:
- err = errors.New("Unknown chronos format")
- }
-
- return
-}
-
-type MultiChronos []Chronos
-
-func (mc MultiChronos) NextAfter(t time.Time) time.Time {
- var nearest time.Time
-
- for _, c := range mc {
- next := c.NextAfter(t)
- if next.IsZero() {
- continue
- }
-
- if nearest.IsZero() {
- nearest = next
- } else if next.Before(nearest) {
- nearest = next
- }
- }
-
- return nearest
-}
-
-func (mc MultiChronos) String() (s string) {
- sep := ""
-
- for _, c := range mc {
- s += sep + c.String()
- sep = "\n"
- }
-
- return
-}
-
-func ParseMultiChronos(s string) (mc MultiChronos, err error) {
- parts := strings.Split(s, "\n")
- for l, _part := range parts {
- part := strings.TrimSpace(_part)
- if part == "" {
- continue
- }
-
- c, err := ParseChronos(part)
- if err != nil {
- return nil, fmt.Errorf("Line %d: %s", l+1, err)
- }
-
- mc = append(mc, c)
- }
-
- return
-}
diff --git a/chronos/chronos_test.go b/chronos/chronos_test.go
deleted file mode 100644
index 1798b4c..0000000
--- a/chronos/chronos_test.go
+++ /dev/null
@@ -1,45 +0,0 @@
-package chronos
-
-import (
- "testing"
- "time"
-)
-
-func mktime(y int, month time.Month, d, h, min int) time.Time {
- return time.Date(y, month, d, h, min, 0, 0, time.UTC)
-}
-
-func TestChronos(t *testing.T) {
- tbl := []struct {
- chronos string
- now time.Time
- want time.Time
- }{
- {"1991-04-30 00:00:00 +1 Year", mktime(2013, 8, 26, 13, 37), mktime(2014, 4, 30, 0, 0)},
- {"2013-01-01 00:00:00", mktime(2013, 8, 26, 13, 37), nilTime},
- {"2013-01-01 00:00:00", mktime(2012, 1, 1, 0, 0), mktime(2013, 1, 1, 0, 0)},
- {"1900-12-24 12:34:00 +5 Year", mktime(2013, 8, 26, 13, 37), mktime(2015, 12, 24, 12, 34)},
- {"1900-12-24 12:34:00 +5 Year !2010-01-01 01:01:00", mktime(2013, 8, 26, 13, 37), nilTime},
- {"2013-08-01 04:02:00 +3 Week", mktime(2013, 8, 26, 13, 37), mktime(2013, 9, 12, 4, 2)},
- {"2013-08-26 13:37:00", mktime(2013, 8, 26, 13, 37), mktime(2013, 8, 26, 13, 37)},
- {"2013-08-25 13:37:00 +1 Day", mktime(2013, 8, 26, 13, 37), mktime(2013, 8, 26, 13, 37)},
- {"2012-12-31 23:59:00 +100 Minute", mktime(2013, 1, 1, 0, 0), mktime(2013, 1, 1, 1, 39)},
- }
-
- for i, e := range tbl {
- c, err := ParseChronos(e.chronos)
- if err != nil {
- t.Errorf("#%d: Failed parsing \"%s\": %s", i, e.chronos, err)
- continue
- }
- have := c.NextAfter(e.now)
- if !have.Equal(e.want) {
- t.Errorf("#%d: Want: %s, Have: %s", i, e.want, have)
- }
-
- if s := c.String(); s != e.chronos {
- t.Errorf("#%d: String() failed: \"%s\" != \"%s\"", i, e.chronos, s)
- }
-
- }
-}