Skip to content

Commit 8b3ec32

Browse files
fix: Handle same day date range with times in agenda
Closes #600
1 parent ac5f48c commit 8b3ec32

File tree

4 files changed

+69
-58
lines changed

4 files changed

+69
-58
lines changed

lua/orgmode/agenda/agenda_item.lua

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ function AgendaItem:_is_valid_for_date()
150150
end
151151

152152
function AgendaItem:_generate_label()
153-
local time = not self.headline_date.date_only and add_padding(self.headline_date:format_time()) or ''
153+
local time = self.headline_date:has_time() and add_padding(self:_format_time(self.headline_date)) or ''
154154
if self.headline_date:is_deadline() then
155155
if self.is_same_day then
156156
return time .. 'Deadline:'
@@ -187,6 +187,29 @@ function AgendaItem:_generate_label()
187187
return time
188188
end
189189

190+
---@private
191+
---@param date Date
192+
function AgendaItem:_format_time(date)
193+
local formatted_time = date:format_time()
194+
195+
-- e.g. <2024-09-24 Sun 10:00-11:00>
196+
if date:has_time_range() then
197+
return formatted_time
198+
end
199+
200+
local date_range_end = date:get_date_range_end()
201+
202+
-- Format same day date ranges as a time range if the date itself
203+
-- does not have a time range (e.g. <2023-09-24 Sun 10:00-11:00)
204+
-- example: <2023-09-24 Sun 10:00>--<2023-09-24 Sun 11:00>
205+
-- result: 10:00-11:00
206+
if date_range_end and date_range_end:is_same(date, 'day') and date_range_end:has_time() then
207+
return formatted_time .. '-' .. date_range_end:format_time()
208+
end
209+
210+
return formatted_time
211+
end
212+
190213
function AgendaItem:_generate_highlight()
191214
if self.headline_date:is_deadline() then
192215
if self.headline:is_done() then

lua/orgmode/agenda/views/agenda.lua

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,26 +22,26 @@ end
2222
local function sort_agenda_items(agenda_items)
2323
table.sort(agenda_items, function(a, b)
2424
if a.is_same_day and b.is_same_day then
25-
if not a.real_date.date_only and b.real_date.date_only then
25+
if a.real_date:has_time() and not b.real_date:has_time() then
2626
return true
2727
end
28-
if not b.real_date.date_only and a.real_date.date_only then
28+
if b.real_date:has_time() and not a.real_date:has_time() then
2929
return false
3030
end
31-
if not a.real_date.date_only and not b.real_date.date_only then
31+
if a.real_date:has_time() and b.real_date:has_time() then
3232
return a.real_date:is_before(b.real_date)
3333
end
3434
return sort_by_date_or_priority_or_category(a, b)
3535
end
3636

3737
if a.is_same_day and not b.is_same_day then
38-
if not a.real_date.date_only or (b.real_date:is_none() and not a.real_date:is_none()) then
38+
if a.real_date:has_time() or (b.real_date:is_none() and not a.real_date:is_none()) then
3939
return true
4040
end
4141
end
4242

4343
if not a.is_same_day and b.is_same_day then
44-
if not b.real_date.date_only or (a.real_date:is_none() and not b.real_date:is_none()) then
44+
if b.real_date:has_time() or (a.real_date:is_none() and not b.real_date:is_none()) then
4545
return false
4646
end
4747
end

lua/orgmode/objects/date.lua

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -317,19 +317,15 @@ end
317317

318318
---@return string
319319
function Date:to_string()
320-
local date = ''
321320
local format = date_format
322321
if self.dayname then
323322
format = format .. ' %a'
324323
end
325324

326-
if self.date_only then
327-
date = os.date(format, self.timestamp)
328-
else
329-
date = os.date(format .. ' ' .. time_format, self.timestamp)
330-
if self.timestamp_end then
331-
date = date .. '-' .. os.date(time_format, self.timestamp_end)
332-
end
325+
local date = tostring(os.date(format, self.timestamp))
326+
327+
if self:has_time() then
328+
date = date .. ' ' .. self:format_time()
333329
end
334330

335331
if #self.adjustments > 0 then
@@ -353,7 +349,7 @@ end
353349

354350
---@return string
355351
function Date:format_time()
356-
if self.date_only then
352+
if not self:has_time() then
357353
return ''
358354
end
359355
local t = self:format(time_format)
@@ -599,6 +595,25 @@ function Date:is_obsolete_range_end()
599595
return self.is_date_range_end and self.related_date_range:is_same(self, 'day')
600596
end
601597

598+
---@return boolean
599+
function Date:has_date_range_end()
600+
return self.related_date_range and self.is_date_range_start
601+
end
602+
603+
function Date:has_time()
604+
return not self.date_only
605+
end
606+
607+
---@return boolean
608+
function Date:has_time_range()
609+
return self.timestamp_end ~= nil
610+
end
611+
612+
---@return Date|nil
613+
function Date:get_date_range_end()
614+
return self:has_date_range_end() and self.related_date_range or nil
615+
end
616+
602617
---Return number of days for a date range
603618
---@return number
604619
function Date:get_date_range_days()

tests/plenary/agenda/agenda_item_spec.lua

Lines changed: 16 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -453,64 +453,37 @@ describe('Agenda item', function()
453453
assert.are.same('10:00...... Scheduled:', agenda_item.label)
454454
end)
455455

456-
it('should properly read date ranges bigger than current day', function()
456+
it('should properly read same day date ranges and time ranges', function()
457+
-- Same day date range
457458
local range_start = Date.from_string('2021-06-13 Sun 13:30')
458-
local range_end = range_start:add({ day = 4, hour = 1 })
459+
local range_end = range_start:add({ hour = 1 })
459460
local headline = generate(string.format('Some text <%s>--<%s>', range_start:to_string(), range_end:to_string()))
460461
local day = range_start:clone()
461462
local agenda_item = AgendaItem:new(headline.dates[1], headline, day)
462463
assert.is.True(agenda_item.is_valid)
463-
assert.are.same('13:30...... (1/5):', agenda_item.label)
464+
assert.are.same(agenda_item.label, '13:30-14:30 ')
464465
agenda_item = AgendaItem:new(headline.dates[2], headline, day)
465466
assert.is.False(agenda_item.is_valid)
466467

467-
day = day:add({ day = 1 })
468-
agenda_item = AgendaItem:new(headline.dates[1], headline, day)
468+
-- Time range on a single date
469+
local date_with_time_range = Date.from_string('2021-06-13 Sun 15:00-16:30')
470+
headline = generate(string.format('Some text <%s>', date_with_time_range:to_string()))
471+
agenda_item = AgendaItem:new(headline.dates[1], headline, date_with_time_range)
469472
assert.is.True(agenda_item.is_valid)
470-
assert.are.same('(2/5):', agenda_item.label)
471-
agenda_item = AgendaItem:new(headline.dates[2], headline, day)
472-
assert.is.False(agenda_item.is_valid)
473-
474-
day = day:add({ day = 1 })
475-
agenda_item = AgendaItem:new(headline.dates[1], headline, day)
476-
assert.is.True(agenda_item.is_valid)
477-
assert.are.same('(3/5):', agenda_item.label)
478-
agenda_item = AgendaItem:new(headline.dates[2], headline, day)
479-
assert.is.False(agenda_item.is_valid)
473+
assert.are.same(agenda_item.label, '15:00-16:30 ')
480474

481-
day = day:add({ day = 1 })
482-
agenda_item = AgendaItem:new(headline.dates[1], headline, day)
475+
-- Time range on a date has precedence over same day date range
476+
date_with_time_range = Date.from_string('2021-06-13 Sun 18:00-19:30')
477+
local date_with_time_range_end = Date.from_string('2021-06-13 Sun 20:00')
478+
headline = generate(string.format('Some text <%s>--<%s>', date_with_time_range:to_string(), date_with_time_range_end:to_string()))
479+
agenda_item = AgendaItem:new(headline.dates[1], headline, date_with_time_range)
483480
assert.is.True(agenda_item.is_valid)
484-
assert.are.same('(4/5):', agenda_item.label)
485-
agenda_item = AgendaItem:new(headline.dates[2], headline, day)
486-
assert.is.False(agenda_item.is_valid)
487-
488-
day = day:add({ day = 1 })
489-
agenda_item = AgendaItem:new(headline.dates[1], headline, day)
490-
assert.is.False(agenda_item.is_valid)
491-
492-
agenda_item = AgendaItem:new(headline.dates[2], headline, day)
493-
assert.is.True(agenda_item.is_valid)
494-
assert.are.same('14:30...... (5/5):', agenda_item.label)
481+
assert.are.same(agenda_item.label, '18:00-19:30 ')
495482
end)
496483

497-
it('should ignore end range if it is set to the same day as start day', function()
498484
local range_start = Date.from_string('2021-06-13 Sun 13:30')
499-
local range_end = range_start:add({ hour = 5 })
485+
local range_end = range_start:add({ day = 4, hour = 1 })
500486
local headline = generate(string.format('Some text <%s>--<%s>', range_start:to_string(), range_end:to_string()))
501-
local day = range_start:clone()
502-
local agenda_item = AgendaItem:new(headline.dates[1], headline, day)
503-
assert.is.True(agenda_item.is_valid)
504-
assert.are.same('13:30...... ', agenda_item.label)
505-
agenda_item = AgendaItem:new(headline.dates[2], headline, day)
506-
assert.is.False(agenda_item.is_valid)
507-
508-
day = day:add({ day = 1 })
509-
agenda_item = AgendaItem:new(headline.dates[1], headline, day)
510-
assert.is.False(agenda_item.is_valid)
511-
agenda_item = AgendaItem:new(headline.dates[2], headline, day)
512-
assert.is.False(agenda_item.is_valid)
513-
end)
514487

515488
it('should not show scheduled DONE item if disabled in config', function()
516489
local future_day = Date.now():add({ day = 2 })

0 commit comments

Comments
 (0)