feat: list reads alarms, and _format_time for human-readable dates

This commit is contained in:
Lewis Wynne 2026-04-01 22:33:48 +01:00
parent 47fe849e9f
commit 97e5dcbac4
2 changed files with 101 additions and 3 deletions

81
nag
View file

@ -502,6 +502,55 @@ _get_alarm_field() {
fi fi
} }
# Usage:
# _format_time <timestamp>
#
# Description:
# Format a unix timestamp for display.
# Time: dots for minutes (3.30pm), omit .00 (3pm).
# Date: Today / Tomorrow / day-of-week within 6 days /
# Next <day> within 13 days / Mon Dec 25 beyond that.
_format_time() {
local _timestamp="${1}"
# Format time: drop .00, use dots for minutes.
local _hour _minute _ampm _time_fmt
_hour="$(date -d "@${_timestamp}" "+%-I")"
_minute="$(date -d "@${_timestamp}" "+%M")"
_ampm="$(date -d "@${_timestamp}" "+%p" | tr '[:upper:]' '[:lower:]')"
if [[ "${_minute}" == "00" ]]
then
_time_fmt="${_hour}${_ampm}"
else
_time_fmt="${_hour}.${_minute}${_ampm}"
fi
# Format date prefix.
local _alarm_date _today _days_away
_alarm_date="$(date -d "@${_timestamp}" +%Y-%m-%d)"
_today="$(date +%Y-%m-%d)"
_days_away=$(( ( $(date -d "${_alarm_date}" +%s) - $(date -d "${_today}" +%s) ) / 86400 ))
local _date_prefix
if (( _days_away == 0 ))
then
_date_prefix="Today"
elif (( _days_away == 1 ))
then
_date_prefix="Tomorrow"
elif (( _days_away <= 6 ))
then
_date_prefix="$(date -d "@${_timestamp}" "+%A")"
elif (( _days_away <= 13 ))
then
_date_prefix="Next $(date -d "@${_timestamp}" "+%A")"
else
_date_prefix="$(date -d "@${_timestamp}" "+%a %b %-d")"
fi
printf "%s, %s" "${_date_prefix}" "${_time_fmt}"
}
# Usage: # Usage:
# _parse_time <time-string> # _parse_time <time-string>
# #
@ -652,6 +701,36 @@ list() {
printf "Nothing to nag about.\\n" printf "Nothing to nag about.\\n"
return 0 return 0
fi fi
_read_alarms
# Sort alarms by timestamp (field 2).
local -a _sorted
IFS=$'\n' _sorted=($(printf "%s\n" "${_ALARMS[@]}" | sort -t$'\t' -k2 -n))
IFS=$'\n\t'
local _line
for _line in "${_sorted[@]}"
do
[[ -n "${_line}" ]] || continue
local _id _timestamp _rule _message _human_time _rule_display
_id="$(_get_alarm_field "${_line}" 1)"
_timestamp="$(_get_alarm_field "${_line}" 2)"
_rule="$(_get_alarm_field "${_line}" 3)"
_message="$(_get_alarm_field "${_line}" 4)"
_human_time="$(_format_time "${_timestamp}")"
if [[ -n "${_rule}" ]]
then
_rule_display="every ${_rule//,/, }, "
else
_rule_display=""
fi
printf "[%s] %s%s — %s\\n" "${_id}" "${_rule_display}" "${_human_time}" "${_message}"
done
} }
# at ########################################################################## # at ##########################################################################
@ -693,7 +772,7 @@ at() {
_prompt_cron _prompt_cron
local _human_time local _human_time
_human_time="$(date -d "@${_timestamp}" "+%a %b %-d %-I:%M%p" | sed 's/AM/am/;s/PM/pm/')" _human_time="$(_format_time "${_timestamp}")"
printf "[%s] %s — %s\\n" "${_id}" "${_human_time}" "${_message}" printf "[%s] %s — %s\\n" "${_id}" "${_human_time}" "${_message}"
} }

View file

@ -50,8 +50,7 @@ load test_helper
@test "at creates a one-shot alarm" { @test "at creates a one-shot alarm" {
run_nag at "tomorrow 3pm" "take a break" run_nag at "tomorrow 3pm" "take a break"
[ "${status}" -eq 0 ] [ "${status}" -eq 0 ]
[[ "${output}" =~ "[1]" ]] [[ "${output}" =~ "[1] Tomorrow, 3pm — take a break" ]]
[[ "${output}" =~ "take a break" ]]
[ -f "${NAG_PATH}" ] [ -f "${NAG_PATH}" ]
[ "$(wc -l < "${NAG_PATH}")" -eq 1 ] [ "$(wc -l < "${NAG_PATH}")" -eq 1 ]
# Verify TSV structure: id<TAB>timestamp<TAB><TAB>message # Verify TSV structure: id<TAB>timestamp<TAB><TAB>message
@ -88,3 +87,23 @@ load test_helper
[ "${status}" -eq 0 ] [ "${status}" -eq 0 ]
[[ "${output}" =~ ^[0-9]+\.[0-9]+(_[a-zA-Z0-9]+)*$ ]] [[ "${output}" =~ ^[0-9]+\.[0-9]+(_[a-zA-Z0-9]+)*$ ]]
} }
@test "list shows formatted alarms with smart dates" {
run_nag at "tomorrow 3pm" "take a break"
run_nag
[ "${status}" -eq 0 ]
[[ "${output}" =~ "[1] Tomorrow, 3pm — take a break" ]]
}
@test "list sorts alarms by time" {
run_nag at "tomorrow 3pm" "take a break"
run_nag at "tomorrow 9am" "standup"
run_nag
[ "${status}" -eq 0 ]
# 9am should come before 3pm in output.
local _first_line _second_line
_first_line="$(printf "%s\n" "${output}" | head -1)"
_second_line="$(printf "%s\n" "${output}" | sed -n '2p')"
[[ "${_first_line}" =~ "standup" ]]
[[ "${_second_line}" =~ "take a break" ]]
}