diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/data/reminders/ReminderNotifier.kt b/app/src/main/java/de/jeanlucmakiola/calendula/data/reminders/ReminderNotifier.kt
index 17d7213..7ca24b7 100644
--- a/app/src/main/java/de/jeanlucmakiola/calendula/data/reminders/ReminderNotifier.kt
+++ b/app/src/main/java/de/jeanlucmakiola/calendula/data/reminders/ReminderNotifier.kt
@@ -88,6 +88,7 @@ class ReminderNotifier @Inject constructor(
is24Hour = is24Hour,
today = Instant.now().atZone(zone).toLocalDate(),
firstDayOfWeek = firstDayOfWeek,
+ todayLabel = context.getString(R.string.reminder_day_today),
tomorrowLabel = context.getString(R.string.reminder_day_tomorrow),
yesterdayLabel = context.getString(R.string.reminder_day_yesterday),
)
diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/data/reminders/ReminderTimeText.kt b/app/src/main/java/de/jeanlucmakiola/calendula/data/reminders/ReminderTimeText.kt
index cdc7462..c169d70 100644
--- a/app/src/main/java/de/jeanlucmakiola/calendula/data/reminders/ReminderTimeText.kt
+++ b/app/src/main/java/de/jeanlucmakiola/calendula/data/reminders/ReminderTimeText.kt
@@ -27,12 +27,12 @@ import java.util.Locale
* alone would be ambiguous)
* - timed, crossing days: "11 Jun, 23:30 – 12 Jun, 00:30" (medium date + short time,
* already unambiguous)
- * - all-day, one day: "11 Jun 2026"
- * - all-day, multi-day: "11 Jun 2026 – 12 Jun 2026"
+ * - all-day, one day: "Tomorrow" / "Thu" / "11 Jun 2026" (same relative rules,
+ * plus [todayLabel] — no time range to lean on)
+ * - all-day, multi-day: "Tomorrow – 12 Jun 2026" (relative start, explicit end)
*
- * All-day instances already carry an explicit date, so they never gain a
- * relative prefix. They store UTC midnights with an exclusive end, so they are
- * read in UTC and the end day is the last *covered* day.
+ * All-day instances store UTC midnights with an exclusive end, so they are read
+ * in UTC and the end day is the last *covered* day (issue #308).
*/
fun reminderTimeText(
beginMillis: Long,
@@ -43,6 +43,7 @@ fun reminderTimeText(
is24Hour: Boolean,
today: LocalDate,
firstDayOfWeek: DayOfWeek,
+ todayLabel: String,
tomorrowLabel: String,
yesterdayLabel: String,
): String {
@@ -53,11 +54,16 @@ fun reminderTimeText(
val lastDay = Instant.ofEpochMilli(endMillis).atZone(ZoneOffset.UTC).toLocalDate()
.minusDays(1)
.coerceAtLeast(firstDay)
- return if (lastDay == firstDay) {
- dateFormat.format(firstDay)
- } else {
- dateFormat.format(firstDay) + RANGE + dateFormat.format(lastDay)
- }
+ val start = relativeDayPrefix(
+ day = firstDay,
+ today = today,
+ firstDayOfWeek = firstDayOfWeek,
+ locale = locale,
+ dateFormat = dateFormat,
+ tomorrowLabel = tomorrowLabel,
+ yesterdayLabel = yesterdayLabel,
+ ) ?: todayLabel
+ return if (lastDay == firstDay) start else start + RANGE + dateFormat.format(lastDay)
}
val timeFormat = timeOfDayFormatter(is24Hour, locale)
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index f1dcca0..323904d 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -353,6 +353,7 @@
Snooze
Dismiss
+ Today
Tomorrow
Yesterday
diff --git a/app/src/test/java/de/jeanlucmakiola/calendula/data/reminders/ReminderTimeTextTest.kt b/app/src/test/java/de/jeanlucmakiola/calendula/data/reminders/ReminderTimeTextTest.kt
index c8014a1..1b7791e 100644
--- a/app/src/test/java/de/jeanlucmakiola/calendula/data/reminders/ReminderTimeTextTest.kt
+++ b/app/src/test/java/de/jeanlucmakiola/calendula/data/reminders/ReminderTimeTextTest.kt
@@ -38,6 +38,7 @@ class ReminderTimeTextTest {
is24Hour = is24Hour,
today = today ?: java.time.Instant.ofEpochMilli(beginMillis).atZone(zone).toLocalDate(),
firstDayOfWeek = firstDayOfWeek,
+ todayLabel = "Today",
tomorrowLabel = "Tomorrow",
yesterdayLabel = "Yesterday",
)
@@ -130,38 +131,74 @@ class ReminderTimeTextTest {
}
@Test
- fun `all-day single day shows one date, read in UTC`() {
+ fun `all-day single day today reads as today, read in UTC`() {
val text = text(
beginMillis = utcMidnight(LocalDate.of(2026, 6, 11)),
endMillis = utcMidnight(LocalDate.of(2026, 6, 12)),
isAllDay = true,
// Zone must not matter for all-day events: UTC midnight is
// 02:00 in Berlin — naive local reading would shift the day.
+ zone = ZoneId.of("America/Los_Angeles"),
today = LocalDate.of(2026, 6, 11),
)
- assertThat(text).isEqualTo("11.06.2026")
+ assertThat(text).isEqualTo("Today")
}
@Test
- fun `all-day event tomorrow still shows the exact date, no relative prefix`() {
+ fun `all-day event tomorrow reads as tomorrow`() {
val text = text(
beginMillis = utcMidnight(LocalDate.of(2026, 6, 12)),
endMillis = utcMidnight(LocalDate.of(2026, 6, 13)),
isAllDay = true,
today = LocalDate.of(2026, 6, 11),
)
- assertThat(text).isEqualTo("12.06.2026")
+ assertThat(text).isEqualTo("Tomorrow")
}
@Test
- fun `all-day multi-day shows the last covered day, not the exclusive end`() {
+ fun `all-day event later this week reads as the short weekday`() {
+ // 2026-06-11 is a Thursday; Saturday the 13th shares its week.
val text = text(
- beginMillis = utcMidnight(LocalDate.of(2026, 6, 11)),
- endMillis = utcMidnight(LocalDate.of(2026, 6, 13)),
+ beginMillis = utcMidnight(LocalDate.of(2026, 6, 13)),
+ endMillis = utcMidnight(LocalDate.of(2026, 6, 14)),
+ isAllDay = true,
+ locale = Locale.US,
+ today = LocalDate.of(2026, 6, 11),
+ )
+ assertThat(text).isEqualTo("Sat")
+ }
+
+ @Test
+ fun `all-day event next week falls back to the exact date`() {
+ val text = text(
+ beginMillis = utcMidnight(LocalDate.of(2026, 6, 16)),
+ endMillis = utcMidnight(LocalDate.of(2026, 6, 17)),
isAllDay = true,
today = LocalDate.of(2026, 6, 11),
)
- assertThat(text).isEqualTo("11.06.2026 – 12.06.2026")
+ assertThat(text).isEqualTo("16.06.2026")
+ }
+
+ @Test
+ fun `all-day multi-day reads relative start and the last covered day`() {
+ val text = text(
+ beginMillis = utcMidnight(LocalDate.of(2026, 6, 12)),
+ endMillis = utcMidnight(LocalDate.of(2026, 6, 14)),
+ isAllDay = true,
+ today = LocalDate.of(2026, 6, 11),
+ )
+ assertThat(text).isEqualTo("Tomorrow – 13.06.2026")
+ }
+
+ @Test
+ fun `all-day multi-day further out keeps both dates`() {
+ val text = text(
+ beginMillis = utcMidnight(LocalDate.of(2026, 7, 1)),
+ endMillis = utcMidnight(LocalDate.of(2026, 7, 3)),
+ isAllDay = true,
+ today = LocalDate.of(2026, 6, 11),
+ )
+ assertThat(text).isEqualTo("01.07.2026 – 02.07.2026")
}
@Test
@@ -173,6 +210,6 @@ class ReminderTimeTextTest {
isAllDay = true,
today = LocalDate.of(2026, 6, 11),
)
- assertThat(text).isEqualTo("11.06.2026")
+ assertThat(text).isEqualTo("Today")
}
}