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)"
|
||||
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
|
||||
|
||||
libiso8601_MONOLITHIC=1
|
||||
|
|
|
@ -67,11 +67,14 @@ void iso8601_print(char* str, int amt, const struct iso8601_date* date,
|
|||
const struct iso8601_details* details);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* leap.c */
|
||||
int iso8601_seconds_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
|
||||
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
|
||||
kate: replace-trailing-space-save true; space-indent true; tab-width 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)
|
||||
{
|
||||
int sday;
|
||||
ldiv_t qr;
|
||||
|
||||
// TODO: leap second support
|
||||
|
||||
sday = date->day;
|
||||
qr = ldiv(seconds + date->sec, 86400);
|
||||
date->day += qr.quot;
|
||||
|
||||
date->sec = qr.rem;
|
||||
if(date->sec < 0) {
|
||||
--date->day;
|
||||
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