Created
September 2, 2013 17:44
-
-
Save kylelemons/6415405 to your computer and use it in GitHub Desktop.
Fun with Date arithmetic!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"log" | |
"math/rand" | |
"time" | |
) | |
type Snapshot struct { | |
Value AccountValue | |
At time.Time | |
} | |
type Granularity struct { | |
Name string | |
DateIncrement [3]int | |
DurIncrement time.Duration | |
DateFormat string | |
} | |
func (g Granularity) AddTo(t time.Time) time.Time { | |
di, dur := g.DateIncrement, g.DurIncrement | |
return t.AddDate(di[0], di[1], di[2]).Add(dur) | |
} | |
func (g Granularity) Format(t time.Time) string { | |
return t.Format(g.DateFormat) | |
} | |
func (g Granularity) Truncate(t time.Time) time.Time { | |
v, err := time.Parse(g.DateFormat, g.Format(t)) | |
if err != nil { | |
log.Fatalf("non-round-trippable date format %q", g.DateFormat) | |
} | |
return v | |
} | |
var Granularities = []Granularity{ | |
{"hour", [3]int{}, 1 * time.Hour, "2006/01/02T15"}, | |
{"day", [3]int{2: 1}, 0, "2006/01/02"}, | |
{"month", [3]int{1: 1}, 0, "2006/01"}, | |
{"year", [3]int{0: 1}, 0, "2006"}, | |
} | |
type Graph struct { | |
Granularity | |
Values map[string][]AccountValue | |
} | |
func (g *Graph) Add(snaps []Snapshot) { | |
if g.Values == nil { | |
g.Values = map[string][]AccountValue{} | |
} | |
for _, s := range snaps { | |
key := g.Format(s.At) | |
g.Values[key] = append(g.Values[key], s.Value) | |
} | |
} | |
func (g *Graph) Get(from, to time.Time) (snaps []Snapshot) { | |
from, to = g.Truncate(from), g.Truncate(to) | |
for cur := from; !to.Before(cur); cur = g.AddTo(cur) { | |
var avg, denom AccountValue | |
for _, v := range g.Values[g.Format(cur)] { | |
avg += v | |
denom += 1 | |
} | |
if denom > 0 { | |
avg /= denom | |
} | |
snaps = append(snaps, Snapshot{ | |
Value: avg, | |
At: cur, | |
}) | |
} | |
return snaps | |
} | |
func main() { | |
start := time.Now() | |
end := start.AddDate(0, 4, 0) | |
// Generate snapshots | |
var snaps []Snapshot | |
var cur = FromPair(1000, 0) | |
for now := start; !now.After(end); now = now.Add(1 * time.Hour) { | |
snaps = append(snaps, Snapshot{ | |
Value: cur, | |
At: now, | |
}) | |
cur += FromDollars(rand.NormFloat64() * 10) | |
} | |
for _, g := range Granularities[1:] { | |
fmt.Println("Graph for: ", g.Name) | |
graph := Graph{Granularity: g} | |
graph.Add(snaps) | |
for _, snap := range graph.Get(start, end) { | |
fmt.Println(g.Format(snap.At), snap.Value) | |
} | |
} | |
} | |
// AccountValue holds a dollar amount | |
// in thousandths of a cent | |
type AccountValue int64 | |
func FromDollars(dollars float64) AccountValue { | |
return AccountValue(dollars * 100000) | |
} | |
func FromPair(dollars int, cents int) AccountValue { | |
return AccountValue(dollars)*100000 + AccountValue(cents)*1000 | |
} | |
func (v AccountValue) Dollars() float64 { return float64(v) / 100000 } | |
func (v AccountValue) String() string { return fmt.Sprintf("$%.2f", v.Dollars()) } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment