diff options
author | Allen Winter <allen.winter@kdab.com> | 2018-11-10 17:47:54 -0500 |
---|---|---|
committer | Allen Winter <allen.winter@kdab.com> | 2018-11-10 17:47:54 -0500 |
commit | bce88d38f057694e7df927bd50f92cd6abe85c1c (patch) | |
tree | 41b1c310e2799dbcd0c311e695debf9ee35c33fe | |
parent | 123d4a79b71d200aabf7bc6909a7144b532dd91a (diff) | |
parent | 8a6f6f40abc73ccc1e5389debcf6058f910bb985 (diff) | |
download | libical-git-bce88d38f057694e7df927bd50f92cd6abe85c1c.tar.gz |
Merge branch 'juldat_rework' of https://github.com/tapkey/libical into tapkey-juldat_rework
-rw-r--r-- | ReleaseNotes.txt | 3 | ||||
-rw-r--r-- | src/libical/astime.h | 54 | ||||
-rw-r--r-- | src/libical/caldate.c | 150 | ||||
-rw-r--r-- | src/libical/icaltime.c | 31 | ||||
-rw-r--r-- | src/test/regression.c | 86 |
5 files changed, 302 insertions, 22 deletions
diff --git a/ReleaseNotes.txt b/ReleaseNotes.txt index 382c8aec..655a574a 100644 --- a/ReleaseNotes.txt +++ b/ReleaseNotes.txt @@ -8,6 +8,9 @@ Version 3.1.0: + icalrecurrencetype_encode_month + icaltzutil_set_zone_directory * icaltzutil_get_zone_directory() can use the TZDIR environment to find system zoneinfo + * Deprecated functions: + + caldat + + juldat Version 3.0.4: -------------- diff --git a/src/libical/astime.h b/src/libical/astime.h index b8710b28..4a01c53c 100644 --- a/src/libical/astime.h +++ b/src/libical/astime.h @@ -1,3 +1,7 @@ +/* + * This work is based on work from Hiram Clawson and has been modified to the + * needs of the libical project. The original copyright notice is as follows: + */ /* * Copyright (c) 1986-2000, Hiram Clawson * All rights reserved. @@ -33,6 +37,27 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ +/* + * The modifications made are licensed as follows (to distinguish between + * the original code and the modifications made, refer to the source code + * history): + */ + /*====================================================================== + + (C) COPYRIGHT 2018, Markus Minichmayr + https://tapkey.com + + This library is free software; you can redistribute it and/or modify + it under the terms of either: + + The LGPL as published by the Free Software Foundation, version + 2.1, available at: http://www.gnu.org/licenses/lgpl-2.1.html + + Or: + + The Mozilla Public License Version 2.0. You may obtain a copy of + the License at http://www.mozilla.org/MPL/ + ========================================================================*/ /** * @file astime.h @@ -62,8 +87,33 @@ typedef struct ut_instant /* Functions in caldate.c */ -LIBICAL_ICAL_EXPORT long caldat(UTinstantPtr); /** converts julian date to year,mo,da */ +/** converts julian date to year,mo,da + * @deprecated use caldat_int() instead
+ */
+LIBICAL_ICAL_EXPORT long caldat(UTinstantPtr); + +/** returns julian day from year,mo,da + * @deprecated use juldat_int() instead
+ */
+LIBICAL_ICAL_EXPORT double juldat(UTinstantPtr); + + +typedef struct ut_instant_int +{ + long j_date0; /**< julian decimal date, 0 = 01 Jan 4713 BC */ + long year; /**< year, valid range [-4,713, +32,767] */ + int month; /**< [1-12] */ + int day; /**< [1-31] */ + int weekday; /**< [0-6] */ + int day_of_year; /**< [1-366] */ +} UTinstantInt, *UTinstantIntPtr; + +/* Functions in caldate.c */ + +/** converts julian date to year,mo,da */ +void caldat_int(UTinstantIntPtr); -LIBICAL_ICAL_EXPORT double juldat(UTinstantPtr); /** returns julian day from year,mo,da */ +/** returns julian day from year,mo,da */ +void juldat_int(UTinstantIntPtr); #endif diff --git a/src/libical/caldate.c b/src/libical/caldate.c index 086e0591..726fffc7 100644 --- a/src/libical/caldate.c +++ b/src/libical/caldate.c @@ -1,4 +1,8 @@ /* + * This work is based on work from Hiram Clawson and has been modified to the + * needs of the libical project. The original copyright notice is as follows: + */ +/* * Copyright (c) 1986-2000, Hiram Clawson * All rights reserved. * @@ -33,6 +37,28 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ +/* + * The modifications made are licensed as follows (to distinguish between + * the original code and the modifications made, refer to the source code + * history): + */ +/*====================================================================== + + (C) COPYRIGHT 2018, Markus Minichmayr + https://tapkey.com + + This library is free software; you can redistribute it and/or modify + it under the terms of either: + + The LGPL as published by the Free Software Foundation, version + 2.1, available at: http://www.gnu.org/licenses/lgpl-2.1.html + + Or: + + The Mozilla Public License Version 2.0. You may obtain a copy of + the License at http://www.mozilla.org/MPL/ + ========================================================================*/ + #include "astime.h" /* time structures */ @@ -175,3 +201,127 @@ struct ut_instant * date; date->weekday = (jd + 1L) % 7L; return( date->j_date ); } /* end of double juldat( date ) */ + + +/** + * caldat computes the day of the week, the day of the year + * the gregorian (or julian) calendar date + * from the julian decimal date. + * for astronomical purposes, The Gregorian calendar reform occurred + * on 15 Oct. 1582. This is 05 Oct 1582 by the julian calendar. + + * Input: a ut_instant structure pointer, where the j_date element + * has been set. ( = 0 for 01 Jan 4713 B.C.) + * + * output: will set all the other elements of the structure. + * As a convienence, the function will also return the year. + * + * Reference: Astronomial formulae for calculators, meeus, p 23 + * from fortran program by F. Espenak - April 1982 Page 277, + * 50 Year canon of solar eclipses: 1986-2035 + * + */ + +void caldat_int( date ) +struct ut_instant_int * date; +{ + long jd; + long ka; + long kb; + long kc; + long kd; + long ke; + long ialp; + + jd = (long) (date->j_date0 + 1L); /* integer julian date */ + ka = (long) jd; + if ( jd >= 2299161L ) + { + ialp = (long) (((jd * 100LL) - 186721625LL) / 3652425LL); + ka = jd + 1L + ialp - ( ialp >> 2 ); + } + kb = ka + 1524L; + kc = (long) ( ((kb * 100LL) - 12210LL) / 36525LL ); + kd = (long) ( ( kc * 36525LL ) / 100LL ); + ke = (long) ( (kb - kd) * 10000LL / 306001LL ); + date->day = kb - kd - ((long) ( (ke * 306001LL) / 10000LL )); + if ( ke > 13L ) + date->month = ke - 13L; + else + date->month = ke - 1L; + if ( (date->month == 2) && (date->day > 28) ) + date->day = 29; + if ( (date->month == 2) && (date->day == 29) && (ke == 3L) ) + date->year = kc - 4716L; + else if ( date->month > 2 ) + date->year = kc - 4716L; + else + date->year = kc - 4715L; + date->weekday = (jd + 1L) % 7L; /* day of week */ + if ( date->year == ((date->year >> 2) << 2) ) + date->day_of_year = + ( ( 275 * date->month ) / 9) + - ((date->month + 9) / 12) + + date->day - 30; + else + date->day_of_year = + ( ( 275 * date->month ) / 9) + - (((date->month + 9) / 12) << 1) + + date->day - 30; +} + +/** + * juldat computes the julian decimal date (j_date) from + * the gregorian (or Julian) calendar date. + * for astronomical purposes, The Gregorian calendar reform occurred + * on 15 Oct. 1582. This is 05 Oct 1582 by the julian calendar. + * Input: a ut_instant structure pointer where Day, Month, Year + * have been set for the date in question. + * + * Output: the j_date and weekday elements of the structure will be set. + * Also, the return value of the function will be the j_date too. + * + * Reference: Astronomial formulae for calculators, meeus, p 23 + * from fortran program by F. Espenak - April 1982 Page 276, + * 50 Year canon of solar eclipses: 1986-2035 + */ + +void juldat_int( date ) +struct ut_instant_int * date; +{ + long iy0, im0; + long ia, ib; + long jd; + + /* conversion factors */ + if ( date->month <= 2 ) + { + iy0 = date->year - 1L; + im0 = date->month + 12; + } + else + { + iy0 = date->year; + im0 = date->month; + } + ia = iy0 / 100L; + ib = 2L - ia + (ia >> 2); + /* calculate julian date */ + if ( date->year < 0L ) + jd = (long) (((36525LL * iy0) - 75) / 100) + + (long) ((306001LL * (im0 + 1L)) / 10000) + + (long) date->day + 1720994L; + else + jd = (long) ((36525LL * iy0) / 100) + + (long) ((306001LL * (im0 + 1L)) / 10000) + + (long) date->day + 1720994L; + + /* on or after 15 October 1582 */ + if ((date->year > 1582) + || ((date->year == 1582) && (((date->month * 100) + date->day) >= 1015)) + ) { + jd += ib; + } + date->j_date0 = jd; + date->weekday = (jd + 2L) % 7L; +} /* end of void juldat( date ) */ diff --git a/src/libical/icaltime.c b/src/libical/icaltime.c index cace5eb9..e978a991 100644 --- a/src/libical/icaltime.c +++ b/src/libical/icaltime.c @@ -526,18 +526,15 @@ int icaltime_days_in_month(const int month, const int year) /* 1-> Sunday, 7->Saturday */ int icaltime_day_of_week(const struct icaltimetype t) { - UTinstant jt; + UTinstantInt jt; - memset(&jt, 0, sizeof(UTinstant)); + memset(&jt, 0, sizeof(UTinstantInt)); jt.year = t.year; jt.month = t.month; jt.day = t.day; - jt.i_hour = 0; - jt.i_minute = 0; - jt.i_second = 0; - (void)juldat(&jt); + (void)juldat_int(&jt); return jt.weekday + 1; } @@ -546,20 +543,17 @@ int icaltime_day_of_week(const struct icaltimetype t) */ int icaltime_start_doy_week(const struct icaltimetype t, int fdow) { - UTinstant jt; + UTinstantInt jt; int delta; - memset(&jt, 0, sizeof(UTinstant)); + memset(&jt, 0, sizeof(UTinstantInt)); jt.year = t.year; jt.month = t.month; jt.day = t.day; - jt.i_hour = 0; - jt.i_minute = 0; - jt.i_second = 0; - (void)juldat(&jt); - (void)caldat(&jt); + (void)juldat_int(&jt); + (void)caldat_int(&jt); delta = jt.weekday - (fdow - 1); if (delta < 0) { @@ -574,19 +568,16 @@ int icaltime_start_doy_week(const struct icaltimetype t, int fdow) */ int icaltime_week_number(const struct icaltimetype ictt) { - UTinstant jt; + UTinstantInt jt; - memset(&jt, 0, sizeof(UTinstant)); + memset(&jt, 0, sizeof(UTinstantInt)); jt.year = ictt.year; jt.month = ictt.month; jt.day = ictt.day; - jt.i_hour = 0; - jt.i_minute = 0; - jt.i_second = 0; - (void)juldat(&jt); - (void)caldat(&jt); + (void)juldat_int(&jt); + (void)caldat_int(&jt); return (jt.day_of_year - jt.weekday) / 7; } diff --git a/src/test/regression.c b/src/test/regression.c index 21557199..ddb2f2bd 100644 --- a/src/test/regression.c +++ b/src/test/regression.c @@ -25,6 +25,7 @@ #endif #include "regression.h" +#include "libical/astime.h" #include "libical/ical.h" #include "libicalss/icalss.h" #include "libicalvcal/icalvcal.h" @@ -2666,6 +2667,90 @@ void test_recur_parser() str_is(str, icalrecurrencetype_as_string(&rt), str); } + +static int test_juldat_caldat_instance(long year, int month, int day) { + + struct icaltimetype t; + struct ut_instant originalInstant; + + + memset(&t, 0, sizeof(t)); + t.year = year; + t.month = month; + t.day = day; + + memset(&originalInstant, 0, sizeof(originalInstant)); + originalInstant.year = year; + originalInstant.month = month; + originalInstant.day = day; + + juldat(&originalInstant); + caldat(&originalInstant); + + if (icaltime_day_of_week(t) != originalInstant.weekday + 1) + return -1; + + if (icaltime_start_doy_week(t, 1) != originalInstant.day_of_year - originalInstant.weekday) + return -1; + + if (icaltime_week_number(t) != (originalInstant.day_of_year - originalInstant.weekday) / 7) + return -1; + + return 0; +} + +/* + * This test verifies the caldat_int and juldat_int functions. The functions are reworked versions + * of the original caldat and juldat functions but avoid using floating point arithmetics. As the + * new functions are not exported, the test cannot access them directly. It therefore checks the + * output of the icaltime_day_of_week, icaltime_start_doy_week and icaltime_week_number functions + * which are based on the functions to be tested. + */ +void test_juldat_caldat() { + + int i; + int failed = 0; + + ok("juldat and caldat return the expected values for specified min input values", test_juldat_caldat_instance(-4713, 1, 1) == 0); + ok("juldat and caldat return the expected values for specified max input values", test_juldat_caldat_instance(+32767, 12, 31) == 0); + + ok("juldat and caldat return the expected values before end of julian calendar", test_juldat_caldat_instance(1582, 10, 4) == 0); + ok("juldat and caldat return the expected values at end of julian calendar", test_juldat_caldat_instance(1582, 10, 5) == 0); + ok("juldat and caldat return the expected values before introduction of gregorian calendar", test_juldat_caldat_instance(1582, 10, 14) == 0); + ok("juldat and caldat return the expected values at introduction of gregorian calendar", test_juldat_caldat_instance(1582, 10, 15) == 0); + ok("juldat and caldat return the expected values after introduction of gregorian calendar", test_juldat_caldat_instance(1582, 10, 16) == 0); + + for (i = 0; i < 2582; i++) { + + long y = i; + + failed |= (test_juldat_caldat_instance(y, 1, 1) != 0); + failed |= (test_juldat_caldat_instance(y, 2, 28) != 0); + + // Not every year has a leap day, but juldat_int/caldat_int should still produce + // the same output as the original implementation. + failed |= (test_juldat_caldat_instance(y, 2, 29) != 0); + failed |= (test_juldat_caldat_instance(y, 3, 1) != 0); + failed |= (test_juldat_caldat_instance(y, 12, 31) != 0); + } + ok("juldat and caldat return the expected values for random input values", failed == 0); + + failed = 0; + for (i = 0; i < 10000; i++) { + long y = rand() % 2582; + int m = rand() % 12 + 1; + + // Might produce some invalid dates, but juldat_int/caldat_int should still produce + // the same output as the original implementation. + int d = rand() % 31 + 1; + + failed |= (test_juldat_caldat_instance(y, m, d) != 0); + } + + ok("juldat and caldat return the expected values for random input values", failed == 0); +} + + char *ical_strstr(const char *haystack, const char *needle) { return strstr(haystack, needle); @@ -4367,6 +4452,7 @@ int main(int argc, char *argv[]) test_run("Test time parser functions", test_time_parser, 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); test_run("Test duration", test_duration, do_test, do_header); test_run("Test period", test_period, do_test, do_header); |