Skip to content

Instantly share code, notes, and snippets.

@kylelemons
Created September 2, 2013 17:44
Show Gist options
  • Save kylelemons/6415405 to your computer and use it in GitHub Desktop.
Save kylelemons/6415405 to your computer and use it in GitHub Desktop.
Fun with Date arithmetic!
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