Fixed dst leap adjustment.

This commit is contained in:
Augusto Becciu 2017-01-11 22:07:19 -08:00
parent 276721802b
commit 1a49152fbc
2 changed files with 93 additions and 9 deletions

View File

@ -247,11 +247,23 @@ func (expr *Expression) nextTime(prev, next time.Time) time.Time {
// a dst leap occurred
if offsetDiff > 0 {
dstChangeTime := findTimeOfDSTChange(prev, t)
// since a dst leap occured, t is offsetDiff seconds ahead
t = t.Add(-1 * offsetDiff)
// check if t is within the skipped interval (offsetDiff)
if noTZDiff(dstChangeTime, t) < offsetDiff {
if dstFlags&DSTLeapUnskip != 0 {
return findTimeOfDSTChange(prev, t).Add(1 * time.Second)
// return the earliest time right after the leap
return dstChangeTime.Add(1 * time.Second)
}
return expr.roundTime(t)
// return the next scheduled time right after the leap
return expr.roundTime(dstChangeTime.Add(1 * time.Second))
}
return t
}
// a dst fall occurred
@ -401,13 +413,13 @@ func workdayOfMonth(targetDom, lastDom time.Time) int {
return dom
}
func utcOffset(t time.Time) int {
func utcOffset(t time.Time) time.Duration {
_, offset := t.Zone()
return offset
return time.Duration(offset) * time.Second
}
func noTZ(t time.Time) time.Time {
return t.UTC().Add(time.Duration(utcOffset(t)) * time.Second)
return t.UTC().Add(utcOffset(t))
}
func noTZDiff(t1, t2 time.Time) time.Duration {
@ -454,7 +466,7 @@ func findTwinTime(t time.Time) time.Time {
// a fall occurs within the next 12 hours
if offsetDiff < 0 {
border := findTimeOfDSTChange(t, t.Add(12*time.Hour))
t0 := border.Add(time.Duration(offsetDiff) * time.Second)
t0 := border.Add(offsetDiff)
if t0.After(t) {
return t
@ -468,9 +480,9 @@ func findTwinTime(t time.Time) time.Time {
// a fall occurred in the past 12 hours
if offsetDiff < 0 {
border := findTimeOfDSTChange(t.Add(-12*time.Hour), t)
t0 := border.Add(time.Duration(offsetDiff) * time.Second)
t0 := border.Add(offsetDiff)
if t0.Add(time.Duration(-2*offsetDiff) * time.Second).Before(t) {
if t0.Add(-2 * offsetDiff).Before(t) {
return t
}

View File

@ -333,6 +333,30 @@ func TestDST(t *testing.T) {
time.Date(2014, 3, 12, 2, 0, 0, 0, locs[0]),
},
},
{
fmt.Sprintf("%s time after daily leap skip", locs[0]),
"0 5 14 * * * *",
cronexpr.Options{DSTFlags: cronexpr.DSTFallFireLate},
time.Date(2016, 3, 12, 14, 6, 0, 0, locs[0]),
[]time.Time{
time.Date(2016, 3, 13, 14, 5, 0, 0, locs[0]),
time.Date(2016, 3, 14, 14, 5, 0, 0, locs[0]),
time.Date(2016, 3, 15, 14, 5, 0, 0, locs[0]),
time.Date(2016, 3, 16, 14, 5, 0, 0, locs[0]),
},
},
{
fmt.Sprintf("%s time after daily leap unskip", locs[0]),
"0 5 14 * * * *",
cronexpr.Options{DSTFlags: cronexpr.DSTLeapUnskip | cronexpr.DSTFallFireLate},
time.Date(2016, 3, 12, 14, 6, 0, 0, locs[0]),
[]time.Time{
time.Date(2016, 3, 13, 14, 5, 0, 0, locs[0]),
time.Date(2016, 3, 14, 14, 5, 0, 0, locs[0]),
time.Date(2016, 3, 15, 14, 5, 0, 0, locs[0]),
time.Date(2016, 3, 16, 14, 5, 0, 0, locs[0]),
},
},
{
fmt.Sprintf("%s hourly leap skip", locs[0]),
"0 0 * * * * *",
@ -477,6 +501,30 @@ func TestDST(t *testing.T) {
time.Date(1981, 4, 4, 2, 0, 0, 0, locs[1]),
},
},
{
fmt.Sprintf("%s time after daily leap skip", locs[1]),
"0 5 14 * * * *",
cronexpr.Options{DSTFlags: cronexpr.DSTFallFireEarly},
time.Date(1981, 3, 31, 15, 0, 0, 0, locs[1]),
[]time.Time{
time.Date(1981, 4, 1, 14, 5, 0, 0, locs[1]),
time.Date(1981, 4, 2, 14, 5, 0, 0, locs[1]),
time.Date(1981, 4, 3, 14, 5, 0, 0, locs[1]),
time.Date(1981, 4, 4, 14, 5, 0, 0, locs[1]),
},
},
{
fmt.Sprintf("%s time after daily leap unskip", locs[1]),
"0 5 14 * * * *",
cronexpr.Options{DSTFlags: cronexpr.DSTLeapUnskip | cronexpr.DSTFallFireEarly},
time.Date(1981, 3, 31, 15, 0, 0, 0, locs[1]),
[]time.Time{
time.Date(1981, 4, 1, 14, 5, 0, 0, locs[1]),
time.Date(1981, 4, 2, 14, 5, 0, 0, locs[1]),
time.Date(1981, 4, 3, 14, 5, 0, 0, locs[1]),
time.Date(1981, 4, 4, 14, 5, 0, 0, locs[1]),
},
},
{
fmt.Sprintf("%s hourly leap skip", locs[1]),
"0 0 * * * * *",
@ -573,6 +621,30 @@ func TestDST(t *testing.T) {
time.Date(2014, 10, 8, 2, 0, 0, 0, locs[2]),
},
},
{
fmt.Sprintf("%s time after daily leap skip", locs[2]),
"0 5 14 * * * *",
cronexpr.Options{DSTFlags: cronexpr.DSTFallFireEarly},
time.Date(2014, 10, 4, 15, 0, 0, 0, locs[2]),
[]time.Time{
time.Date(2014, 10, 5, 14, 5, 0, 0, locs[2]),
time.Date(2014, 10, 6, 14, 5, 0, 0, locs[2]),
time.Date(2014, 10, 7, 14, 5, 0, 0, locs[2]),
time.Date(2014, 10, 8, 14, 5, 0, 0, locs[2]),
},
},
{
fmt.Sprintf("%s time after daily leap unskip", locs[2]),
"0 5 14 * * * *",
cronexpr.Options{DSTFlags: cronexpr.DSTLeapUnskip | cronexpr.DSTFallFireEarly},
time.Date(2014, 10, 4, 15, 0, 0, 0, locs[2]),
[]time.Time{
time.Date(2014, 10, 5, 14, 5, 0, 0, locs[2]),
time.Date(2014, 10, 6, 14, 5, 0, 0, locs[2]),
time.Date(2014, 10, 7, 14, 5, 0, 0, locs[2]),
time.Date(2014, 10, 8, 14, 5, 0, 0, locs[2]),
},
},
{
fmt.Sprintf("%s hourly leap skip", locs[2]),
"0 0 * * * * *",