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)