summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAllen Winter <allen.winter@kdab.com>2018-11-10 17:47:54 -0500
committerAllen Winter <allen.winter@kdab.com>2018-11-10 17:47:54 -0500
commitbce88d38f057694e7df927bd50f92cd6abe85c1c (patch)
tree41b1c310e2799dbcd0c311e695debf9ee35c33fe
parent123d4a79b71d200aabf7bc6909a7144b532dd91a (diff)
parent8a6f6f40abc73ccc1e5389debcf6058f910bb985 (diff)
downloadlibical-git-bce88d38f057694e7df927bd50f92cd6abe85c1c.tar.gz
Merge branch 'juldat_rework' of https://github.com/tapkey/libical into tapkey-juldat_rework
-rw-r--r--ReleaseNotes.txt3
-rw-r--r--src/libical/astime.h54
-rw-r--r--src/libical/caldate.c150
-rw-r--r--src/libical/icaltime.c31
-rw-r--r--src/test/regression.c86
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);