Skip to content

Commit 4dfd468

Browse files
committed
datetime: fix interval arithmetic with timezones
Tarantool used to ignore timezone difference (offset) for a datetime interval calculations due to a bug [1]. We have to fix it too since we relied on the wrong behavior. 1. tarantool/tarantool#7698
1 parent 64e41c5 commit 4dfd468

File tree

3 files changed

+14
-48
lines changed

3 files changed

+14
-48
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ Versioning](http://semver.org/spec/v2.0.0.html) except to the first release.
3535
- Decimal package use a test function GetNumberLength instead of a
3636
package-level function getNumberLength (#219)
3737
- Datetime location after encode + decode is unequal (#217)
38+
- Wrong interval arithmetic with timezones (#221)
3839

3940
## [1.8.0] - 2022-08-17
4041

datetime/datetime.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,9 @@ func (dtime *Datetime) Sub(ival Interval) (*Datetime, error) {
220220
func (dtime *Datetime) Interval(next *Datetime) Interval {
221221
curIval := intervalFromDatetime(dtime)
222222
nextIval := intervalFromDatetime(next)
223+
_, curOffset := dtime.time.Zone()
224+
_, nextOffset := next.time.Zone()
225+
curIval.Min -= int64(curOffset-nextOffset) / 60
223226
return nextIval.Sub(curIval)
224227
}
225228

datetime/datetime_test.go

Lines changed: 10 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ func TestDatetimeAddOutOfRange(t *testing.T) {
321321
}
322322

323323
func TestDatetimeInterval(t *testing.T) {
324-
var first = "2015-03-20T17:50:56.000000009Z"
324+
var first = "2015-03-20T17:50:56.000000009+01:00"
325325
var second = "2013-01-31T17:51:56.000000009Z"
326326

327327
tmFirst, err := time.Parse(time.RFC3339, first)
@@ -345,60 +345,22 @@ func TestDatetimeInterval(t *testing.T) {
345345
ivalFirst := dtFirst.Interval(dtSecond)
346346
ivalSecond := dtSecond.Interval(dtFirst)
347347

348-
expectedFirst := Interval{-2, -2, 0, 11, 0, 1, 0, 0, NoneAdjust}
349-
expectedSecond := Interval{2, 2, 0, -11, 0, -1, 0, 0, NoneAdjust}
348+
expectedFirst := Interval{-2, -2, 0, 11, 0, 61, 0, 0, NoneAdjust}
349+
expectedSecond := Interval{2, 2, 0, -11, 0, -61, 0, 0, NoneAdjust}
350350

351351
if !reflect.DeepEqual(ivalFirst, expectedFirst) {
352352
t.Errorf("Unexpected interval %v, expected %v", ivalFirst, expectedFirst)
353353
}
354354
if !reflect.DeepEqual(ivalSecond, expectedSecond) {
355-
t.Errorf("Unexpected interval %v, expected %v", ivalFirst, expectedSecond)
355+
t.Errorf("Unexpected interval %v, expected %v", ivalSecond, expectedSecond)
356356
}
357-
}
358-
359-
func TestDatetimeTarantoolInterval(t *testing.T) {
360-
skipIfDatetimeUnsupported(t)
361-
362-
conn := test_helpers.ConnectWithValidation(t, server, opts)
363-
defer conn.Close()
364357

365-
dates := []string{
366-
"2015-03-20T17:50:56.000000009+01:00",
367-
"2015-12-21T17:50:53Z",
368-
"2010-02-24T23:03:56.0000013-04:00",
369-
"1980-03-28T13:18:39.000099Z",
370-
"2025-08-01T00:00:00.000000003+11:00",
371-
"2020-01-01T01:01:01+11:30",
372-
}
373-
datetimes := []*Datetime{}
374-
for _, date := range dates {
375-
tm, err := time.Parse(time.RFC3339, date)
376-
if err != nil {
377-
t.Fatalf("Error in time.Parse(%s): %s", date, err)
378-
}
379-
dt, err := NewDatetime(tm)
380-
if err != nil {
381-
t.Fatalf("Error in NewDatetime(%s): %s", tm, err)
382-
}
383-
datetimes = append(datetimes, dt)
384-
}
385-
386-
for _, dti := range datetimes {
387-
for _, dtj := range datetimes {
388-
t.Run(fmt.Sprintf("%s_to_%s", dti.ToTime(), dtj.ToTime()),
389-
func(t *testing.T) {
390-
resp, err := conn.Call17("call_datetime_interval",
391-
[]interface{}{dti, dtj})
392-
if err != nil {
393-
t.Fatalf("Unable to call call_datetime_interval: %s", err)
394-
}
395-
ival := dti.Interval(dtj)
396-
ret := resp.Data[0].(Interval)
397-
if !reflect.DeepEqual(ival, ret) {
398-
t.Fatalf("%v != %v", ival, ret)
399-
}
400-
})
401-
}
358+
dtFirst, err = dtFirst.Add(ivalFirst)
359+
if err != nil {
360+
t.Fatalf("Unable to add an intarval: %s", err)
361+
}
362+
if !dtFirst.ToTime().Equal(dtSecond.ToTime()) {
363+
t.Errorf("Incorrect add interval result: %s, expected %s", dtFirst.ToTime(), dtSecond.ToTime())
402364
}
403365
}
404366

0 commit comments

Comments
 (0)