Update JSON output.

This commit is contained in:
Dianne Skoll
2025-09-03 13:57:25 -04:00
parent bcfee04cae
commit 703907c94d
6 changed files with 73 additions and 2 deletions

View File

@@ -693,6 +693,7 @@ Its syntax is:
[\fBSCANFROM\fR \fIscan_date\fR | \fBFROM\fR \fIstart_date\fR]
[\fBDURATION\fR \fIduration\fR]
[\fBTAG\fR \fItag\fR]
[\fBTZ\fR \fItimezone\fR]
[\fBINFO\fR "\fIinfo_string\fR"]
\fBMSG\fR | \fBMSF\fR | \fBRUN\fR | \fBCAL\fR | \fBSATISFY\fR |
\fBSPECIAL\fR \fIspecial\fR | \fBPS\fR | \fBPSFILE\fR
@@ -2042,6 +2043,55 @@ In Purge Mode, \fBRemind\fR will not purge TODOs unless they have been marked
as complete. In the case of a recurring TODO, \fBRemind\fR will not purge
it until the last occurrence is marked as complete.
.PP
.SH TIMEZONE SUPPORT
.PP
The \fBREM\fR command supports an optional \fBTZ\fR keyword, which should
be followed by the \fIcase-sensitive\fR time zone name in which the
command is to be interpreted. Note that if you use the \fBTZ\fR keyword,
then you \fImust also\fR use an \fBAT\fR clause. Here are some examples:
.PP
.nf
REM Wednesday AT 14:00 TZ America/Toronto MSG 2PM Eastern (%2).
REM Wednesday AT 23:59 TZ America/Los_Angeles SATISFY [$Td == 13] MSG Foo %b %2.
.fi
.PP
Within a \fBSATISFY\fR clause, all trigger functions are interpreted in
the time zone specified in the \fBREM\fR command. Outside the \fBREM\fR
command, however, trigger functions are adjusted to the local time
zone. If the local time zone is UTC and we feed \fBRemind\fR the
following file on 2025-09-04 UTC:
.PP
.nf
SET $AddBlankLines 0
BANNER %
REM Wednesday AT 14:00 TZ America/Toronto MSG 2PM Eastern (%2).
set a $T
set b $Tt
REM MSG a = [a], b = [b]
REM Wednesday AT 23:59 TZ America/Los_Angeles SATISFY [$Td == 13] MSG Foo %b %2.
set c $T
set d $Tt
REM MSG c = [c], d = [d]
.fi
.PP
Then the output is as follows:
.PP
.nf
a = 2025-09-10, b = 18:00
c = 2026-05-14, d = 06:59
.fi
.PP
That is because the trigger date of the first (Wednesday, 2025-09-10
at 14:00 Eastern time) is 2025-09-10 at 18:00 UTC. In the second case,
Wednesday, 13 May 2026 is the SATISFied trigger date, which is
adjusted to Thursday, 14 May 2026 at 06:59 UTC because of the
time zone adjustment.
.PP
If you use an invalid time zone name after the \fBTZ\fR keyword,
results are undefined. Unfortunately, \fBRemind\fR cannot diagnose
this error becase the C library \fBtzset()\fR function has no
error return.
.PP
.SH THE OMIT COMMAND
.PP
In addition to being a keyword in the \fBREM\fR command,

View File

@@ -2316,6 +2316,9 @@ static int DoCalRem(ParsePtr p, int col)
e->nonconst_expr = nonconst_expr;
e->if_depth = get_if_pointer() - get_base_if_pointer();
e->trig = trig;
if (e->trig.tz) {
e->trig.tz = StrDup(e->trig.tz);
}
e->tt = tim;
#ifdef REM_USE_WCHAR
e->wc_pos = NULL;
@@ -2412,6 +2415,9 @@ static void WriteSimpleEntryProtocol1(CalEntry const *e)
void WriteJSONTimeTrigger(TimeTrig const *tt)
{
PrintJSONKeyPairTime("time", tt->ttime);
if (tt->ttime != tt->ttime_orig) {
PrintJSONKeyPairTime("time_in_tz", tt->ttime_orig);
}
PrintJSONKeyPairTime("nexttime", tt->nexttime);
PrintJSONKeyPairInt("tdelta", tt->delta);
PrintJSONKeyPairInt("trep", tt->rep);
@@ -2543,6 +2549,10 @@ void WriteJSONTrigger(Trigger const *t, int include_tags)
PrintJSONKeyPairDate("from", t->from);
PrintJSONKeyPairInt("priority", t->priority);
PrintJSONKeyPairDateTime("eventstart", t->eventstart);
if (t->eventstart_orig != NO_TIME &&
t->eventstart_orig != t->eventstart) {
PrintJSONKeyPairDateTime("eventstart_in_tz", t->eventstart_orig);
}
if (t->eventduration != NO_TIME) {
PrintJSONKeyPairInt("eventduration", t->eventduration);
}
@@ -2564,6 +2574,7 @@ void WriteJSONTrigger(Trigger const *t, int include_tags)
}
PrintJSONKeyPairString("tags", DBufValue(&(t->tags)));
}
PrintJSONKeyPairString("tz", t->tz);
}
static void WriteSimpleEntryProtocol2(CalEntry *e)

View File

@@ -35,7 +35,7 @@ static int ComputeTrigDuration(TimeTrig const *t);
static int CalledEnterTimezone = 0;
int AdjustTriggerForTimeZone(Trigger const *trig, int dse, TimeTrig *tim)
int AdjustTriggerForTimeZone(Trigger *trig, int dse, TimeTrig *tim)
{
int y, m, d, hour, minute;
int r;
@@ -57,6 +57,8 @@ int AdjustTriggerForTimeZone(Trigger const *trig, int dse, TimeTrig *tim)
dse = DSE(tm.tm_year+1900, tm.tm_mon, tm.tm_mday);
tim->ttime = tm.tm_hour * 60 + tm.tm_min;
SaveAllTriggerInfo(trig, tim, dse, tim->ttime, 1);
/* Adjust eventstart also */
trig->eventstart = dse * MINUTES_PER_DAY + tim->ttime;
if (DebugFlag & DB_PRTTRIG) {
fprintf(ErrFp, "%s(%s): Trig(tz_adj %s) = %s, %d %s, %d AT %02d:%02d",
GetCurrentFilename(), line_range(LineNoStart, LineNo), trig->tz,
@@ -612,6 +614,9 @@ int DoRem(ParsePtr p)
}
if (tim.ttime != NO_TIME) {
PrintJSONKeyPairInt("time", tim.ttime);
if (tim.ttime_orig != tim.ttime) {
PrintJSONKeyPairInt("time_in_tz", tim.ttime_orig);
}
}
if (p->nonconst_expr) {
PrintJSONKeyPairInt("nonconst_expr", 1);
@@ -797,6 +802,7 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
trig->omitfunc[0] = 0;
trig->duration_days = 0;
trig->eventstart = NO_TIME;
trig->eventstart_orig = NO_TIME;
trig->eventduration = NO_TIME;
trig->maybe_uncomputable = 0;
DBufInit(&(trig->tags));
@@ -1971,6 +1977,7 @@ int DoSatRemind(Trigger *trig, TimeTrig *tt, ParsePtr p)
} else if (dse == start) {
if (tt->ttime != NO_TIME) {
trig->eventstart = MINUTES_PER_DAY * r + tt->ttime;
trig->eventstart_orig = trig->eventstart;
if (tt->duration != NO_TIME) {
trig->eventduration = tt->duration;
}

View File

@@ -298,6 +298,6 @@ int system_to_stderr(char const *cmd);
int system1(char const *cmd);
int tz_set_tz (char const *tz);
int tz_convert(int year, int month, int day, int hour, int minute, char const *src_tz, char const *tgt_tz, struct tm *tm);
int AdjustTriggerForTimeZone(Trigger const *trig, int dse, TimeTrig *tim);
int AdjustTriggerForTimeZone(Trigger *trig, int dse, TimeTrig *tim);
void EnterTimezone(char const *tz);
void ExitTimezone(char const *tz);

View File

@@ -453,6 +453,7 @@ AdjustTriggerForDuration(int today, int r, Trigger *trig, TimeTrig *tim, int sav
/* If we have an AT, save the original event start */
if (tim->ttime != NO_TIME) {
trig->eventstart = MINUTES_PER_DAY * r + tim->ttime;
trig->eventstart_orig = trig->eventstart;
if (tim->duration != NO_TIME) {
trig->eventduration = tim->duration;
}
@@ -515,6 +516,7 @@ int ComputeTrigger(int today, Trigger *trig, TimeTrig *tim,
if (r == today) {
if (tim->ttime != NO_TIME) {
trig->eventstart = MINUTES_PER_DAY * r + tim->ttime;
trig->eventstart_orig = trig->eventstart;
if (tim->duration != NO_TIME) {
trig->eventduration = tim->duration;
}

View File

@@ -141,6 +141,7 @@ typedef struct {
int priority;
int duration_days; /* Duration converted to days to search */
int eventstart; /* Original event start (datetime) */
int eventstart_orig; /* Original event start in TZ (datetime) */
int eventduration; /* Original event duration (minutes) */
int maybe_uncomputable; /* Suppress "can't compute trigger" warnings */
int addomit; /* Add trigger date to global OMITs */