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>
This commit is contained in:
parent
f91b7cdee0
commit
4263a28504
@ -326,7 +326,10 @@ void apoint_switch_notify(struct apoint *apt)
|
|||||||
|
|
||||||
void apoint_paste_item(struct apoint *apt, long date)
|
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_LOCK(&alist_p);
|
||||||
LLIST_TS_ADD_SORTED(&alist_p, apt, apoint_cmp);
|
LLIST_TS_ADD_SORTED(&alist_p, apt, apoint_cmp);
|
||||||
|
15
src/recur.c
15
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)
|
void recur_apoint_paste_item(struct recur_apoint *rapt, long date)
|
||||||
{
|
{
|
||||||
long time_shift;
|
long ostart = rapt->start;
|
||||||
|
int days;
|
||||||
llist_item_t *i;
|
llist_item_t *i;
|
||||||
|
struct tm t;
|
||||||
|
|
||||||
time_shift = (date + get_item_time(rapt->start)) - rapt->start;
|
localtime_r((time_t *)&rapt->start, &t);
|
||||||
rapt->start += time_shift;
|
rapt->start = update_time_in_date(date, t.tm_hour, t.tm_min);
|
||||||
|
|
||||||
|
/* The number of days shifted. */
|
||||||
|
days = (rapt->start - ostart) / DAYINSEC;
|
||||||
|
|
||||||
if (rapt->rpt->until != 0)
|
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) {
|
LLIST_FOREACH(&rapt->exc, i) {
|
||||||
struct excp *exc = LLIST_GET_DATA(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);
|
LLIST_TS_LOCK(&recur_alist_p);
|
||||||
|
@ -332,7 +332,7 @@ static void update_rept(struct rpt **rpt, const long start)
|
|||||||
keys_wgetch(win[KEY].p);
|
keys_wgetch(win[KEY].p);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
newuntil = start + days * DAYINSEC;
|
newuntil = date_sec_change(start, 0, days);
|
||||||
} else {
|
} else {
|
||||||
int year, month, day;
|
int year, month, day;
|
||||||
if (!parse_date(timstr, conf.input_datefmt, &year,
|
if (!parse_date(timstr, conf.input_datefmt, &year,
|
||||||
@ -836,7 +836,7 @@ void ui_day_item_repeat(void)
|
|||||||
keys_wgetch(win[KEY].p);
|
keys_wgetch(win[KEY].p);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
until = p->start + days * DAYINSEC;
|
until = date_sec_change(p->start, 0, days);
|
||||||
} else {
|
} else {
|
||||||
int year, month, day;
|
int year, month, day;
|
||||||
if (!parse_date(user_input, conf.input_datefmt,
|
if (!parse_date(user_input, conf.input_datefmt,
|
||||||
|
28
src/utils.c
28
src/utils.c
@ -530,7 +530,27 @@ long date_sec_change(long date, int delta_month, int delta_day)
|
|||||||
return t;
|
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)
|
time_t update_time_in_date(time_t date, unsigned hr, unsigned mn)
|
||||||
{
|
{
|
||||||
struct tm lt;
|
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)) {
|
} else if (parse_date_interactive(d, &year, &month, &day)) {
|
||||||
ret |= PARSE_DATETIME_HAS_DATE;
|
ret |= PARSE_DATETIME_HAS_DATE;
|
||||||
}
|
}
|
||||||
if (ret & PARSE_DATETIME_HAS_DATE) {
|
if (ret & PARSE_DATETIME_HAS_DATE)
|
||||||
struct date date = { day , month, year };
|
*ts = update_date_in_date(*ts, day, month, year);
|
||||||
*ts = date2sec(date, 0, 0) + get_item_time(*ts);
|
|
||||||
}
|
|
||||||
if (ret & PARSE_DATETIME_HAS_TIME)
|
if (ret & PARSE_DATETIME_HAS_TIME)
|
||||||
*ts = update_time_in_date(*ts, hour, minute);
|
*ts = update_time_in_date(*ts, hour, minute);
|
||||||
mem_free(d);
|
mem_free(d);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user