comparison pkg/common/time.go @ 3332:c86a8e70b40f

Made time interpolation more precise and added a unit test.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Mon, 20 May 2019 16:36:19 +0200
parents 8c4c1b3fd856
children ecb4baa2be1a
comparison
equal deleted inserted replaced
3331:6172acfa7ff5 3332:c86a8e70b40f
33 ValueBelow ValueRangeKind = -1 33 ValueBelow ValueRangeKind = -1
34 ValueInside ValueRangeKind = 0 34 ValueInside ValueRangeKind = 0
35 ValueAbove ValueRangeKind = +1 35 ValueAbove ValueRangeKind = +1
36 ) 36 )
37 37
38 var utc0 = time.Unix(0, 0)
39
38 func InterpolateValueByTime(t1 time.Time, m1 float64, t2 time.Time, m2 float64) func(time.Time) (float64, ValueRangeKind) { 40 func InterpolateValueByTime(t1 time.Time, m1 float64, t2 time.Time, m2 float64) func(time.Time) (float64, ValueRangeKind) {
39 41
40 // f(t1) = m1 42 // f(t1) = m1
41 // f(t2) = m2 43 // f(t2) = m2
42 // m1 = t1*a + b <=> b = m1 - t1*a 44 // m1 = t1*a + b <=> b = m1 - t1*a
62 } else { 64 } else {
63 min, max = t2, t1 65 min, max = t2, t1
64 } 66 }
65 67
66 a := (m1 - m2) / t1.Sub(t2).Seconds() 68 a := (m1 - m2) / t1.Sub(t2).Seconds()
67 b := m1 - a*float64(t1.Unix()) 69 b := m1 - a*t1.Sub(utc0).Seconds()
68 70
69 return func(t time.Time) (float64, ValueRangeKind) { 71 return func(t time.Time) (float64, ValueRangeKind) {
70 switch { 72 switch {
71 case t.Before(min): 73 case t.Before(min):
72 return 0, ValueBelow 74 return 0, ValueBelow
73 case t.After(max): 75 case t.After(max):
74 return 0, ValueAbove 76 return 0, ValueAbove
75 default: 77 default:
76 return a*float64(t.Unix()) + b, ValueInside 78 return a*t.Sub(utc0).Seconds() + b, ValueInside
77 } 79 }
78 } 80 }
79 } 81 }
80 82
81 func InterpolateTimeByValue(t1 time.Time, m1 float64, t2 time.Time, m2 float64) func(float64) (time.Time, ValueRangeKind) { 83 func InterpolateTimeByValue(t1 time.Time, m1 float64, t2 time.Time, m2 float64) func(float64) (time.Time, ValueRangeKind) {
102 } 104 }
103 105
104 min, max := math.Min(m1, m2), math.Max(m1, m2) 106 min, max := math.Min(m1, m2), math.Max(m1, m2)
105 107
106 a := t1.Sub(t2).Seconds() / (m1 - m2) 108 a := t1.Sub(t2).Seconds() / (m1 - m2)
107 b := float64(t1.Unix()) - m1*a 109 b := t1.Sub(utc0).Seconds() - m1*a
108 110
109 return func(m float64) (time.Time, ValueRangeKind) { 111 return func(m float64) (time.Time, ValueRangeKind) {
110 switch { 112 switch {
111 case m < min: 113 case m < min:
112 return time.Time{}, ValueBelow 114 return time.Time{}, ValueBelow
113 case m > max: 115 case m > max:
114 return time.Time{}, ValueAbove 116 return time.Time{}, ValueAbove
115 default: 117 default:
116 return time.Unix(int64(math.Ceil(m*a+b)), 0), ValueInside 118 x := m*a + b
119 secs := math.Ceil(x)
120 nsecs := math.Ceil((x - secs) * (999999999 + 1))
121 return time.Unix(int64(secs), int64(nsecs)), ValueInside
117 } 122 }
118 } 123 }
119 } 124 }