From c682c8858fdcab2c74476f61f9e16cbf30412c1c Mon Sep 17 00:00:00 2001 From: Markus Minichmayr Date: Thu, 15 Sep 2022 09:23:37 +0200 Subject: Fix icaltime_as_timet to support dates after year 2100. --- src/libical/icaltime.c | 10 ++++++++-- src/libical/icaltime.h.cmake | 2 ++ src/test/regression.c | 24 ++++++++++++++++++++++++ 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/libical/icaltime.c b/src/libical/icaltime.c index d98880b2..93eebf6c 100644 --- a/src/libical/icaltime.c +++ b/src/libical/icaltime.c @@ -102,6 +102,7 @@ static icaltime_t icaltime_timegm(const struct tm *tm) static icaltime_t make_time(struct tm *tm, int tzm) { icaltime_t tim; + int febs; static int days[] = { -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364 }; @@ -136,12 +137,17 @@ static icaltime_t make_time(struct tm *tm, int tzm) tim = (icaltime_t) ((tm->tm_year - 70) * 365 + ((tm->tm_year - 1) / 4) - 17); + /* adjust: no leap days every 100 years, except every 400 years. */ + + febs = (tm->tm_year - 100) - ((tm->tm_mon <= 1) ? 1 : 0); + tim -= febs / 100; + tim += febs / 400; + /* add number of days elapsed in the current year */ tim += days[tm->tm_mon]; - /* check and adjust for leap years (the leap year check only valid - during the 32-bit era */ + /* check and adjust for leap years */ if ((tm->tm_year & 3) == 0 && tm->tm_mon > 1) tim += 1; diff --git a/src/libical/icaltime.h.cmake b/src/libical/icaltime.h.cmake index 90b62ce8..4e24d4b6 100644 --- a/src/libical/icaltime.h.cmake +++ b/src/libical/icaltime.h.cmake @@ -190,6 +190,8 @@ LIBICAL_ICAL_EXPORT struct icaltimetype icaltime_from_day_of_year(const int doy, * This function probably won't do what you expect. In particular, you should * only pass an icaltime in UTC, since no conversion is done. Even in that case, * it's probably better to just use icaltime_as_timet_with_zone(). + * + * The return value is defined for dates starting with 1902-01-01 until 10000-01-01 (excl.). */ LIBICAL_ICAL_EXPORT icaltime_t icaltime_as_timet(const struct icaltimetype); diff --git a/src/test/regression.c b/src/test/regression.c index 8f036110..106c08e0 100644 --- a/src/test/regression.c +++ b/src/test/regression.c @@ -5234,6 +5234,29 @@ static void test_remove_tzid_from_due(void) icalcomponent_free(c); } +void test_icaltime_as_timet(void) { + + ok("icaltime_from_string translates 19020101T000000Z to -2145916800", icaltime_as_timet(icaltime_from_string("19020101T000000Z")) == -2145916800); + ok("icaltime_from_string translates 19290519T000000Z to -1281916800", icaltime_as_timet(icaltime_from_string("19290519T000000Z")) == -1281916800); + ok("icaltime_from_string translates 19561004T000000Z to -417916800", icaltime_as_timet(icaltime_from_string("19561004T000000Z")) == -417916800); + ok("icaltime_from_string translates 19700101T000000Z to 0", icaltime_as_timet(icaltime_from_string("19700101T000000Z")) == 0); + ok("icaltime_from_string translates 19700301T235959Z to 5183999", icaltime_as_timet(icaltime_from_string("19700301T235959Z")) == 5183999); + ok("icaltime_from_string translates 19970717T235959Z to 869183999", icaltime_as_timet(icaltime_from_string("19970717T235959Z")) == 869183999); + ok("icaltime_from_string translates 20241202T235959Z to 1733183999", icaltime_as_timet(icaltime_from_string("20241202T235959Z")) == 1733183999); + ok("icaltime_from_string translates 20371231T235959Z to 2145916799", icaltime_as_timet(icaltime_from_string("20371231T235959Z")) == 2145916799); +#if (SIZEOF_ICALTIME_T > 4) + ok("icaltime_from_string translates 20520419T235959Z to 2597183999", icaltime_as_timet(icaltime_from_string("20520419T235959Z")) == 2597183999); + ok("icaltime_from_string translates 20790905T235959Z to 3461183999", icaltime_as_timet(icaltime_from_string("20790905T235959Z")) == 3461183999); + ok("icaltime_from_string translates 21000101T235959Z to 4102531199", icaltime_as_timet(icaltime_from_string("21000101T235959Z")) == 4102531199); + ok("icaltime_from_string translates 21000301T235959Z to 4107628799", icaltime_as_timet(icaltime_from_string("21000301T235959Z")) == 4107628799); + ok("icaltime_from_string translates 22370122T235959Z to 8427628799", icaltime_as_timet(icaltime_from_string("22370122T235959Z")) == 8427628799); + ok("icaltime_from_string translates 23731215T235959Z to 12747628799", icaltime_as_timet(icaltime_from_string("23731215T235959Z")) == 12747628799); + ok("icaltime_from_string translates 25101107T235959Z to 17067628799", icaltime_as_timet(icaltime_from_string("25101107T235959Z")) == 17067628799); + ok("icaltime_from_string translates 25821231T235959Z to 19344441599", icaltime_as_timet(icaltime_from_string("25821231T235959Z")) == 19344441599); + ok("icaltime_from_string translates 99991231T235959Z to 253402300799", icaltime_as_timet(icaltime_from_string("99991231T235959Z")) == 253402300799); +#endif +} + int main(int argc, char *argv[]) { #if !defined(HAVE_UNISTD_H) @@ -5300,6 +5323,7 @@ int main(int argc, char *argv[]) #endif test_run("Test time parser functions", test_time_parser, do_test, do_header); + test_run("Test icaltime_as_timet", test_icaltime_as_timet, do_test, do_header); test_run("Test time", test_time, do_test, do_header); test_run("Test calculation of DOY and WD", test_juldat_caldat, do_test, do_header); test_run("Test day of Year", test_doy, do_test, do_header); -- cgit v1.2.1