diff options
author | Lars Henriksen <LarsHenriksen@get2net.dk> | 2018-10-31 15:23:41 +0100 |
---|---|---|
committer | Lukas Fleischer <lfleischer@calcurse.org> | 2018-11-10 12:19:28 +0100 |
commit | 4263a2850431b7328699c713b4e97667f9ba02e2 (patch) | |
tree | c15245e7187be4f081a90e851e77ae7093e8af64 /src | |
parent | f91b7cdee0efb7af2989eed56b6e3248da2b6712 (diff) | |
download | calcurse-4263a2850431b7328699c713b4e97667f9ba02e2.tar.gz calcurse-4263a2850431b7328699c713b4e97667f9ba02e2.zip |
DST fix: adjusting time in appointments
Calcurse saves time and date information on disk as local time in readable text
file format. When loaded from disk or when entered by the user, local time is
converted to Unix time (seconds since 00:00:00, 1 January 1970). When
displayed, and later when saved to disk, the Unix time is converted back to
readable local time. Both conversions depend on DST.
Hence, if midnight for a day with DST in effect (i.e. local time) is converted,
increased with an amount and converted back, the amount has changed if DST is
_not_ in effect for the resulting time. In general, calculations on Unix time
variables should be used with caution because of the DST-dependent conversions.
Instead, the calculations should be performed on local time data with the help
of mktime().
The commit fixes start time for pasted appointments (ordinary and recurrent)
and the 'until'-date of recurrent appointments, pasted as well as new and
edited. The latter problem is slightly different in that the adjustment is a
number of days, as it is for exception dates.
Update of the date in parse_datetime() has been corrected to be similar to
update of the time, although no problem has been identified.
Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
Diffstat (limited to 'src')
-rw-r--r-- | src/apoint.c | 5 | ||||
-rw-r--r-- | src/recur.c | 15 | ||||
-rw-r--r-- | src/ui-day.c | 4 | ||||
-rw-r--r-- | src/utils.c | 28 |
4 files changed, 39 insertions, 13 deletions
diff --git a/src/apoint.c b/src/apoint.c index a1c4934..c485477 100644 --- a/src/apoint.c +++ b/src/apoint.c @@ -326,7 +326,10 @@ void apoint_switch_notify(struct apoint *apt) void apoint_paste_item(struct apoint *apt, long date) { - apt->start = date + get_item_time(apt->start); + struct tm t; + + localtime_r((time_t *)&apt->start, &t); + apt->start = update_time_in_date(date, t.tm_hour, t.tm_min); LLIST_TS_LOCK(&alist_p); LLIST_TS_ADD_SORTED(&alist_p, apt, apoint_cmp); diff --git a/src/recur.c b/src/recur.c index 2a62e94..e4cc1b2 100644 --- a/src/recur.c +++ b/src/recur.c @@ -995,18 +995,23 @@ void recur_event_paste_item(struct recur_event *rev, long date) void recur_apoint_paste_item(struct recur_apoint *rapt, long date) { - long time_shift; + long ostart = rapt->start; + int days; llist_item_t *i; + struct tm t; + + localtime_r((time_t *)&rapt->start, &t); + rapt->start = update_time_in_date(date, t.tm_hour, t.tm_min); - time_shift = (date + get_item_time(rapt->start)) - rapt->start; - rapt->start += time_shift; + /* The number of days shifted. */ + days = (rapt->start - ostart) / DAYINSEC; if (rapt->rpt->until != 0) - rapt->rpt->until += time_shift; + rapt->rpt->until = date_sec_change(rapt->rpt->until, 0, days); LLIST_FOREACH(&rapt->exc, i) { struct excp *exc = LLIST_GET_DATA(i); - exc->st += time_shift; + exc->st = date_sec_change(exc->st, 0, days); } LLIST_TS_LOCK(&recur_alist_p); diff --git a/src/ui-day.c b/src/ui-day.c index 9a118dc..979ecc0 100644 --- a/src/ui-day.c +++ b/src/ui-day.c @@ -332,7 +332,7 @@ static void update_rept(struct rpt **rpt, const long start) keys_wgetch(win[KEY].p); continue; } - newuntil = start + days * DAYINSEC; + newuntil = date_sec_change(start, 0, days); } else { int year, month, day; if (!parse_date(timstr, conf.input_datefmt, &year, @@ -836,7 +836,7 @@ void ui_day_item_repeat(void) keys_wgetch(win[KEY].p); continue; } - until = p->start + days * DAYINSEC; + until = date_sec_change(p->start, 0, days); } else { int year, month, day; if (!parse_date(user_input, conf.input_datefmt, diff --git a/src/utils.c b/src/utils.c index 09f1f98..7b02f12 100644 --- a/src/utils.c +++ b/src/utils.c @@ -530,7 +530,27 @@ long date_sec_change(long date, int delta_month, int delta_day) return t; } -/* A time in seconds is updated with new hour and minutes and returned. */ +/* + * A date in seconds is updated with new day, month and year and returned. + */ +static time_t update_date_in_date(time_t date, int day, int month, int year) +{ + struct tm lt; + + localtime_r(&date, <); + lt.tm_mday = day; + lt.tm_mon = month - 1; + lt.tm_year = year - 1900; + lt.tm_isdst = -1; + date = mktime(<); + EXIT_IF(date == -1, _("error in mktime")); + + return date; +} + +/* + * A date in seconds is updated with new hour and minutes and returned. + */ time_t update_time_in_date(time_t date, unsigned hr, unsigned mn) { struct tm lt; @@ -1218,10 +1238,8 @@ int parse_datetime(const char *string, time_t *ts, time_t dur) } else if (parse_date_interactive(d, &year, &month, &day)) { ret |= PARSE_DATETIME_HAS_DATE; } - if (ret & PARSE_DATETIME_HAS_DATE) { - struct date date = { day , month, year }; - *ts = date2sec(date, 0, 0) + get_item_time(*ts); - } + if (ret & PARSE_DATETIME_HAS_DATE) + *ts = update_date_in_date(*ts, day, month, year); if (ret & PARSE_DATETIME_HAS_TIME) *ts = update_time_in_date(*ts, hour, minute); mem_free(d); |