diff --git a/changelogs/unreleased/gh-7698-datetime-subtraction-with-tz.md b/changelogs/unreleased/gh-7698-datetime-subtraction-with-tz.md new file mode 100644 index 0000000000000000000000000000000000000000..3e11cd52c0525bb11a4f1d2c617bea0c79310b7a --- /dev/null +++ b/changelogs/unreleased/gh-7698-datetime-subtraction-with-tz.md @@ -0,0 +1,28 @@ +## bugfix/datetime + +* Fixed subtractions for datetimes with different timezones (gh-7698). + + We used to ignore timezone difference (im `tzoffset`) for + datetime subtraction operation: + + ``` + tarantool> datetime.new{tz='MSK'} - datetime.new{tz='UTC'} + --- + - +0 seconds + ... + tarantool> datetime.new{tz='MSK'}.timestamp - + datetime.new{tz='UTC'}.timestamp + --- + - -10800 + ... + ``` + + Now we accumulate that difference to the minute component of + a resultant interval: + + ``` + tarantool> datetime.new{tz='MSK'} - datetime.new{tz='UTC'} + --- + - -180 minutes + ... + ``` diff --git a/src/lib/core/datetime.c b/src/lib/core/datetime.c index e1e85457a945965bbfbca8dfbf5b161c62640eb8..e22504d2fbcc08a883cb73a5127540a442c49d36 100644 --- a/src/lib/core/datetime.c +++ b/src/lib/core/datetime.c @@ -844,6 +844,7 @@ datetime_datetime_sub(struct interval *res, const struct datetime *lhs, struct interval inv_rhs; datetime_totable(lhs, res); datetime_totable(rhs, &inv_rhs); + res->min -= lhs->tzoffset - rhs->tzoffset; return interval_interval_sub(res, &inv_rhs); } diff --git a/test/app-tap/datetime.test.lua b/test/app-tap/datetime.test.lua index b08b0dd26ae76a76a4dd702e503872f713a0c55b..cb06b0a65bf41bcc08a6785fe41119c18b25a4d2 100755 --- a/test/app-tap/datetime.test.lua +++ b/test/app-tap/datetime.test.lua @@ -12,7 +12,7 @@ local TZ = date.TZ --]] if jit.arch == 'arm64' then jit.off() end -test:plan(38) +test:plan(39) -- minimum supported date - -5879610-06-22 local MIN_DATE_YEAR = -5879610 @@ -1257,6 +1257,20 @@ test:test("Time interval operations - different adjustments", function(test) end end) +test:test("Time interval operations - different timezones", function(test) + test:plan(8) + local d1_msk = date.new{tz = 'MSK'} + local d1_utc = date.new{tz = 'UTC'} + test:is(d1_msk.tzoffset, 180, 'MSK is +180') + test:is(d1_utc.tzoffset, 0, 'UTC is 0') + test:is(tostring(d1_msk), '1970-01-01T00:00:00 MSK', '1970-01-01 MSK') + test:is(tostring(d1_utc), '1970-01-01T00:00:00 UTC', '1970-01-01 UTC') + test:is(d1_utc > d1_msk, true, 'utc > msk') + test:is(tostring(d1_utc - d1_msk), '+180 minutes', 'utc - msk') + test:is(tostring(d1_msk - d1_utc), '-180 minutes', 'msk - utc') + test:is(d1_msk.epoch - d1_utc.epoch, -10800, '-10800') +end) + test:test("Time intervals creation - range checks", function(test) test:plan(23)