diff options
-rw-r--r-- | ReleaseNotes.txt | 2 | ||||
-rw-r--r-- | src/libical/icaltime.c | 10 | ||||
-rw-r--r-- | src/libical/icaltime.h | 2 | ||||
-rw-r--r-- | src/test/regression.c | 24 |
4 files changed, 36 insertions, 2 deletions
diff --git a/ReleaseNotes.txt b/ReleaseNotes.txt index 4843d746..f027309a 100644 --- a/ReleaseNotes.txt +++ b/ReleaseNotes.txt @@ -5,6 +5,8 @@ Version 3.0.15 (UNRELEASED): ---------------------------- * Add missing property parameters into libical-glib * Fix CMake option USE_32BIT_TIME_T actually uses a 32-bit time_t value + * Fix icaltime_as_timet, which returned incorrect results for years >= 2100, + to work properly between years 1902 and 10k. * Fix x-property comma handling and escaping Version 3.0.14 (05 February 2022): diff --git a/src/libical/icaltime.c b/src/libical/icaltime.c index 223ebb0a..fe03aee5 100644 --- a/src/libical/icaltime.c +++ b/src/libical/icaltime.c @@ -111,6 +111,7 @@ static time_t icaltime_timegm(const struct tm *tm) static time_t make_time(struct tm *tm, int tzm) { time_t tim; + int febs; static int days[] = { -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364 }; @@ -145,12 +146,17 @@ static time_t make_time(struct tm *tm, int tzm) tim = (time_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 b/src/libical/icaltime.h index ca69724f..e7c7d1a2 100644 --- a/src/libical/icaltime.h +++ b/src/libical/icaltime.h @@ -198,6 +198,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 time_t icaltime_as_timet(const struct icaltimetype); diff --git a/src/test/regression.c b/src/test/regression.c index cdfc77c1..957b9c26 100644 --- a/src/test/regression.c +++ b/src/test/regression.c @@ -4963,6 +4963,29 @@ static void test_comma_in_xproperty(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_TIME_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) @@ -5018,6 +5041,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 day of Year", test_doy, do_test, do_header); test_run("Test duration", test_duration, do_test, do_header); |