diff --git a/src/libiso8601/100_leap.c b/src/libiso8601/100_leap.c index cf2a900..851d274 100644 --- a/src/libiso8601/100_leap.c +++ b/src/libiso8601/100_leap.c @@ -57,7 +57,7 @@ static int _leap_elapsed_day(int sday, int eday) if(eday <= leap_second_days[epos]) break; } - return spos - epos; + return epos - spos; } diff --git a/src/libiso8601/400_manip.c b/src/libiso8601/400_manip.c index 1ab5fd9..d9489d1 100644 --- a/src/libiso8601/400_manip.c +++ b/src/libiso8601/400_manip.c @@ -40,14 +40,52 @@ int iso8601_eq(const struct iso8601_date* d1, const struct iso8601_date* d2) void iso8601_add_elapsed(struct iso8601_date* date, const struct iso8601_elapsed* per) { - /* TODO */ + div_t qr; + int leapcorrect; + + /* work out number to advance `day' by */ + qr = div(per->sec, 86400); + leapcorrect = _leap_elapsed_day(date->day, date->day + qr.quot); + date->day += qr.quot; + date->sec += qr.rem - leapcorrect; + if(date->sec < 0) { + --date->day; + date->sec += iso8601_seconds_leap(date); + } + + date->nsec += per->nsec; + if(date->nsec > BILLION) { + ++date->sec; + date->nsec -= BILLION; + } } void iso8601_subtract_elapsed(struct iso8601_date* date, const struct iso8601_elapsed* per) { - /* TODO */ + div_t qr; + int leapcorrect; + + /* work out number to advance `day' by */ + qr = div(per->sec, 86400); + leapcorrect = _leap_elapsed_day(date->day - qr.quot, date->day); + date->day -= qr.quot; + date->sec -= qr.rem - leapcorrect; + date->nsec -= per->nsec; + if(date->nsec < 0) { + --date->sec; + date->nsec += BILLION; + } + + if(date->sec < 0) { + --date->day; + date->sec += iso8601_seconds_leap(date); + } + if(date->sec >= iso8601_seconds_leap(date)) { + date->sec -= iso8601_seconds_leap(date); + ++date->day; + } } diff --git a/src/tests/leap.c b/src/tests/leap.c index 0f36def..11cf7a9 100644 --- a/src/tests/leap.c +++ b/src/tests/leap.c @@ -30,6 +30,7 @@ int leap_diff(const char* s1, const char* s2, int* diff) int regression1(void) { struct iso8601_date d; + struct iso8601_elapsed elapsed; char s1[30], s2[30], s3[30]; int ret = 0, oday; @@ -39,11 +40,13 @@ int regression1(void) d.nsec = 0; iso8601_print(s1, sizeof(s1), &d, 0); - iso8601_add_seconds(&d, 86400); + elapsed.sec = 86400; + elapsed.nsec = 0; + iso8601_add_elapsed(&d, &elapsed); iso8601_print(s2, sizeof(s2), &d, 0); ret |= (d.day != oday) | (d.sec != 86400); - iso8601_add_seconds(&d, 86400); + iso8601_add_elapsed(&d, &elapsed); iso8601_print(s3, sizeof(s3), &d, 0); ret |= (d.day != (oday + 1)) | (d.sec != 86399); @@ -58,6 +61,7 @@ int regression2(void) { struct iso8601_date d; char s1[30], s2[30], s3[30]; + struct iso8601_elapsed elapsed; int ret = 0, oday; iso8601_from_cal(&d, 2005, 12, 31); @@ -66,11 +70,13 @@ int regression2(void) d.nsec = 0; iso8601_print(s1, sizeof(s1), &d, 0); - iso8601_add_seconds(&d, 86400); + elapsed.sec = 86400; + elapsed.nsec = 0; + iso8601_add_elapsed(&d, &elapsed); iso8601_print(s2, sizeof(s2), &d, 0); ret |= (d.day != (oday + 1)) | (d.sec != 86398); - iso8601_add_seconds(&d, 86400); + iso8601_add_elapsed(&d, &elapsed); iso8601_print(s3, sizeof(s3), &d, 0); ret |= (d.day != (oday + 2)) | (d.sec != 86398); @@ -85,6 +91,7 @@ int regression3(void) { struct iso8601_date d; char s1[30], s2[30], s3[30]; + struct iso8601_elapsed elapsed; int ret = 0, oday; iso8601_from_cal(&d, 2005, 12, 31); @@ -93,11 +100,13 @@ int regression3(void) d.nsec = 0; iso8601_print(s1, sizeof(s1), &d, 0); - iso8601_add_seconds(&d, 86400); + elapsed.sec = 86400; + elapsed.nsec = 0; + iso8601_add_elapsed(&d, &elapsed); iso8601_print(s2, sizeof(s2), &d, 0); ret |= (d.day != (oday + 1)) | (d.sec != 86399); - iso8601_add_seconds(&d, 86400); + iso8601_add_elapsed(&d, &elapsed); iso8601_print(s3, sizeof(s3), &d, 0); ret |= (d.day != (oday + 2)) | (d.sec != 86399); @@ -112,6 +121,7 @@ int regression4(void) { struct iso8601_date d; char s1[30], s2[30], s3[30]; + struct iso8601_elapsed elapsed; int ret = 0, oday; iso8601_from_cal(&d, 2006, 1, 1); @@ -120,11 +130,13 @@ int regression4(void) d.nsec = 0; iso8601_print(s1, sizeof(s1), &d, 0); - iso8601_add_seconds(&d, -86400); + elapsed.sec = 86400; + elapsed.nsec = 0; + iso8601_subtract_elapsed(&d, &elapsed); iso8601_print(s2, sizeof(s2), &d, 0); ret |= (d.day != (oday - 1)) | (d.sec != 86400); - iso8601_add_seconds(&d, -86400); + iso8601_subtract_elapsed(&d, &elapsed); iso8601_print(s3, sizeof(s3), &d, 0); ret |= (d.day != (oday - 1)) | (d.sec != 0); @@ -139,6 +151,7 @@ int regression5(void) { struct iso8601_date d; char s1[30], s2[30], s3[30]; + struct iso8601_elapsed elapsed; int ret = 0, oday; iso8601_from_cal(&d, 2006, 1, 2); @@ -147,11 +160,13 @@ int regression5(void) d.nsec = 0; iso8601_print(s1, sizeof(s1), &d, 0); - iso8601_add_seconds(&d, -86400); + elapsed.sec = 86400; + elapsed.nsec = 0; + iso8601_subtract_elapsed(&d, &elapsed); iso8601_print(s2, sizeof(s2), &d, 0); ret |= (d.day != (oday - 1)) | (d.sec != 86398); - iso8601_add_seconds(&d, -86400); + iso8601_subtract_elapsed(&d, &elapsed); iso8601_print(s3, sizeof(s3), &d, 0); ret |= (d.day != (oday - 2)) | (d.sec != 86399); @@ -166,6 +181,7 @@ int regression6(void) { struct iso8601_date d; char s1[30], s2[30], s3[30]; + struct iso8601_elapsed elapsed; int ret = 0, oday; iso8601_from_cal(&d, 2006, 1, 2); @@ -174,11 +190,13 @@ int regression6(void) d.nsec = 0; iso8601_print(s1, sizeof(s1), &d, 0); - iso8601_add_seconds(&d, -86400); + elapsed.sec = 86400; + elapsed.nsec = 0; + iso8601_subtract_elapsed(&d, &elapsed); iso8601_print(s2, sizeof(s2), &d, 0); ret |= (d.day != (oday - 1)) | (d.sec != 86399); - iso8601_add_seconds(&d, -86400); + iso8601_subtract_elapsed(&d, &elapsed); iso8601_print(s3, sizeof(s3), &d, 0); ret |= (d.day != (oday - 2)) | (d.sec != 86400);