fix(agenda): all day event offsets, locale display

Currently, allDay events are off by one day for negative timezones. Per
the CalendarContract:

    If allDay is set to 1 eventTimezone must be "UTC" and the time must
    correspond to a midnight boundary.

For example, in GMT-2:00, an all day event on December 2nd (beginning at
00:00:00) will be wrongly displayed as starting on December 1st, since
the locale will determine that the event's start time is actually
22:00:00 on Dec 1.

Source:

https://developer.android.com/reference/android/provider/CalendarContract.Events.html

This commit:

* Corrects the offset back to UTC 00:00:00 for allDay events

* Fixes the conditional for single-day all day events in showEvent()

* Fixes the display of formatDateShort() for some English locales by
  also removing any trailing commas or whitespace when the year is
  removed
pull/3695/head
thomas 2024-12-12 16:06:08 -05:00 committed by Thomas Anderson
parent 7238266124
commit bcf88c31f1
3 changed files with 21 additions and 11 deletions

View File

@ -15,3 +15,4 @@
0.13: Show day of the week in date 0.13: Show day of the week in date
0.14: Fixed "Today" and "Yesterday" wrongly displayed for allDay events on some time zones 0.14: Fixed "Today" and "Yesterday" wrongly displayed for allDay events on some time zones
0.15: Minor code improvements 0.15: Minor code improvements
0.16: Correct date for all day events in negative timezones, improve locale display

View File

@ -30,11 +30,16 @@ var settings = require("Storage").readJSON("agenda.settings.json",true)||{};
CALENDAR=CALENDAR.sort((a,b)=>a.timestamp - b.timestamp); CALENDAR=CALENDAR.sort((a,b)=>a.timestamp - b.timestamp);
function getDate(timestamp) { function getDate(timestamp, allDay) {
return new Date(timestamp*1000); // All day events are always in UTC and always start at 00:00:00, so we
// need to "undo" the timezone offsetting to make sure that the day is
// correct.
var offset = allDay ? new Date().getTimezoneOffset() * 60 : 0
return new Date((timestamp+offset)*1000);
} }
function formatDay(date) { function formatDay(date) {
let formattedDate = Locale.dow(date,1) + " " + Locale.date(date).replace(/\d\d\d\d/,""); let formattedDate = Locale.dow(date,1) + " " + Locale.date(date).replace(/,*\s*\d\d\d\d/,"");
if (!settings.useToday) { if (!settings.useToday) {
return formattedDate; return formattedDate;
} }
@ -57,8 +62,9 @@ function formatDateLong(date, includeDay, allDay) {
} }
return shortTime; return shortTime;
} }
function formatDateShort(date, allDay) { function formatDateShort(date, allDay) {
return formatDay(date)+(allDay?"":Locale.time(date,1)+Locale.meridian(date)); return formatDay(date)+(allDay?"":" "+Locale.time(date,1)+Locale.meridian(date));
} }
var lines = []; var lines = [];
@ -69,16 +75,19 @@ function showEvent(ev) {
//var lines = []; //var lines = [];
if (ev.title) lines = g.wrapString(ev.title, g.getWidth()-10); if (ev.title) lines = g.wrapString(ev.title, g.getWidth()-10);
var titleCnt = lines.length; var titleCnt = lines.length;
var start = getDate(ev.timestamp); var start = getDate(ev.timestamp, ev.allDay);
var end = getDate((+ev.timestamp) + (+ev.durationInSeconds)); // All day events end at the midnight boundary of the following day. Here, we
// subtract one second for all day events so the days display correctly.
const allDayEndCorrection = ev.allDay ? 1 : 0;
var end = getDate((+ev.timestamp) + (+ev.durationInSeconds) - allDayEndCorrection, ev.allDay);
var includeDay = true; var includeDay = true;
if (titleCnt) lines.push(""); // add blank line after title if (titleCnt) lines.push(""); // add blank line after title
if(start.getDay() == end.getDay() && start.getMonth() == end.getMonth()) if(start.getDay() == end.getDay() && start.getMonth() == end.getMonth())
includeDay = false; includeDay = false;
if(includeDay && ev.allDay) { if(!includeDay && ev.allDay) {
//single day all day (average to avoid getting previous day) //single day all day
lines = lines.concat( lines = lines.concat(
g.wrapString(formatDateLong(new Date((start+end)/2), includeDay, ev.allDay), g.getWidth()-10)); g.wrapString(formatDateLong(start, includeDay, ev.allDay), g.getWidth()-10));
} else if(includeDay || ev.allDay) { } else if(includeDay || ev.allDay) {
lines = lines.concat( lines = lines.concat(
/*LANG*/"Start"+":", /*LANG*/"Start"+":",
@ -137,7 +146,7 @@ function showList() {
if (!ev) return; if (!ev) return;
var isPast = false; var isPast = false;
var x = r.x+2, title = ev.title; var x = r.x+2, title = ev.title;
var body = formatDateShort(getDate(ev.timestamp),ev.allDay)+"\n"+(ev.location?ev.location:/*LANG*/"No location"); var body = formatDateShort(getDate(ev.timestamp, ev.allDay),ev.allDay)+"\n"+(ev.location?ev.location:/*LANG*/"No location");
if(settings.pastEvents) isPast = ev.timestamp + ev.durationInSeconds < (new Date())/1000; if(settings.pastEvents) isPast = ev.timestamp + ev.durationInSeconds < (new Date())/1000;
if (title) g.setFontAlign(-1,-1).setFont(fontBig) if (title) g.setFontAlign(-1,-1).setFont(fontBig)
.setColor(isPast ? "#888" : g.theme.fg).drawString(title, x+4,r.y+2); .setColor(isPast ? "#888" : g.theme.fg).drawString(title, x+4,r.y+2);

View File

@ -1,7 +1,7 @@
{ {
"id": "agenda", "id": "agenda",
"name": "Agenda", "name": "Agenda",
"version": "0.15", "version": "0.16",
"description": "Simple agenda", "description": "Simple agenda",
"icon": "agenda.png", "icon": "agenda.png",
"screenshots": [{"url":"screenshot_agenda_overview.png"}, {"url":"screenshot_agenda_event1.png"}, {"url":"screenshot_agenda_event2.png"}], "screenshots": [{"url":"screenshot_agenda_overview.png"}, {"url":"screenshot_agenda_event1.png"}, {"url":"screenshot_agenda_event2.png"}],