fix(msgpack): strptime() fails east of UTC+12 #41743

Problem:
msgpack#strptime() finds a timestamp by bisecting strftime() output, and
brackets the search with the extreme UTC offsets. The lower bound
subtracts 12 hours, but -12:00 is the westernmost offset, which produces
the *largest* timestamp for a given local time. The easternmost offset
is +14:00, so in any zone east of UTC+12 the search can start above the
target and the function throws:

    internal-start-string:Internal error: start > string

With TZ=GMT-14, four of the five timestamps in msgpack_spec.lua fail,
as do three tests in shada_spec.lua, which reaches the same function
through shada#strings_to_sd().

Solution:
Subtract 14 hours instead. The upper bound is already generous enough at
+14, and widening a bisection bracket downwards cannot change the result
in zones that worked before.

The test disables the python3 provider, because msgpack#strptime() only
uses the Vimscript implementation changed here when no provider answers,
and otherwise hands the work to datetime.strptime().

AI-assisted
This commit is contained in:
Volodymyr Chernetskyi
2026-09-07 14:24:16 +02:00
committed by GitHub
parent 1c8d5581d9
commit a31f9affde
2 changed files with 24 additions and 2 deletions

View File

@@ -132,11 +132,11 @@ function s:msgpack_init_python() abort
let [year, month, day, hour, minute, second] = match[1:6]
" Bisection start and end:
"
" Start: 365 days in year, 28 days in month, -12 hours tz offset.
" Start: 365 days in year, 28 days in month, -14 hours tz offset.
let bisect_ts_start = (((((year - 1970) * 365
\+ (month - 1) * 28
\+ (day - 1)) * 24
\+ hour - 12) * 60
\+ hour - 14) * 60
\+ minute) * 60
\+ second)
if bisect_ts_start < 0

View File

@@ -735,3 +735,25 @@ describe('autoload/msgpack.vim', function()
end)
end)
end)
describe('autoload/msgpack.vim in an eastern timezone', function()
setup(function()
clear({
-- msgpack#strptime() prefers a Python implementation and only falls back to the
-- Vimscript one, which is the one under test, when no provider answers.
args = { '-u', 'NORC', '--cmd', 'let g:loaded_python3_provider = 0' },
-- POSIX TZ signs are inverted: GMT-14 is UTC+14, the easternmost offset.
env = { TZ = 'GMT-14' },
})
end)
describe('function msgpack#strptime', function()
it('works east of UTC+12 #7625', function()
eq(0, nvim_eval('has("python3")'))
for _, v in ipairs({ 0, 10, 100000, 204, 1000000000 }) do
local time = nvim_eval(('strftime("%%Y-%%m-%%dT%%H:%%M:%%S", %d)'):format(v))
eq(v, nvim_eval(('msgpack#strptime("%%Y-%%m-%%dT%%H:%%M:%%S", "%s")'):format(time)))
end
end)
end)
end)