From 45d40d1324fa0c1d26a764bc157aee6cd586fcb0 Mon Sep 17 00:00:00 2001
From: Sergey Bronnikov <sergeyb@tarantool.org>
Date: Wed, 28 Aug 2024 16:16:10 +0300
Subject: [PATCH] datetime: use tzoffset in a parse() with custom format

The patch fixes a behaviour, when `datetime.parse()` ignores
`tzoffset` option if custom format is used.

Fixes #8333
Relates to #10420

NO_DOC=bugfix

(cherry picked from commit 04811e032f29afe0fa6206ef2c7a0f8434861830)
---
 .../gh-8333-fix-ignoring-tzoffset-in-parse.md |  4 ++++
 src/lua/datetime.lua                          | 21 +++++++++++--------
 test/app-tap/datetime.test.lua                |  6 +++++-
 3 files changed, 21 insertions(+), 10 deletions(-)
 create mode 100644 changelogs/unreleased/gh-8333-fix-ignoring-tzoffset-in-parse.md

diff --git a/changelogs/unreleased/gh-8333-fix-ignoring-tzoffset-in-parse.md b/changelogs/unreleased/gh-8333-fix-ignoring-tzoffset-in-parse.md
new file mode 100644
index 0000000000..73130e56ce
--- /dev/null
+++ b/changelogs/unreleased/gh-8333-fix-ignoring-tzoffset-in-parse.md
@@ -0,0 +1,4 @@
+## bugfix/lua/datetime
+
+* Fixed a bug that caused `datetime.parse()` ignore `tzoffset`
+  option if a custom format was used (gh-8333).
diff --git a/src/lua/datetime.lua b/src/lua/datetime.lua
index 093e74cd47..959517efc1 100644
--- a/src/lua/datetime.lua
+++ b/src/lua/datetime.lua
@@ -913,9 +913,8 @@ local function datetime_parse_from(str, obj)
     end
     check_str_or_nil(fmt, 'datetime.parse()')
 
-    local offset
     if tzoffset ~= nil then
-        offset = get_timezone(tzoffset, 'tzoffset')
+        local offset = get_timezone(tzoffset, 'tzoffset')
         check_range(offset, -720, 840, 'tzoffset')
     end
 
@@ -923,16 +922,20 @@ local function datetime_parse_from(str, obj)
         check_str(tzname, 'datetime.parse()')
     end
 
+    local date, len
     if not fmt or fmt == '' or fmt == 'iso8601' or fmt == 'rfc3339' then
-        local date, len = datetime_parse_full(str)
-        -- Override timezone.
-        if date.tz == '' and date.tzoffset == 0 then
-            datetime_set(date, obj or {})
-        end
-        return date, tonumber(len)
+        date, len = datetime_parse_full(str)
     else
-        return datetime_parse_format(str, fmt)
+        date, len = datetime_parse_format(str, fmt)
     end
+
+    -- Override timezone, if it was not specified in a parsed
+    -- string.
+    if date.tz == '' and date.tzoffset == 0 then
+        datetime_set(date, { tzoffset = tzoffset, tz = tzname })
+    end
+
+    return date, len
 end
 
 --[[
diff --git a/test/app-tap/datetime.test.lua b/test/app-tap/datetime.test.lua
index d448a6d9b8..2ca31e4cad 100755
--- a/test/app-tap/datetime.test.lua
+++ b/test/app-tap/datetime.test.lua
@@ -424,7 +424,7 @@ test:test("Formatting limits", function(test)
 end)
 
 test:test("Simple tests for parser", function(test)
-    test:plan(12)
+    test:plan(14)
     test:ok(date.parse("1970-01-01T01:00:00Z") ==
             date.new{year=1970, mon=1, day=1, hour=1, min=0, sec=0})
     test:ok(date.parse("1970-01-01T01:00:00Z", {format = 'iso8601'}) ==
@@ -445,6 +445,10 @@ test:test("Simple tests for parser", function(test)
             date.new{year=1970, mon=1, day=1, hour=1, min=0, sec=0, tzoffset=0})
     test:ok(date.parse("1970-01-01T01:00:00+01:00", {tzoffset = '+02:00'}) ==
             date.new{year=1970, mon=1, day=1, hour=1, min=0, sec=0, tzoffset=60})
+    test:ok(date.parse('1998-11-25', { format = '%Y-%m-%d', tzoffset = 180 }) ==
+            date.new({ year = 1998, month = 11, day = 25, tzoffset = 180 }))
+    test:ok(date.parse('1998', { format = '%Y', tzoffset = '+03:00' }) ==
+            date.new({ year = 1998, tzoffset = 180 }))
 
     test:ok(date.parse("1970-01-01T02:00:00Z") <
             date.new{year=1970, mon=1, day=1, hour=2, min=0, sec=1})
-- 
GitLab