Add some more leap second support
This commit is contained in:
parent
4bd50f62e2
commit
7aace3d8e3
|
@ -11,7 +11,7 @@ then
|
||||||
MONOLITHIC_SOURCE="$(echo src/libiso8601/{TopHeader,types,functions,BottomHeader}.h)"
|
MONOLITHIC_SOURCE="$(echo src/libiso8601/{TopHeader,types,functions,BottomHeader}.h)"
|
||||||
make_monolithic ${HDR} Ch || return 1
|
make_monolithic ${HDR} Ch || return 1
|
||||||
|
|
||||||
MONOLITHIC_SOURCE="$(echo src/libiso8601/{TopSource,c_library,calc,parser,print,manip,leap}.c)"
|
MONOLITHIC_SOURCE="$(echo src/libiso8601/{TopSource,leap,c_library,calc,parser,print,manip}.c)"
|
||||||
make_monolithic ${SRC} C || return 1
|
make_monolithic ${SRC} C || return 1
|
||||||
|
|
||||||
libiso8601_MONOLITHIC=1
|
libiso8601_MONOLITHIC=1
|
||||||
|
|
|
@ -67,11 +67,14 @@ void iso8601_print(char* str, int amt, const struct iso8601_date* date,
|
||||||
const struct iso8601_details* details);
|
const struct iso8601_details* details);
|
||||||
|
|
||||||
/* manip.c */
|
/* manip.c */
|
||||||
|
int iso8601_lt(const struct iso8601_date* d1, const struct iso8601_date* d2);
|
||||||
|
int iso8601_lte(const struct iso8601_date* d1, const struct iso8601_date* d2);
|
||||||
void iso8601_add_seconds(struct iso8601_date* date, long seconds);
|
void iso8601_add_seconds(struct iso8601_date* date, long seconds);
|
||||||
|
|
||||||
/* leap.c */
|
/* leap.c */
|
||||||
int iso8601_seconds_leap(const struct iso8601_date* date);
|
int iso8601_seconds_leap(const struct iso8601_date* date);
|
||||||
int iso8601_valid_leap(const struct iso8601_date* date);
|
int iso8601_valid_leap(const struct iso8601_date* date);
|
||||||
|
int iso8601_leap_elapsed(const struct iso8601_date* start, const struct iso8601_date* end);
|
||||||
|
|
||||||
/* options for text editors
|
/* options for text editors
|
||||||
kate: replace-trailing-space-save true; space-indent true; tab-width 4;
|
kate: replace-trailing-space-save true; space-indent true; tab-width 4;
|
||||||
|
|
|
@ -67,6 +67,29 @@ int iso8601_valid_leap(const struct iso8601_date* date)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int _leap_elapsed_day(int sday, int eday)
|
||||||
|
{
|
||||||
|
int spos, epos;
|
||||||
|
|
||||||
|
for(spos = 0; (unsigned)spos < sizeof(leap_second_days) / sizeof(int); ++spos) {
|
||||||
|
if(sday <= leap_second_days[spos]) break;
|
||||||
|
}
|
||||||
|
for(epos = 0; (unsigned)epos < sizeof(leap_second_days) / sizeof(int); ++epos) {
|
||||||
|
if(eday <= leap_second_days[epos]) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return spos - epos;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int iso8601_leap_elapsed(const struct iso8601_date* start, const struct iso8601_date* end)
|
||||||
|
{
|
||||||
|
return _leap_elapsed_day(start->day, end->day);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* options for text editors
|
/* options for text editors
|
||||||
kate: replace-trailing-space-save true; space-indent true; tab-width 4;
|
kate: replace-trailing-space-save true; space-indent true; tab-width 4;
|
||||||
vim: expandtab:ts=4:sw=4
|
vim: expandtab:ts=4:sw=4
|
||||||
|
|
|
@ -7,19 +7,56 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int iso8601_lt(const struct iso8601_date* d1, const struct iso8601_date* d2)
|
||||||
|
{
|
||||||
|
if(d1->day < d2->day) return 1;
|
||||||
|
if(d1->day > d2->day) return 0;
|
||||||
|
if(d1->sec < d2->sec) return 1;
|
||||||
|
if(d1->sec > d2->sec) return 0;
|
||||||
|
if(d1->nsec < d2->nsec) return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int iso8601_lte(const struct iso8601_date* d1, const struct iso8601_date* d2)
|
||||||
|
{
|
||||||
|
if(d1->day < d2->day) return 1;
|
||||||
|
if(d1->day > d2->day) return 0;
|
||||||
|
if(d1->sec < d2->sec) return 1;
|
||||||
|
if(d1->sec > d2->sec) return 0;
|
||||||
|
if(d1->nsec < d2->nsec) return 0;
|
||||||
|
return d1->nsec == d2->nsec;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void iso8601_add_seconds(struct iso8601_date* date, long seconds)
|
void iso8601_add_seconds(struct iso8601_date* date, long seconds)
|
||||||
{
|
{
|
||||||
|
int sday;
|
||||||
ldiv_t qr;
|
ldiv_t qr;
|
||||||
|
|
||||||
// TODO: leap second support
|
sday = date->day;
|
||||||
|
|
||||||
qr = ldiv(seconds + date->sec, 86400);
|
qr = ldiv(seconds + date->sec, 86400);
|
||||||
date->day += qr.quot;
|
date->day += qr.quot;
|
||||||
|
|
||||||
date->sec = qr.rem;
|
date->sec = qr.rem;
|
||||||
if(date->sec < 0) {
|
if(date->sec < 0) {
|
||||||
--date->day;
|
--date->day;
|
||||||
date->sec += 86400;
|
date->sec += 86400;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* leap second correction */
|
||||||
|
if(sday != date->day) {
|
||||||
|
date->sec += _leap_elapsed_day(sday, date->day);
|
||||||
|
if(date->sec < 0) {
|
||||||
|
--date->day;
|
||||||
|
date->sec += iso8601_seconds_leap(date);
|
||||||
|
} else if(date->sec >= iso8601_seconds_leap(date)) {
|
||||||
|
date->sec -= iso8601_seconds_leap(date);
|
||||||
|
++date->day;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,267 @@
|
||||||
|
/* libiso8601/src/tests/leap.c
|
||||||
|
*
|
||||||
|
* (c)2007, Laurence Withers, <l@lwithers.me.uk>.
|
||||||
|
* Released under the GNU GPLv2. See file COPYING or
|
||||||
|
* http://www.gnu.org/copyleft/gpl.html for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "iso8601.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int leap_diff(const char* s1, const char* s2, int* diff)
|
||||||
|
{
|
||||||
|
struct iso8601_date d1, d2;
|
||||||
|
|
||||||
|
if(iso8601_parse(s1, &d1, 0, 0) || iso8601_parse(s2, &d2, 0, 0)) {
|
||||||
|
fprintf(stderr, "Unable to parse ``%s'' or ``%s'' (%m).", s1, s2);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*diff = iso8601_leap_elapsed(&d1, &d2);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int regression1(void)
|
||||||
|
{
|
||||||
|
struct iso8601_date d;
|
||||||
|
char s1[30], s2[30], s3[30];
|
||||||
|
int ret = 0, oday;
|
||||||
|
|
||||||
|
iso8601_from_cal(&d, 2005, 12, 31);
|
||||||
|
oday = d.day;
|
||||||
|
d.sec = 0;
|
||||||
|
d.nsec = 0;
|
||||||
|
iso8601_print(s1, sizeof(s1), &d, 0);
|
||||||
|
|
||||||
|
iso8601_add_seconds(&d, 86400);
|
||||||
|
iso8601_print(s2, sizeof(s2), &d, 0);
|
||||||
|
ret |= (d.day != oday) | (d.sec != 86400);
|
||||||
|
|
||||||
|
iso8601_add_seconds(&d, 86400);
|
||||||
|
iso8601_print(s3, sizeof(s3), &d, 0);
|
||||||
|
ret |= (d.day != (oday + 1)) | (d.sec != 86399);
|
||||||
|
|
||||||
|
printf("%s -> %s -> %s\n", s1, s2, s3);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int regression2(void)
|
||||||
|
{
|
||||||
|
struct iso8601_date d;
|
||||||
|
char s1[30], s2[30], s3[30];
|
||||||
|
int ret = 0, oday;
|
||||||
|
|
||||||
|
iso8601_from_cal(&d, 2005, 12, 31);
|
||||||
|
oday = d.day;
|
||||||
|
d.sec = 86399;
|
||||||
|
d.nsec = 0;
|
||||||
|
iso8601_print(s1, sizeof(s1), &d, 0);
|
||||||
|
|
||||||
|
iso8601_add_seconds(&d, 86400);
|
||||||
|
iso8601_print(s2, sizeof(s2), &d, 0);
|
||||||
|
ret |= (d.day != (oday + 1)) | (d.sec != 86398);
|
||||||
|
|
||||||
|
iso8601_add_seconds(&d, 86400);
|
||||||
|
iso8601_print(s3, sizeof(s3), &d, 0);
|
||||||
|
ret |= (d.day != (oday + 2)) | (d.sec != 86398);
|
||||||
|
|
||||||
|
printf("%s -> %s -> %s\n", s1, s2, s3);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int regression3(void)
|
||||||
|
{
|
||||||
|
struct iso8601_date d;
|
||||||
|
char s1[30], s2[30], s3[30];
|
||||||
|
int ret = 0, oday;
|
||||||
|
|
||||||
|
iso8601_from_cal(&d, 2005, 12, 31);
|
||||||
|
oday = d.day;
|
||||||
|
d.sec = 86400;
|
||||||
|
d.nsec = 0;
|
||||||
|
iso8601_print(s1, sizeof(s1), &d, 0);
|
||||||
|
|
||||||
|
iso8601_add_seconds(&d, 86400);
|
||||||
|
iso8601_print(s2, sizeof(s2), &d, 0);
|
||||||
|
ret |= (d.day != (oday + 1)) | (d.sec != 86399);
|
||||||
|
|
||||||
|
iso8601_add_seconds(&d, 86400);
|
||||||
|
iso8601_print(s3, sizeof(s3), &d, 0);
|
||||||
|
ret |= (d.day != (oday + 2)) | (d.sec != 86399);
|
||||||
|
|
||||||
|
printf("%s -> %s -> %s\n", s1, s2, s3);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int regression4(void)
|
||||||
|
{
|
||||||
|
struct iso8601_date d;
|
||||||
|
char s1[30], s2[30], s3[30];
|
||||||
|
int ret = 0, oday;
|
||||||
|
|
||||||
|
iso8601_from_cal(&d, 2006, 1, 1);
|
||||||
|
oday = d.day;
|
||||||
|
d.sec = 86399;
|
||||||
|
d.nsec = 0;
|
||||||
|
iso8601_print(s1, sizeof(s1), &d, 0);
|
||||||
|
|
||||||
|
iso8601_add_seconds(&d, -86400);
|
||||||
|
iso8601_print(s2, sizeof(s2), &d, 0);
|
||||||
|
ret |= (d.day != (oday - 1)) | (d.sec != 86400);
|
||||||
|
|
||||||
|
iso8601_add_seconds(&d, -86400);
|
||||||
|
iso8601_print(s3, sizeof(s3), &d, 0);
|
||||||
|
ret |= (d.day != (oday - 1)) | (d.sec != 0);
|
||||||
|
|
||||||
|
printf("%s -> %s -> %s\n", s1, s2, s3);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int regression5(void)
|
||||||
|
{
|
||||||
|
struct iso8601_date d;
|
||||||
|
char s1[30], s2[30], s3[30];
|
||||||
|
int ret = 0, oday;
|
||||||
|
|
||||||
|
iso8601_from_cal(&d, 2006, 1, 2);
|
||||||
|
oday = d.day;
|
||||||
|
d.sec = 86398;
|
||||||
|
d.nsec = 0;
|
||||||
|
iso8601_print(s1, sizeof(s1), &d, 0);
|
||||||
|
|
||||||
|
iso8601_add_seconds(&d, -86400);
|
||||||
|
iso8601_print(s2, sizeof(s2), &d, 0);
|
||||||
|
ret |= (d.day != (oday - 1)) | (d.sec != 86398);
|
||||||
|
|
||||||
|
iso8601_add_seconds(&d, -86400);
|
||||||
|
iso8601_print(s3, sizeof(s3), &d, 0);
|
||||||
|
ret |= (d.day != (oday - 2)) | (d.sec != 86399);
|
||||||
|
|
||||||
|
printf("%s -> %s -> %s\n", s1, s2, s3);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int regression6(void)
|
||||||
|
{
|
||||||
|
struct iso8601_date d;
|
||||||
|
char s1[30], s2[30], s3[30];
|
||||||
|
int ret = 0, oday;
|
||||||
|
|
||||||
|
iso8601_from_cal(&d, 2006, 1, 2);
|
||||||
|
oday = d.day;
|
||||||
|
d.sec = 86399;
|
||||||
|
d.nsec = 0;
|
||||||
|
iso8601_print(s1, sizeof(s1), &d, 0);
|
||||||
|
|
||||||
|
iso8601_add_seconds(&d, -86400);
|
||||||
|
iso8601_print(s2, sizeof(s2), &d, 0);
|
||||||
|
ret |= (d.day != (oday - 1)) | (d.sec != 86399);
|
||||||
|
|
||||||
|
iso8601_add_seconds(&d, -86400);
|
||||||
|
iso8601_print(s3, sizeof(s3), &d, 0);
|
||||||
|
ret |= (d.day != (oday - 2)) | (d.sec != 86400);
|
||||||
|
|
||||||
|
printf("%s -> %s -> %s\n", s1, s2, s3);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct regression_test {
|
||||||
|
const char* name;
|
||||||
|
int (*func)(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct regression_test regression_tests[] = {
|
||||||
|
{ "Start of leap day, +86400s", regression1 },
|
||||||
|
{ "Near end of leap day, +86400s", regression2 },
|
||||||
|
{ "End of leap day, +86400s", regression3 },
|
||||||
|
{ "Start of post-leap day, -86400s", regression4 },
|
||||||
|
{ "Near end of post-leap day, -86400s", regression5 },
|
||||||
|
{ "End of post-leap day, -86400s", regression6 },
|
||||||
|
{ 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int regression(void)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
struct regression_test* test;
|
||||||
|
|
||||||
|
for(test = regression_tests; test->func; ++test) {
|
||||||
|
if(test->func()) {
|
||||||
|
fprintf(stderr, "%s failed.\n", test->name);
|
||||||
|
++ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
int ret = 0, diff;
|
||||||
|
|
||||||
|
if(argc == 2 && !strcmp(argv[1], "--print-summary")) {
|
||||||
|
fputs("Leap second regression test.\n", stdout);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(argc) {
|
||||||
|
case 1:
|
||||||
|
ret = regression();
|
||||||
|
fputs("Alternative use: pass two dates on commandline to see elapsed leap seconds.\n",
|
||||||
|
stdout);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
ret = leap_diff(argv[1], argv[2], &diff);
|
||||||
|
if(!ret) printf("Leap second correction: %d\n", diff);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
if(!strcmp(argv[1], "--print-summary")) {
|
||||||
|
printf("Leap second regression test.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* fall through */
|
||||||
|
default:
|
||||||
|
ret = 1;
|
||||||
|
fputs("Either zero or two arguments expected.\n", stderr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO */
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* options for text editors
|
||||||
|
kate: replace-trailing-space-save true; space-indent true; tab-width 4;
|
||||||
|
vim: expandtab:ts=4:sw=4
|
||||||
|
*/
|
Loading…
Reference in New Issue