Skip to content

Commit b1b42d1

Browse files
fix: Consider dst when calculating the diff. Fixes #538
1 parent 77b4cc8 commit b1b42d1

File tree

2 files changed

+39
-2
lines changed

2 files changed

+39
-2
lines changed

lua/orgmode/objects/date.lua

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ local time_format = '%H:%M'
2020
---@field min number
2121
---@field timestamp number
2222
---@field timestamp_end number
23+
---@field is_dst boolean
2324
---@field is_date_range_start boolean
2425
---@field is_date_range_end boolean
2526
---@field related_date_range Date
@@ -77,6 +78,7 @@ function Date:new(data)
7778
opts.timestamp = os.time(opts)
7879
opts.date_only = date_only
7980
opts.dayname = os.date('%a', opts.timestamp)
81+
opts.is_dst = os.date('*t', opts.timestamp).isdst
8082
opts.adjustments = data.adjustments or {}
8183
opts.timestamp_end = data.timestamp_end
8284
opts.is_date_range_start = data.is_date_range_start or false
@@ -638,11 +640,16 @@ function Date:format(format)
638640
end
639641

640642
---@param from Date
641-
---@param span? string
643+
---@param span? 'day' | 'minute'
642644
---@return number
643645
function Date:diff(from, span)
644646
span = span or 'day'
645-
local diff = self:start_of(span).timestamp - from:start_of(span).timestamp
647+
local to_date = self:start_of(span)
648+
local from_date = from:start_of(span)
649+
local diff = to_date.timestamp - from_date.timestamp
650+
if to_date.is_dst ~= from_date.is_dst then
651+
diff = diff + (to_date.is_dst and 3600 or -3600)
652+
end
646653
local durations = {
647654
day = 86400,
648655
minute = 60,

tests/plenary/object/date_spec.lua

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,26 @@ describe('Date object', function()
362362
}, dates)
363363
end)
364364

365+
it('should return proper diff in days between DST difference', function()
366+
-- No overlap
367+
local date = Date.from_string('2023-06-26')
368+
local end_date = Date.from_string('2023-06-27')
369+
assert.are.same(1, end_date:diff(date))
370+
assert.are.same(1440, end_date:diff(date, 'minute'))
371+
372+
-- DST start overlap
373+
local date_no_dst = Date.from_string('2023-03-26 Sun')
374+
local end_date_dst = Date.from_string('2023-03-27 Mon')
375+
assert.are.same(1, end_date_dst:diff(date_no_dst))
376+
assert.are.same(1440, end_date_dst:diff(date_no_dst, 'minute'))
377+
378+
-- DST end overlap
379+
local date_dst = Date.from_string('2023-10-28 Sun')
380+
local end_date_no_dst = Date.from_string('2023-10-29 Mon')
381+
assert.are.same(1, end_date_no_dst:diff(date_dst))
382+
assert.are.same(1440, end_date_no_dst:diff(date_dst, 'minute'))
383+
end)
384+
365385
it('should format the date', function()
366386
local date = Date.from_string('2021-05-12 14:00')
367387
assert.are.same('Wednesday 12 May', date:format('%A %d %B'))
@@ -394,6 +414,7 @@ describe('Date object', function()
394414
date_only = true,
395415
day = 15,
396416
dayname = 'Sat',
417+
is_dst = true,
397418
hour = 0,
398419
min = 0,
399420
month = 5,
@@ -425,6 +446,7 @@ describe('Date object', function()
425446
dayname = 'Sat',
426447
hour = 0,
427448
min = 0,
449+
is_dst = true,
428450
month = 5,
429451
is_date_range_start = false,
430452
is_date_range_end = false,
@@ -448,6 +470,7 @@ describe('Date object', function()
448470
hour = 9,
449471
min = 25,
450472
month = 6,
473+
is_dst = true,
451474
is_date_range_start = false,
452475
is_date_range_end = false,
453476
related_date_range = nil,
@@ -476,6 +499,7 @@ describe('Date object', function()
476499
dayname = 'Sat',
477500
hour = 0,
478501
min = 0,
502+
is_dst = true,
479503
month = 5,
480504
is_date_range_start = false,
481505
is_date_range_end = false,
@@ -499,6 +523,7 @@ describe('Date object', function()
499523
hour = 0,
500524
min = 0,
501525
month = 5,
526+
is_dst = true,
502527
is_date_range_start = false,
503528
is_date_range_end = false,
504529
related_date_range = nil,
@@ -630,6 +655,7 @@ describe('Date object', function()
630655
dayname = 'Sat',
631656
hour = 14,
632657
min = 30,
658+
is_dst = true,
633659
month = 5,
634660
is_date_range_start = false,
635661
is_date_range_end = false,
@@ -654,6 +680,7 @@ describe('Date object', function()
654680
hour = 0,
655681
min = 0,
656682
month = 5,
683+
is_dst = true,
657684
is_date_range_start = false,
658685
is_date_range_end = false,
659686
related_date_range = nil,
@@ -681,6 +708,7 @@ describe('Date object', function()
681708
day = 15,
682709
dayname = 'Sat',
683710
hour = 0,
711+
is_dst = true,
684712
min = 0,
685713
month = 5,
686714
is_date_range_start = true,
@@ -705,6 +733,7 @@ describe('Date object', function()
705733
hour = 0,
706734
min = 0,
707735
month = 5,
736+
is_dst = true,
708737
is_date_range_start = false,
709738
is_date_range_end = true,
710739
related_date_range = dates[1],
@@ -730,6 +759,7 @@ describe('Date object', function()
730759
is_date_range_start = false,
731760
is_date_range_end = false,
732761
related_date_range = nil,
762+
is_dst = true,
733763
range = Range:new({
734764
start_line = 1,
735765
end_line = 1,

0 commit comments

Comments
 (0)