Compare commits

...

40 Commits

Author SHA1 Message Date
Laurence Withers 82aa0f2f20 Bump version 2015-06-12 11:01:21 +01:00
Laurence Withers 2e610c4db3 Add 2015-06-30 leap second to built-in table 2015-06-12 10:55:53 +01:00
Laurence Withers dd3fe182af Update build system (Doxyfile) 2015-06-12 10:53:31 +01:00
Laurence Withers 0d5c2078b3 Bump version 2013-04-05 09:35:19 +00:00
Laurence Withers 6b25293f35 Fix build system ordering
Make sure that the library is built before either of the isodate or setisodate
apps, otherwise we end up with problems compiling from scratch.
2013-04-05 09:32:22 +00:00
Laurence Withers dcb15f2081 Bump version 2012-01-07 17:42:57 +00:00
Laurence Withers 4c470ec1e9 Bump version 2012-01-07 17:42:57 +00:00
Laurence Withers ba81c458e1 Update for 2012-06-30 leap second 2012-01-07 17:42:44 +00:00
Laurence Withers 49536349f7 Bump version 2011-11-18 12:19:09 +00:00
Laurence Withers c7b38eab5a Bump version 2011-11-18 12:19:09 +00:00
Laurence Withers c198eaf34b Remove accidental variable definition 2011-11-16 12:04:15 +00:00
Laurence Withers b622223b64 Remove unneeded nonnull attribute 2011-11-16 09:58:21 +00:00
Laurence Withers 81df4e8a05 Add C++ extern C include guards 2011-11-15 16:49:46 +00:00
Laurence Withers 7a5f30bfcd Update build system 2011-11-15 16:49:46 +00:00
Laurence Withers d910e88bc3 Bump version 2010-08-02 12:01:43 +00:00
Laurence Withers 2aa3d5aaac Bump version 2010-08-02 12:01:43 +00:00
Laurence Withers d013bff263 Remove incorrect nonnull attribute
iso8601_leap_table_load() had an incorrect ‘nonnull’ attribute, which could
lead to crashes as the compiled code could omit the test for null which then
substitutes the system default. Fix it by removing the attribute.
2010-08-02 12:00:20 +00:00
Laurence Withers 8cc71fb069 Bump version 2010-06-18 12:49:36 +00:00
Laurence Withers 2d9621e0a5 Bump version 2010-06-18 12:49:33 +00:00
Laurence Withers 944331702f Cope with negative C library timestamps
While perhaps not strictly valid, negative timestamps can potentially be
returned by the C library and passed in to iso8601_from_ts() etc. This commit
adds a check for such timestamps and copes with the gracefully, whereas
previously invalid ISO8601 timestamps would have been generated.
2010-06-18 12:47:38 +00:00
Laurence Withers 0d56edd890 Bump version 2010-01-28 16:22:46 +00:00
Laurence Withers 65fe613272 Bump version 2010-01-28 16:22:39 +00:00
Laurence Withers 64e06d17c4 Add explicit note on params which may be null 2010-01-28 16:22:03 +00:00
Laurence Withers cd9a2d252a iso8601_difference(): incorrect nonnull attribute
iso8601_difference was incorrectly marked as having all of its attributes
required to be non-null, but this is not the case according to the docs or
the implementation. This was causing a crash as the compiled library was
taking advantage of the nonnull notation to remove some tests against null
which, according to the docs, are actually required.

Fix by tightening the nonnull specification to those parameters which actually
require it.
2010-01-28 16:17:53 +00:00
Laurence Withers ed05b5c872 Bump version 2010-01-08 19:26:21 +00:00
Laurence Withers bd4ddd7621 Write brief description for library
Add a brief description of the library on the doxygen front page.
2010-01-08 19:25:58 +00:00
Laurence Withers 420df40a5b Bring C code up to coding standards
Reformatting and comment improvement only. No code changes.
2010-01-08 19:22:36 +00:00
Laurence Withers 9f3fbd4116 Minor build system update
A fix for when there are multiple libraries in a single package. Doesn't apply
here but just in case.
2010-01-08 18:49:50 +00:00
Laurence Withers 6285d214aa Documentation and annotation updates
This commit updates the Doxygen documentation (particularly taking into account
a request from Kelly Dunlop for more verbose notice about which members are
changed by iso8601_from_*()) and file/function annotation/formatting to current
standards.
2010-01-08 18:46:34 +00:00
Laurence Withers e504a722f5 Bump version 2009-05-29 14:52:52 +00:00
Laurence Withers 1a0553e083 Bump version 2009-05-29 14:52:52 +00:00
Laurence Withers 7ba82a2988 Add default path for iso8601_leap_table_load() 2009-05-29 14:51:26 +00:00
Laurence Withers b7d039a32c Add iso8601_elapsed_divide() 2009-05-29 14:51:14 +00:00
Laurence Withers dcfc699af0 Bump version 2009-04-06 14:58:26 +00:00
Laurence Withers 47ccc537b8 Bump version 2009-04-06 14:58:26 +00:00
Laurence Withers 1d9447dcd2 Add iso8601_cmp(), comparison function for qsort() 2009-04-06 14:58:05 +00:00
Laurence Withers d09e55e8ae Update build system 2009-04-06 14:56:00 +00:00
Laurence Withers 3309803b9e Bump version 2009-02-12 02:32:14 +00:00
Laurence Withers 076d215860 Bump version 2009-02-12 02:32:14 +00:00
Laurence Withers 6937f2f12b Bugfix in rounding of iso8601_add_elapsed()
When adding a number of nanoseconds so that the resultant date lies exactly on
a second boundary, rounding was not performed when it should have been. Fix
the rounding so that the seconds field rolls over.
2009-02-12 02:31:04 +00:00
40 changed files with 3029 additions and 496 deletions

2
config
View File

@ -32,5 +32,7 @@
source "scripts/paths"
# Project-specific variables below.
[ -z "${DEFAULT_LEAP_TABLE}" ] && DEFAULT_LEAP_TABLE="${SHAREDIR}/libiso8601/leap-table"
[ -z "${CC}" ] && CC="gcc"
[ -z "${CFLAGS}" ] && CFLAGS="-g -O2 -W -Wall"

11
make.sh
View File

@ -1,7 +1,7 @@
#!/bin/sh
#!/bin/bash
# libiso8601/make.sh
#
# (c)2006-2007, Laurence Withers, <l@lwithers.me.uk>.
# (c)2009, Laurence Withers, <l@lwithers.me.uk>.
# Released under the GNU GPLv3. See file COPYING or
# http://www.gnu.org/copyleft/gpl.html for details.
#
@ -15,19 +15,19 @@ then
echo "Configuration file not found???"
exit 1
fi
source "config" # don't fail on error, since last command in config might return false
source "./config" # don't fail on error, since last command in config might return false
# Get version information
source version || exit 1
source "./version" || exit 1
VERSION="${VERMAJOR}.${VERMINOR}.${VERMICRO}"
# Get standard functions
[ -z "${VERBOSE}" ] && VERBOSE="0"
source scripts/functions.sh || exit 1
source "./scripts/functions.sh" || exit 1
# List of directories which will be emptied by clean.
@ -292,5 +292,4 @@ done
exit 0
# kate: replace-trailing-space-save true; space-indent true; tab-width 4;
# vim: expandtab:ts=4:sw=4

View File

@ -1,9 +1,9 @@
#!/bin/sh
#!/bin/bash
# libiso8601/test.sh
#
# (c)2007, Laurence Withers, <l@lwithers.me.uk>.
# Released under the GNU GPLv3. See file COPYING or
# http://www.gnu.org/copyleft/gpl.html for details.
# Copyright: ©20092011, Güralp Systems Ltd.
# Author: Laurence Withers <lwithers@guralp.com>
# License: GPLv3
#
# Running this script on its own will display a summary of all the
@ -21,7 +21,7 @@ run_test() {
return 1
fi
LD_LIBRARY_PATH="obj" "${EXE}" "$@" || return 1
LD_LIBRARY_PATH="obj:${LD_LIBRARY_PATH}" "${EXE}" "$@" || return 1
return 0
}
@ -33,14 +33,15 @@ print_tests() {
echo "---------------------------------------------------------------------"
for EXE in obj/tests/*
do
[ -x ${EXE} ] || continue
NAME=$(echo ${EXE} | sed 's,obj/tests/,,')
[ -x "${EXE}" ] || continue
NAME="$(echo "${EXE}" | sed 's,obj/tests/,,')"
echo -ne "${NAME}\t"
LD_LIBRARY_PATH="obj" ${EXE} --print-summary
LD_LIBRARY_PATH="obj:${LD_LIBRARY_PATH}" "${EXE}" --print-summary
done
}
# Main script
if [ $# -eq 0 ]
then
@ -48,7 +49,6 @@ then
exit 0
fi
run_test $*
run_test "$@"
# kate: replace-trailing-space-save true; space-indent true; tab-width 4;
# vim: expandtab:ts=4:sw=4

1
scripts/.gitignore vendored
View File

@ -7,6 +7,7 @@ build.docs.none
build.files.none
build.firmware.gpasm
build.firmware.sdcc
build.header.c
build.lib.c
build.lib.c++
build.make.none

View File

@ -1,8 +1,8 @@
# libiso8601/scripts/functions.sh
#
# (c)2007, Laurence Withers, <l@lwithers.me.uk>.
# Released under the GNU GPLv3. See file COPYING or
# http://www.gnu.org/copyleft/gpl.html for details.
# Copyright: ©20072011, Güralp Systems Ltd.
# Author: Laurence Withers, <lwithers@guralp.com>
# License: GPLv3
#
# Common functions
@ -63,5 +63,4 @@ do_cmd_redir() {
fi
}
# kate: replace-trailing-space-save true; space-indent true; tab-width 4;
# vim: expandtab:ts=4:sw=4

View File

@ -1,8 +1,8 @@
# libiso8601/scripts/paths
#
# (c)2007, Laurence Withers, <l@lwithers.me.uk>.
# Released under the GNU GPLv3. See file COPYING or
# http://www.gnu.org/copyleft/gpl.html for details.
# Copyright: ©2011, Güralp Systems Ltd.
# Author: Laurence Withers, <lwithers@guralp.com>
# License: GPLv3
#
# Default path setup. Not meant for editing; use environment variables
# to override values if needed.
@ -60,5 +60,4 @@ fi
[ -z "${WEBDIR}" ] && WEBDIR="${SRVDIR}/http"
[ -z "${CGIDIR}" ] && CGIDIR="${WEBDIR}/cgi-bin"
# kate: replace-trailing-space-save true; space-indent true; tab-width 4;
# vim: syntax=sh:expandtab:ts=4:sw=4

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +1,16 @@
/* libiso8601/src/docs/MainPage.dox
*
* (c)2007, Laurence Withers, <l@lwithers.me.uk>.
* (c)2007-2010, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv3. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details.
*/
/*! \mainpage
/*! \mainpage Library for manipulating ISO8601-format dates and times
\c libiso8601 is a library containing conversion routines for ISO8601-format
dates and times and a set of associated date/time manipulation routines. It has
support for leap seconds and nanosecond accuracy and is intended for use in
e.g. physical science applications.
*/

View File

@ -39,5 +39,4 @@ then
docs_BUILT=1
fi
# kate: replace-trailing-space-save true; space-indent true; tab-width 4;
# vim: syntax=sh:expandtab:ts=4:sw=4

View File

@ -17,5 +17,4 @@ do
done
print_success "Documentation installed"
# kate: replace-trailing-space-save true; space-indent true; tab-width 4;
# vim: syntax=sh:expandtab:ts=4:sw=4

View File

@ -8,7 +8,8 @@ build_target libiso8601
if [ -z ${isodate_BUILT} ]
then
isodate="obj/isodate"
EXTRAS="${libiso8601} ${libiso8601_DEP_CFLAGS} ${libiso8601_DEP_LIBS}"
EXTRAS="-std=gnu99 -D_GNU_SOURCE -DAPP_NAME=\"isodate\" \
${libiso8601} ${libiso8601_DEP_CFLAGS} ${libiso8601_DEP_LIBS}"
echo "Building application ${isodate}..."
@ -39,5 +40,4 @@ then
fi
# kate: replace-trailing-space-save true; space-indent true; tab-width 4;
# vim: syntax=sh:expandtab:ts=4:sw=4

View File

@ -8,5 +8,4 @@ echo "Installing binaries into '${BINDIR}'"
install_file "${isodate}" "${BINDIR}" 0755 || return 1
print_success "Done"
# kate: replace-trailing-space-save true; space-indent true; tab-width 4;
# vim: syntax=sh:expandtab:ts=4:sw=4

View File

@ -14,5 +14,4 @@ then
MONOLITHIC_DOC="${MONOLITHIC_DOC} ${SRC}"
fi
# kate: replace-trailing-space-save true; space-indent true; tab-width 4;
# vim: syntax=sh:expandtab:ts=4:sw=4

View File

@ -1,13 +1,17 @@
/* libiso8601/src/libiso8601/000_TopHeader.h
*
* (c)2006, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv2. See file COPYING or
* (c)2006-2010, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv3. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details.
*/
#ifndef HEADER_libiso8601
#define HEADER_libiso8601
#ifdef __cplusplus
extern "C" {
#endif
/* standard includes, or includes needed for type declarations */
#include <time.h>
#include <stdint.h>

View File

@ -1,7 +1,7 @@
/* libiso8601/src/libiso8601/000_TopSource.c
*
* (c)2006, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv2. See file COPYING or
* (c)2006-2010, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv3. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details.
*/

View File

@ -1,25 +1,28 @@
/* libiso8601/src/libiso8601/100_calc.c
*
* (c)2006, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv2. See file COPYING or
* (c)2006-2010, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv3. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details.
*/
/* CALCULATION ROUTINES
*
* This file contains calculation routines used internally in the library. Our date format is the
* number of days elapsed since 0000-001 (so that date would be 0, -0001-365 would be -1, etc.).
* Time is represented as the number of seconds elapsed since midnight at the start of the day. It
* is a value between 0 and 86399 (or 86400 for leap seconds).
*/
/* CALCULATION ROUTINES ********************************************************
This file contains calculation routines used internally in the library. Our
date format is the number of days elapsed since 0000-001 (so that date would be
0, -0001-365 would be -1, etc.). Time is represented as the number of seconds
elapsed since midnight at the start of the day. It is a value between 0 and
86399 (or 86400 for leap seconds).
*******************************************************************************/
#define DAYS_IN_400_YEARS (146097)
int iso8601_isleap(int year)
int
iso8601_isleap(int year)
{
if(year % 4) return 0;
if(year % 100) return 1;
@ -31,14 +34,15 @@ int iso8601_isleap(int year)
/* struct monthcount, _days_in_month_common[], _days_in_month_leap[]
*
* Tables of the number of days in each month, and the number of days elapsed since the start of
* the year for each month.
* Tables of the number of days in each month, and the number of days elapsed
* since the start of the year for each month.
*/
struct monthcount {
int elapsed, days;
};
static const struct monthcount _days_in_month_common[] = {
static const struct monthcount
_days_in_month_common[] = {
{ 0, 31 },
{ 31, 28 },
{ 59, 31 },
@ -53,7 +57,8 @@ static const struct monthcount _days_in_month_common[] = {
{ 334, 31 }
};
static const struct monthcount _days_in_month_leap[] = {
static const struct monthcount
_days_in_month_leap[] = {
{ 0, 31 },
{ 31, 29 },
{ 60, 31 },
@ -70,7 +75,8 @@ static const struct monthcount _days_in_month_leap[] = {
static int _days_in_month(int year, int month)
static int
_days_in_month(int year, int month)
{
const struct monthcount* mc;
@ -85,42 +91,45 @@ static int _days_in_month(int year, int month)
static void _to_year(int* year, int* days_left, const struct iso8601_date* date)
static void
_to_year(int* year, int* days_left, const struct iso8601_date* date)
{
div_t qr;
int ndays = date->day;
// Each 400 years have 97 leap days, giving 365*400+97 = DAYS_IN_400_YEARS days in 400 years
/* Each 400 years have 97 leap days, giving 365*400+97 = DAYS_IN_400_YEARS
days in 400 years */
qr = div(ndays, DAYS_IN_400_YEARS);
*year = qr.quot * 400;
ndays = qr.rem;
// ensure that we always end up with between 0 and 146096 days remaining
/* ensure that we always end up with between 0 and 146096 days remaining */
if(ndays < 0) {
ndays += DAYS_IN_400_YEARS;
*year -= 400;
}
// we insert `fake' leap days for years 101, 201, 301
/* we insert `fake' leap days for years 101, 201, 301 */
if(ndays >= 36890) ++ndays;
if(ndays >= 73415) ++ndays;
if(ndays >= 109940) ++ndays;
// each remaining 100 year block has 24 leap days, giving 365*100+24 = 36524 days
/* each remaining 100 year block has 24 leap days, giving 365*100+24 = 36524
days */
qr = div(ndays, 36525);
*year += qr.quot * 100;
ndays = qr.rem;
// each 4-year block has 1 leap day, giving 365*4 + 1 = 1461 days
/* each 4-year block has 1 leap day, giving 365*4 + 1 = 1461 days */
qr = div(ndays, 1461);
*year += qr.quot * 4;
ndays = qr.rem;
// the first year of a 4-year block has 1 leap day, 366 days
/* the first year of a 4-year block has 1 leap day, 366 days */
if(ndays >= 366) {
--ndays; // pretend to have dealt with leap day
--ndays; /* pretend to have dealt with leap day */
// 365 days per remaining year
/* 365 days per remaining year */
qr = div(ndays, 365);
*year += qr.quot;
ndays = qr.rem;
@ -131,15 +140,16 @@ static void _to_year(int* year, int* days_left, const struct iso8601_date* date)
void iso8601_to_cal(int* year, int* month, int* day, const struct iso8601_date* date)
void
iso8601_to_cal(int* year, int* month, int* day, const struct iso8601_date* date)
{
const struct monthcount* mc;
int ndays;
// perform year calulation
/* perform year calulation */
_to_year(year, &ndays, date);
// now we simply have number of days elapsed since day 001 in `year'.
/* now we simply have number of days elapsed since day 001 in `year'. */
mc = iso8601_isleap(*year) ? _days_in_month_leap : _days_in_month_common;
*month = 1;
while(ndays >= mc->days) {
@ -152,35 +162,38 @@ void iso8601_to_cal(int* year, int* month, int* day, const struct iso8601_date*
void iso8601_to_ord(int* year, int* oday, const struct iso8601_date* date)
void
iso8601_to_ord(int* year, int* oday, const struct iso8601_date* date)
{
int ndays;
// perform year calcutation
/* perform year calcutation */
_to_year(year, &ndays, date);
// now we simply have number of days elapsed since day 001 in `year'.
/* now we simply have number of days elapsed since day 001 in `year'. */
*oday = ndays + 1;
}
static int _weekday_of_year(int year)
static int
_weekday_of_year(int year)
{
int w = 6;
/* Algorithm notes:
* - 0 = sun, 1 = mon, ..., 6 = sat
* - 0000-001 is a Saturday, day 6
* - every year we pass gives us one additional day (364 is divisible by 7)
* - but of course every leap year we pass gives us a further day
* - so for every 400 years, we add 497 (400 common years, 97 leap years); 497 % 7 = 0
* 0 = sun, 1 = mon, ..., 6 = sat
* 0000-001 is a Saturday, day 6
* every year we pass gives us one additional day (364 is divisible by 7)
* but of course every leap year we pass gives us a further day
* so for every 400 years, we add 497 (400 common years, 97 leap years);
* 497 % 7 = 0
*/
year %= 400;
if(year < 0) year += 400; // end up with between 0-399 years left
w += year; // excluding leap years, we increase by 1 day a year
w += (year + 3) / 4; // there is one leap year for every four years
w -= (year - 1) / 100; // but one less for every century over 0
if(year < 0) year += 400; /* end up with between 0-399 years left */
w += year; /* excluding leap years, we increase by 1 day a year */
w += (year + 3) / 4; /* there is one leap year for every four years */
w -= (year - 1) / 100; /* but one less for every century over 0 */
w %= 7;
return w;
@ -188,42 +201,47 @@ static int _weekday_of_year(int year)
void iso8601_to_week(int* year, int* week, int* wday, const struct iso8601_date* date)
void
iso8601_to_week(int* year, int* week, int* wday,
const struct iso8601_date* date)
{
int ndays, w, has53 = 0;
div_t d;
// perform year and weekday calculation
/* perform year and weekday calculation */
_to_year(year, &ndays, date);
w = _weekday_of_year(*year);
// find out what day jan 1 was; from there, we can find the ISO week and year number
/* find out what day jan 1 was; from there, we can find the ISO week and
year number */
switch(w) {
case 4: // W01 starts XXXY-12-28
case 4: /* W01 starts XXXY-12-28 */
w += 7;
has53 = 1; // years starting Thursday have 53 weeks
has53 = 1; /* years starting Thursday have 53 weeks */
break;
case 5: // W01 starts XXXZ-01-03
case 6: // W01 starts XXXZ-01-02
case 5: /* W01 starts XXXZ-01-03 */
case 6: /* W01 starts XXXZ-01-02 */
break;
case 0: // W01 starts XXXZ-01-01
case 1: // W01 starts XXXY-12-31
case 2: // W01 starts XXXY-12-30
w += 7; // for week calculation
case 0: /* W01 starts XXXZ-01-01 */
case 1: /* W01 starts XXXY-12-31 */
case 2: /* W01 starts XXXY-12-30 */
w += 7; /* for week calculation */
break;
case 3: // W01 starts XXXY-12-29
case 3: /* W01 starts XXXY-12-29 */
w += 7;
if(iso8601_isleap(*year)) has53 = 1; // leap years starting Wednesday have 53 weeks
if(iso8601_isleap(*year)) has53 = 1; /* leap years starting Wednesday
have 53 weeks */
}
// now we simply add the number of days elapsed since the start of the year, and % 7
/* now we simply add the number of days elapsed since the start of the
year, and % 7 */
w += ndays;
d = div(w, 7); // w can never be 0
d = div(w, 7); /* w can never be 0 */
// do Sunday correction
/* do Sunday correction */
if(!d.rem) {
d.rem = 7;
--d.quot;
@ -256,54 +274,57 @@ void iso8601_to_week(int* year, int* week, int* wday, const struct iso8601_date*
int _from_year(struct iso8601_date* date, int year)
static int
_from_year(struct iso8601_date* date, int year)
{
div_t qr;
// check for range errors
/* check for range errors */
if(year < -5879609 || year > 5879609) {
errno = ERANGE;
return -1;
}
// Each 400 years have 97 leap days, giving 365*400+97 = DAYS_IN_400_YEARS days in 400 years
/* Each 400 years have 97 leap days, giving 365*400+97 = DAYS_IN_400_YEARS
days in 400 years */
qr = div(year, 400);
date->day = qr.quot * DAYS_IN_400_YEARS;
year = qr.rem;
// ensure we have between 0 and 399 years
/* ensure we have between 0 and 399 years */
if(year < 0) {
date->day -= DAYS_IN_400_YEARS;
year += 400;
}
// excluding leap days, there are 365 days per year
/* excluding leap days, there are 365 days per year */
date->day += 365 * year;
date->day += (year + 3) / 4; // there is one leap year for every four years
date->day -= (year - 1) / 100; // but one less for every century over 0
date->day += (year + 3) / 4; /* one leap year for every four years */
date->day -= (year - 1) / 100; /* but one less for every century over 0 */
return 0;
}
int iso8601_from_cal(struct iso8601_date* date, int year, int month, int day)
int
iso8601_from_cal(struct iso8601_date* date, int year, int month, int day)
{
const struct monthcount* mc;
// check for domain errors
/* check for domain errors */
mc = iso8601_isleap(year) ? _days_in_month_leap : _days_in_month_common;
if(month < 1 || month > 12 || day < 1 || day > mc[month - 1].days) {
errno = EDOM;
return -1;
}
// perform year calculation
/* perform year calculation */
if(_from_year(date, year)) return -1;
// now get number of days elapsed up to start of month
/* now get number of days elapsed up to start of month */
date->day += mc[month - 1].elapsed;
// and add number of days elapsed sinced start of month
/* and add number of days elapsed sinced start of month */
date->day += day - 1;
return 0;
@ -311,18 +332,19 @@ int iso8601_from_cal(struct iso8601_date* date, int year, int month, int day)
int iso8601_from_ord(struct iso8601_date* date, int year, int oday)
int
iso8601_from_ord(struct iso8601_date* date, int year, int oday)
{
// check for domain errors
/* check for domain errors */
if(oday < 1 || oday > (iso8601_isleap(year) ? 366 : 365)) {
errno = EDOM;
return -1;
}
// perform year calculation
/* perform year calculation */
if(_from_year(date, year)) return -1;
// now simply add number of days elapsed this year
/* now simply add number of days elapsed this year */
date->day += oday - 1;
return 0;
@ -330,18 +352,19 @@ int iso8601_from_ord(struct iso8601_date* date, int year, int oday)
int iso8601_from_week(struct iso8601_date* date, int isoyear, int week, int wday)
int
iso8601_from_week(struct iso8601_date* date, int isoyear, int week, int wday)
{
int day1off, maxwk;
// compute year part
/* compute year part */
_from_year(date, isoyear);
// 400-year cycle; ensure we're between 0-400 years
/* 400-year cycle; ensure we're between 0-400 years */
isoyear %= 400;
if(isoyear < 0) isoyear += 400;
// domain check
/* domain check */
maxwk = (((isoyear % 7) == 52) || ((isoyear % 28) == 24)) ? 53 : 52;
if(wday < 1 || wday > 7 || week < 1 || week > maxwk) {
errno = EDOM;
@ -349,18 +372,20 @@ int iso8601_from_week(struct iso8601_date* date, int isoyear, int week, int wday
}
/* Algorithm notes:
* We now compute the offset between the start day of the ISO year and the start day of the
* real year. Year 0000 starts on a Saturday, meaning the ISO year 0000 starts on 0000-003
* (offset of +2 days). Each year reduces the offset by one day, and each leap year reduces it
* by a further day; the offset wraps from -3 to +3.
* We now compute the offset between the start day of the ISO year and
* the start day of the real year. Year 0000 starts on a Saturday, meaning
* the ISO year 0000 starts on 0000-003 (offset of +2 days). Each year
* reduces the offset by one day, and each leap year reduces it by a
* further day; the offset wraps from -3 to +3.
*/
day1off = 2 - isoyear; // reduce offset by 1 for each year
day1off += (isoyear - 1) / 100; // cancel out 1 leap year for each century past the first
day1off -= (isoyear + 3) / 4; // 1 leap year every 4 years
day1off = 2 - isoyear; /* reduce offset by 1 for each year */
day1off += (isoyear - 1) / 100; /* cancel out 1 leap year for each century
past the first */
day1off -= (isoyear + 3) / 4; /* 1 leap year every 4 years */
day1off %= 7;
if(day1off < -3) day1off += 7;
// now simply add in the day offset and days/weeks elapsed
/* now simply add in the day offset and days/weeks elapsed */
date->day += day1off + (week - 1) * 7 + wday - 1;
return 0;
@ -368,11 +393,13 @@ int iso8601_from_week(struct iso8601_date* date, int isoyear, int week, int wday
void iso8601_to_clocktime(int* hour, int* min, int* sec, const struct iso8601_date* date)
void
iso8601_to_clocktime(int* hour, int* min, int* sec,
const struct iso8601_date* date)
{
div_t qr;
// special case: leap second
/* special case: leap second */
if(date->sec == 86400) {
*hour = 23;
*min = 59;
@ -380,7 +407,7 @@ void iso8601_to_clocktime(int* hour, int* min, int* sec, const struct iso8601_da
return;
}
// normal case
/* normal case */
qr = div(date->sec, 3600);
*hour = qr.quot;
qr = div(qr.rem, 60);
@ -390,21 +417,22 @@ void iso8601_to_clocktime(int* hour, int* min, int* sec, const struct iso8601_da
int iso8601_from_clocktime(struct iso8601_date* date, int hour, int min, int sec)
int
iso8601_from_clocktime(struct iso8601_date* date, int hour, int min, int sec)
{
// special case: leap second
/* special case: leap second */
if(hour == 23 && min == 59 && sec == 60) {
date->sec = 86400;
return 0;
}
// domain check
/* domain check */
if(hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 || sec > 59) {
errno = EDOM;
return -1;
}
// normal calculation
/* normal calculation */
date->sec = hour * 3600 + min * 60 + sec;
return 0;
}

View File

@ -1,13 +1,20 @@
/* libiso8601/src/libiso8601/100_leap.c
*
* (c)2006, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv2. See file COPYING or
* (c)2006-2010, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv3. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details.
*/
static int leap_second_days_table[] = {
/* leap_second_days_table[]
* This is a sorted array of days (in libiso8601 format) on which a positive
* leap second occurred. This table is built in to the library, but may be
* overridden at runtime by changing what leap_second_days points to. There
* should be no other references to this table, therefore.
*/
static int
leap_second_days_table[] = {
720439, /* 1972-06-30 */
720623, /* 1972-12-31 */
720988, /* 1973-12-31 */
@ -32,25 +39,47 @@ static int leap_second_days_table[] = {
730119, /* 1998-12-31 */
732676, /* 2005-12-31 */
733772, /* 2008-12-31 */
735049, /* 2012-06-30 */
736144, /* 2015-06-30 */
};
static int* leap_second_days = leap_second_days_table;
static int leap_second_days_num = sizeof(leap_second_days_table) / sizeof(int);
/* leap_second_days[], leap_second_days_num
* Pointer to an array (and number of elements in the array) representing the
* table of positive leap seconds. The array is sorted and contains libiso8601
* day numbers of days with positive leap seconds.
*/
static int*
leap_second_days = leap_second_days_table;
static int
leap_second_days_num = sizeof(leap_second_days_table) / sizeof(int);
int iso8601_seconds_leap(const struct iso8601_date* date)
/* iso8601_seconds_leap()
* Returns the number of seconds that elapse on a given date, which requires us
* to search the table of leap seconds to see if we need to return a special
* case.
*/
int
iso8601_seconds_leap(const struct iso8601_date* date)
{
int i;
for(i = 0; i < leap_second_days_num; ++i) if(leap_second_days[i] == date->day) return 86401;
for(i = 0; i < leap_second_days_num; ++i) {
if(leap_second_days[i] == date->day) return 86401;
}
return 86400;
}
static int _leap_elapsed_day(int sday, int eday)
/* _leap_elapsed_day()
* Returns the number of leap seconds that have elapsed between sday (start
* day) and eday (end day), both in libiso8601 format.
*/
static int
_leap_elapsed_day(int sday, int eday)
{
int spos, epos;
@ -66,16 +95,31 @@ static int _leap_elapsed_day(int sday, int eday)
int iso8601_leap_elapsed(const struct iso8601_date* start, const struct iso8601_date* end)
/* iso8601_leap_elapsed()
* Wrapper around _leap_elapsed_day().
*/
int
iso8601_leap_elapsed(const struct iso8601_date* start,
const struct iso8601_date* end)
{
return _leap_elapsed_day(start->day, end->day);
}
/* leap_table_free_old
* If set, then when we update the leap table, we should free the old array.
* Initially clear so that we don't free our static built-in table.
*/
static int leap_table_free_old = 0;
void iso8601_leap_table_set(int* new_table, int new_size)
/* iso8601_leap_table_set()
* Switch to using a new table of leap seconds, possibly freeing the old one.
*/
void
iso8601_leap_table_set(int* new_table, int new_size)
{
if(leap_table_free_old) free(leap_second_days);
leap_table_free_old = 0;
@ -86,16 +130,29 @@ void iso8601_leap_table_set(int* new_table, int new_size)
static const char* leap_table_signature = "/O9PdPZI";
/* leap_table_signature
* The first 8 bytes of a leap second table must match this string, otherwise
* the file is taken not to be of the correct format.
*/
static const char*
leap_table_signature = "/O9PdPZI";
int iso8601_leap_table_load(const char* fname)
/* iso8601_leap_table_load()
* Loads a new table of leap seconds from disk. Ensures the signature of the
* given file matches leap_table_signature, and does some basic sanity
* checking (file in sorted order etc.).
*/
int
iso8601_leap_table_load(const char* fname)
{
struct stat st;
int fd, saved_errno, i, new_size, * days = 0;
char buf[12];
if(!fname) fname = DEFAULT_LEAP_TABLE;
if(stat(fname, &st)) return -1;
if(st.st_size < 12) {
errno = EINVAL;

View File

@ -1,7 +1,7 @@
/* libiso8601/src/libiso8601/100_types.h
*
* (c)2006, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv2. See file COPYING or
* (c)2006-2010, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv3. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details.
*/
@ -9,12 +9,13 @@
/*! \brief Date/time point.
This structure contains the details to represent a specific instant on the UTC timescale. It uses
Jan 1, year 0000 as the origin (when \a day will be 0). \a sec is the number of seconds elapsed
since start of day, and \a nsec is the number of nanoseconds elapsed since the start of the current
second.
This structure contains the details to represent a specific instant on the UTC
timescale. It uses Jan 1, year 0000 as the origin (when \a day will be 0). \a
sec is the number of seconds elapsed since start of day, and \a nsec is the
number of nanoseconds elapsed since the start of the current second.
We correctly deal with leap seconds by encoding 23:59:60 as having a \a sec field of 86400.
We correctly deal with leap seconds by encoding 23:59:60 as having a \a sec
field of 86400.
*/
struct iso8601_date {
@ -33,9 +34,10 @@ struct iso8601_date {
/*! \brief Date (day portion) precision.
\ingroup parser
This enumeration will record how precisely the date was specified, as well as the format in use. It
allows the library to determine the earliest and latest dates that could possibly be represented
with the given input and also allows the output format to match the input format.
This enumeration will record how precisely the date was specified, as well as
the format in use. It allows the library to determine the earliest and latest
dates that could possibly be represented with the given input and also allows
the output format to match the input format.
*/
enum iso8601_date_prec {
@ -56,16 +58,17 @@ enum iso8601_date_prec {
/*! \brief Year, week and weekday specified (week format). */
iso8601_prec_wday
}date_prec;
};
/*! \brief Time precision.
\ingroup parser
This enumeration records how precisely the time was specified as well as its format. The fractional
format will record whether it was the hour, minute or second that was specified with a fractional
part, allowing a processed date/time to be presented to the user in the format it was originally
This enumeration records how precisely the time was specified as well as its
format. The fractional format will record whether it was the hour, minute or
second that was specified with a fractional part, allowing a processed
date/time to be presented to the user in the format it was originally
encountered.
*/
@ -84,16 +87,16 @@ enum iso8601_time_prec {
iso8601_prec_minfrac,
/*! \brief Display hour, minute, second and nanoseconds. */
iso8601_prec_secfrac
}time_prec;
};
/*! \brief Date/time formatting details.
This structure simply records details related to the formatting (and precision) of a date/time
structure. The structure can be filled out by the parser so that a program's output can match
the format of its input. Alternatively it can be controlled by the program to provide a consistent
output format.
This structure simply records details related to the formatting (and precision)
of a date/time structure. The structure can be filled out by the parser so that
a program's output can match the format of its input. Alternatively it can be
controlled by the program to provide a consistent output format.
*/
struct iso8601_details {
@ -114,9 +117,10 @@ struct iso8601_details {
/*! \brief Short period elapsed time.
This structure contains the details of an elapsed time period, split into seconds and nanoseconds.
None of its components can ever be negative. This is only capable of representing short (compared to
struct iso8601_date's range) periods of up to approximately 136 years.
This structure contains the details of an elapsed time period, split into
seconds and nanoseconds. None of its components can ever be negative. This is
only capable of representing short (compared to struct iso8601_date's range)
periods of up to approximately 136 years.
*/
struct iso8601_elapsed {

View File

@ -1,24 +1,25 @@
/* libiso8601/src/libiso8601/200_parser.c
*
* (c)2006, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv2. See file COPYING or
* (c)2006-2010, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv3. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details.
*/
int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601_date* latest,
struct iso8601_details* details)
int
iso8601_parse(const char* str, struct iso8601_date* earliest,
struct iso8601_date* latest, struct iso8601_details* details)
{
enum {
state_none,
state_year, // e.g. `2006' or `2006123'
state_date2, // 2nd component of date, e.g. `2006-' or `2006-1'
state_day, // e.g. `2006-01-' or `2006-01-01'
state_week_basic, // e.g. `2006W' or `2006W123'
state_week_extended, // e.g. `2006-W' or `2006-W31'
state_week_day, // e.g. `2006-W31-'
state_week_done, // `2006-W31-1'
state_year, /* e.g. `2006' or `2006123' */
state_date2, /* 2nd component of date, e.g. `2006-' or `2006-1' */
state_day, /* e.g. `2006-01-' or `2006-01-01' */
state_week_basic, /* e.g. `2006W' or `2006W123' */
state_week_extended, /* e.g. `2006-W' or `2006-W31' */
state_week_day, /* e.g. `2006-W31-' */
state_week_done, /* `2006-W31-1' */
state_time_basic,
state_time_hour,
state_time_min,
@ -34,8 +35,9 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601
div_t qr;
char ch;
int num = 0, neg = 0, dig = 0, tz_neg = 0, nsec = -1, nsec_dig = -1, leap_sec_req = 0;
int y = 0, m = -1, d = -1, w = -1, wd = -1, hour = -1, min = -1, sec = -1, tz_sec = 0;
int num = 0, neg = 0, dig = 0, tz_neg = 0, nsec = -1, nsec_dig = -1,
leap_sec_req = 0, y = 0, m = -1, d = -1, w = -1, wd = -1, hour = -1,
min = -1, sec = -1, tz_sec = 0;
double frac;
struct iso8601_elapsed elapsed;
@ -436,7 +438,8 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601
case '-':
tz_neg = -1;
case '+':
state = (state == state_time_nsec_basic) ? state_tz_basic : state_tz_hour;
state = (state == state_time_nsec_basic) ?
state_tz_basic : state_tz_hour;
break;
}
break;
@ -544,7 +547,8 @@ done:
if(m != -1) {
if(d == -1) {
ERROR_IF(earliest && iso8601_from_cal(earliest, y, m, 1));
ERROR_IF(latest && iso8601_from_cal(latest, y, m, _days_in_month(y, m)));
ERROR_IF(latest && iso8601_from_cal(latest, y, m,
_days_in_month(y, m)));
if(details) details->date_prec = iso8601_prec_month;
} else {
@ -608,7 +612,8 @@ done:
} else if(min != -1) {
if(nsec_dig == -1) {
ERROR_IF(earliest && iso8601_from_clocktime(earliest, hour, min, 0));
ERROR_IF(earliest && iso8601_from_clocktime(earliest,
hour, min, 0));
ERROR_IF(latest && iso8601_from_clocktime(latest, hour, min, 59));
if(latest) latest->nsec = 999999999;
if(details) details->time_prec = iso8601_prec_min;
@ -617,7 +622,8 @@ done:
frac = nsec * 60.0 / 1e9;
sec = (int)frac;
nsec = (frac - sec) * 1e9;
ERROR_IF(earliest && iso8601_from_clocktime(earliest, hour, min, sec));
ERROR_IF(earliest && iso8601_from_clocktime(earliest,
hour, min, sec));
if(earliest) earliest->nsec = nsec;
ERROR_IF(latest && iso8601_from_clocktime(latest, hour, min, sec));
if(latest) latest->nsec = nsec;
@ -639,7 +645,8 @@ done:
frac *= 60;
sec = (int)frac;
nsec = (frac - sec) * 1e9;
ERROR_IF(earliest && iso8601_from_clocktime(earliest, hour, min, sec));
ERROR_IF(earliest && iso8601_from_clocktime(earliest,
hour, min, sec));
if(earliest) earliest->nsec = nsec;
ERROR_IF(latest && iso8601_from_clocktime(latest, hour, min, sec));
if(latest) latest->nsec = nsec;
@ -676,7 +683,8 @@ done:
int iso8601_invalid(const struct iso8601_date* date)
int
iso8601_invalid(const struct iso8601_date* date)
{
return date->nsec < 0
|| date->nsec >= BILLION

View File

@ -1,7 +1,7 @@
/* libiso8601/src/libiso8601/200_parser.h
*
* (c)2006, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv2. See file COPYING or
* (c)2006-2010, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv3. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details.
*/
@ -9,31 +9,41 @@
/*! \defgroup parser Parsing, printing and validation routines.
These routines are used for parsing an ISO8601 date/time string into the internal structure used
to represent them, and for validating such dates/times.
These routines are used for parsing an ISO8601 date/time string into the
internal structure used to represent them, and for validating such dates/times.
*/
/*!@{*/
/*! \brief Parse ISO8601 date/time.
\param str The input string. Whitespace will be stripped.
\param[out] earliest The earliest possible time the string could represent. May be 0.
\param[out] latest The latest possible time the string could represent. May be 0.
\param[out] details Stores details such as the precision to which the time/date were specified. May
\param[out] earliest The earliest possible time the string could represent. May
be 0.
\param[out] latest The latest possible time the string could represent. May be
0.
\param[out] details Stores details such as the precision to which the time/date
were specified. May be 0.
\retval -1 on error.
\retval 0 on success.
Parses a string containing the ISO8601 date/time. Deals with any format of date, optionally storing
the details in \a details. The time may be partial, in which case this function returns the earliest
and latest times that could possibly be represented by the string.
Parses a string containing the ISO8601 date/time. Deals with any format of
date, optionally storing the details in \a details. The time may be partial, in
which case this function returns the earliest and latest times that could
possibly be represented by the string.
Note that this function will accept leap seconds (23:59:60) on days on which they occurred.
Note that this function will accept leap seconds (23:59:60) on days on which
they occurred.
*/
int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601_date* latest,
struct iso8601_details* details);
int iso8601_parse(const char* str, struct iso8601_date* earliest,
struct iso8601_date* latest, struct iso8601_details* details)
#ifndef DOXYGEN
__attribute__((nonnull(1),warn_unused_result))
#endif
;
@ -45,12 +55,17 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601
\param details Formatting details (may be 0).
\returns Pointer to buffer (\a str).
Formats and prints an ISO8601 date, optionally using the details in \a details. Will always return
a null-terminated result, even if that means truncating the output to fit the buffer.
Formats and prints an ISO8601 date, optionally using the details in \a details.
Will always return a null-terminated result, even if that means truncating the
output to fit the buffer.
*/
char* iso8601_print(char* str, int amt, const struct iso8601_date* date,
const struct iso8601_details* details);
const struct iso8601_details* details)
#ifndef DOXYGEN
__attribute__((nonnull(1,3)))
#endif
;
@ -60,18 +75,21 @@ char* iso8601_print(char* str, int amt, const struct iso8601_date* date,
\retval -1 if not valid.
\retval 0 if valid.
Checks the details of \a date to ensure that they are sensible. This involves checking that \a sec
is in the range 0 to 86399 (or 86400 if there is a leap second), and that \a nsec is in the range 0
to 999999999.
Checks the details of \a date to ensure that they are sensible. This involves
checking that \a sec is in the range 0 to 86399 (or 86400 if there is a leap
second), and that \a nsec is in the range 0 to 999999999.
*/
int iso8601_invalid(const struct iso8601_date* date);
int iso8601_invalid(const struct iso8601_date* date)
#ifndef DOXYGEN
__attribute__((nonnull))
#endif
;
/*!@}*/
/* options for text editors
kate: replace-trailing-space-save true; space-indent true; tab-width 4;
vim: expandtab:ts=4:sw=4
vim: expandtab:ts=4:sw=4:syntax=ch.doxygen
*/

View File

@ -1,13 +1,18 @@
/* libiso8601/src/libiso8601/print.c
/* libiso8601/src/libiso8601/200_print.c
*
* (c)2006, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv2. See file COPYING or
* (c)2006-2010, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv3. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details.
*/
static const struct iso8601_details _default_details = {
/* _default_details
* If the user doesn't pass precision details to iso8601_print(), these are
* used instead.
*/
static const struct iso8601_details
_default_details = {
iso8601_prec_day,
iso8601_prec_sec,
1,
@ -16,7 +21,8 @@ static const struct iso8601_details _default_details = {
char* iso8601_print(char* str, int amt, const struct iso8601_date* date,
char*
iso8601_print(char* str, int amt, const struct iso8601_date* date,
const struct iso8601_details* details)
{
int y, m, d, ret = 0, extended;
@ -27,10 +33,10 @@ char* iso8601_print(char* str, int amt, const struct iso8601_date* date,
str_orig = str;
// use default details if none provided
/* use default details if none provided */
if(!details) details = &_default_details;
// adjust output for timezone
/* adjust output for timezone */
dttz = *date;
if(details->tz_sec) {
elapsed.sec = details ? details->tz_sec : 0;
@ -38,7 +44,7 @@ char* iso8601_print(char* str, int amt, const struct iso8601_date* date,
iso8601_add_elapsed(&dttz, &elapsed);
}
// determine whether or not to force extended output
/* determine whether or not to force extended output */
iso8601_to_cal(&y, &m, &d, &dttz);
extended = details->extended || y < 0 || y > 9999;
@ -55,27 +61,32 @@ char* iso8601_print(char* str, int amt, const struct iso8601_date* date,
case iso8601_prec_day:
if(y < 0) ret = snprintf(str, amt, "%05d-%02d-%02d", y, m, d);
else ret = snprintf(str, amt, extended ? "%04d-%02d-%02d" : "%04d%02d%02d", y, m, d);
else ret = snprintf(str, amt, extended ?
"%04d-%02d-%02d" : "%04d%02d%02d", y, m, d);
break;
case iso8601_prec_ord:
iso8601_to_ord(&y, &d, &dttz);
if(y < 0) ret = snprintf(str, amt, "%05d-%03d", y, d);
else ret = snprintf(str, amt, extended ? "%04d-%03d" : "%04d%03d", y, d);
else ret = snprintf(str, amt, extended ?
"%04d-%03d" : "%04d%03d", y, d);
break;
case iso8601_prec_week:
iso8601_to_week(&y, &m, &d, &dttz);
extended = y < 0 || y > 9999 || details->extended; // ISO year is different
/* note: ISO year can differ, so recompute extended flag */
extended = y < 0 || y > 9999 || details->extended;
if(y < 0) snprintf(str, amt, "%05d-W%02d", y, m);
else snprintf(str, amt, extended ? "%04d-W%02d" : "%04dW%02d", y, m);
return str_orig;
case iso8601_prec_wday:
iso8601_to_week(&y, &m, &d, &dttz);
extended = y < 0 || y > 9999 || details->extended; // ISO year is different
/* note: ISO year can differ, so recompute extended flag */
extended = y < 0 || y > 9999 || details->extended;
if(y < 0) ret = snprintf(str, amt, "%05d-W%02d-%d", y, m, d);
else ret = snprintf(str, amt, extended ? "%04d-W%02d-%d" : "%04dW%02d%d", y, m, d);
else ret = snprintf(str, amt, extended ?
"%04d-W%02d-%d" : "%04dW%02d%d", y, m, d);
break;
}
@ -111,7 +122,8 @@ char* iso8601_print(char* str, int amt, const struct iso8601_date* date,
break;
case iso8601_prec_sec:
ret = snprintf(str, amt, extended ? "T%02d:%02d:%02d" : "T%02d%02d%02d", y, m, d);
ret = snprintf(str, amt, extended ?
"T%02d:%02d:%02d" : "T%02d%02d%02d", y, m, d);
break;
case iso8601_prec_hourfrac:
@ -121,12 +133,14 @@ char* iso8601_print(char* str, int amt, const struct iso8601_date* date,
case iso8601_prec_minfrac:
frac = m + (d + date->nsec / 1e9) / 60.0;
ret = snprintf(str, amt, extended ? "T%02d:%#012.9f" : "T%02d%#012.9f", y, frac);
ret = snprintf(str, amt, extended ?
"T%02d:%#012.9f" : "T%02d%#012.9f", y, frac);
break;
case iso8601_prec_secfrac:
frac = d + date->nsec / 1e9;
ret = snprintf(str, amt, extended ? "T%02d:%02d:%#012.9f" : "T%02d%02d%#012.9f", y, m, frac);
ret = snprintf(str, amt, extended ?
"T%02d:%02d:%#012.9f" : "T%02d%02d%#012.9f", y, m, frac);
break;
}
@ -150,8 +164,10 @@ char* iso8601_print(char* str, int amt, const struct iso8601_date* date,
ret -= m * 60;
d = ret;
if(d) snprintf(str, amt, extended ? "%02d:%02d:%02d" : "%02d%02d%02d", y, m, d);
else if(m) snprintf(str, amt, extended ? "%02d:%02d" : "%02d%02d", y, m);
if(d) snprintf(str, amt, extended ?
"%02d:%02d:%02d" : "%02d%02d%02d", y, m, d);
else if(m) snprintf(str, amt, extended ?
"%02d:%02d" : "%02d%02d", y, m);
else snprintf(str, amt, "%02d", y);
} else {
*str++ = 'Z';

View File

@ -1,16 +1,17 @@
/* libiso8601/src/libiso8601/400_c_library.c
*
* (c)2006, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv2. See file COPYING or
* (c)2006-2010, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv3. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details.
*/
// days between 0000-001 and 1970-001 (the unix epoch)
/* days between 0000-001 and 1970-001 (the unix epoch) */
#define EPOCH_GDAY (719528)
void iso8601_now(struct iso8601_date* date, struct iso8601_details* details)
void
iso8601_now(struct iso8601_date* date, struct iso8601_details* details)
{
static int use_gettimeofday = 0;
struct timespec ts;
@ -21,7 +22,8 @@ void iso8601_now(struct iso8601_date* date, struct iso8601_details* details)
if(use_gettimeofday || clock_gettime(CLOCK_REALTIME, &ts)) {
use_gettimeofday = 1;
gettimeofday(&tv, 0);
ts.tv_sec = tv.tv_sec;
if(tv.tv_sec < 0) ts.tv_sec = 0;
else ts.tv_sec = tv.tv_sec;
ts.tv_nsec = tv.tv_usec * 1000L;
}
@ -44,7 +46,8 @@ void iso8601_now(struct iso8601_date* date, struct iso8601_details* details)
int iso8601_set_sysclock(const struct iso8601_date* date)
int
iso8601_set_sysclock(const struct iso8601_date* date)
{
static int use_settimeofday = 0;
struct timeval tv;
@ -71,11 +74,16 @@ int iso8601_set_sysclock(const struct iso8601_date* date)
void iso8601_from_ts(struct iso8601_date* date, const struct timespec* ts)
void
iso8601_from_ts(struct iso8601_date* date, const struct timespec* ts)
{
ldiv_t qr;
qr = ldiv(ts->tv_sec, 86400);
if(ts->tv_sec < 0) {
--qr.quot;
qr.rem += 86400;
}
date->day = EPOCH_GDAY + qr.quot;
date->sec = qr.rem;
date->nsec = ts->tv_nsec;
@ -83,7 +91,8 @@ void iso8601_from_ts(struct iso8601_date* date, const struct timespec* ts)
void iso8601_to_ts(struct timespec* ts, const struct iso8601_date* date)
void
iso8601_to_ts(struct timespec* ts, const struct iso8601_date* date)
{
ts->tv_sec = 86400L * (date->day - EPOCH_GDAY) + date->sec;
ts->tv_nsec = date->nsec;
@ -91,11 +100,16 @@ void iso8601_to_ts(struct timespec* ts, const struct iso8601_date* date)
void iso8601_from_tv(struct iso8601_date* date, const struct timeval* tv)
void
iso8601_from_tv(struct iso8601_date* date, const struct timeval* tv)
{
ldiv_t qr;
qr = ldiv(tv->tv_sec, 86400);
if(tv->tv_sec < 0) {
--qr.quot;
qr.rem += 86400;
}
date->day = EPOCH_GDAY + qr.quot;
date->sec = qr.rem;
date->nsec = tv->tv_usec * 1000;
@ -103,7 +117,8 @@ void iso8601_from_tv(struct iso8601_date* date, const struct timeval* tv)
void iso8601_to_tv(struct timeval* tv, const struct iso8601_date* date)
void
iso8601_to_tv(struct timeval* tv, const struct iso8601_date* date)
{
tv->tv_sec = 86400L * (date->day - EPOCH_GDAY) + date->sec;
tv->tv_usec = date->nsec / 1000;
@ -111,11 +126,16 @@ void iso8601_to_tv(struct timeval* tv, const struct iso8601_date* date)
void iso8601_from_time_t(struct iso8601_date* date, const time_t* t)
void
iso8601_from_time_t(struct iso8601_date* date, const time_t* t)
{
ldiv_t qr;
qr = ldiv(*t, 86400);
if(*t < 0) {
--qr.quot;
qr.rem += 86400;
}
date->day = EPOCH_GDAY + qr.quot;
date->sec = qr.rem;
date->nsec = 0;
@ -123,7 +143,8 @@ void iso8601_from_time_t(struct iso8601_date* date, const time_t* t)
void iso8601_to_time_t(time_t* t, const struct iso8601_date* date)
void
iso8601_to_time_t(time_t* t, const struct iso8601_date* date)
{
*t = 86400L * (date->day - EPOCH_GDAY) + date->sec;
}

View File

@ -1,7 +1,7 @@
/* libiso8601/src/libiso8601/400_c_library.h
*
* (c)2006, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv2. See file COPYING or
* (c)2006-2010, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv3. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details.
*/
@ -9,7 +9,8 @@
/*! \defgroup c_library C library integration.
These functions enable integration with the C library (system call wrappers and conversion).
These functions enable integration with the C library (system call wrappers and
conversion).
*/
/*!@{*/
@ -18,11 +19,11 @@ These functions enable integration with the C library (system call wrappers and
/*! \brief Retrieve the current time.
\param[out] date Current date/time (may be 0), in UTC.
\param[out] details Details (may be 0), including timezone.
\param[out] date Current date/time (may be 0), in UTC. May be 0.
\param[out] details Details (may be 0), including timezone. May be 0.
Retrieves the current time from the system clock, storing it into \a date and \a details (both
parameters optional).
Retrieves the current time from the system clock, storing it into \a date and
\a details (both parameters optional).
*/
void iso8601_now(struct iso8601_date* date, struct iso8601_details* details);
@ -35,32 +36,65 @@ void iso8601_now(struct iso8601_date* date, struct iso8601_details* details);
\retval 0 on success.
\retval -1 on error (and see \a errno).
Attempts to set the system clock using \c clock_settime(), falling back to \c settimeofday(). The
user will need the \c CAP_SYS_TIME capability to set the clock, otherwise \a errno will be set to
\c EPERM.
Attempts to set the system clock using \c clock_settime(), falling back to \c
settimeofday(). The user will need the \c CAP_SYS_TIME capability to set the
clock, otherwise \a errno will be set to \c EPERM.
*/
int iso8601_set_sysclock(const struct iso8601_date* date);
int iso8601_set_sysclock(const struct iso8601_date* date)
#ifndef DOXYGEN
__attribute__((nonnull))
#endif
;
/*! \brief Convert from a struct timespec. */
void iso8601_from_ts(struct iso8601_date* date, const struct timespec* ts);
void iso8601_from_ts(struct iso8601_date* date, const struct timespec* ts)
#ifndef DOXYGEN
__attribute__((nonnull))
#endif
;
/*! \brief Convert to a struct timespec. */
void iso8601_to_ts(struct timespec* ts, const struct iso8601_date* date);
void iso8601_to_ts(struct timespec* ts, const struct iso8601_date* date)
#ifndef DOXYGEN
__attribute__((nonnull))
#endif
;
/*! \brief Convert from a struct timeval. */
void iso8601_from_tv(struct iso8601_date* date, const struct timeval* tv);
void iso8601_from_tv(struct iso8601_date* date, const struct timeval* tv)
#ifndef DOXYGEN
__attribute__((nonnull))
#endif
;
/*! \brief Convert to a struct timeval. */
void iso8601_to_tv(struct timeval* tv, const struct iso8601_date* date);
void iso8601_to_tv(struct timeval* tv, const struct iso8601_date* date)
#ifndef DOXYGEN
__attribute__((nonnull))
#endif
;
/*! \brief Convert from a time_t. */
void iso8601_from_time_t(struct iso8601_date* date, const time_t* t);
void iso8601_from_time_t(struct iso8601_date* date, const time_t* t)
#ifndef DOXYGEN
__attribute__((nonnull))
#endif
;
/*! \brief Convert to a time_t. */
void iso8601_to_time_t(time_t* t, const struct iso8601_date* date);
void iso8601_to_time_t(time_t* t, const struct iso8601_date* date)
#ifndef DOXYGEN
__attribute__((nonnull))
#endif
;
/*!@}*/
/* options for text editors
kate: replace-trailing-space-save true; space-indent true; tab-width 4;
vim: expandtab:ts=4:sw=4
vim: expandtab:ts=4:sw=4:syntax=ch.doxygen
*/

View File

@ -1,7 +1,7 @@
/* libiso8601/src/libiso8601/400_calc.h
*
* (c)2006, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv2. See file COPYING or
* (c)2006-2010, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv3. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details.
*/
@ -9,8 +9,8 @@
/*! \defgroup calc Conversion and calculation routines.
This set of functions is useful for converting dates and times into formats understood by humans,
and vice versa.
This set of functions is useful for converting dates and times into formats
understood by humans, and vice versa.
*/
/*!@{*/
@ -38,7 +38,12 @@ int iso8601_isleap(int year);
\param date Date to convert.
*/
void iso8601_to_cal(int* year, int* month, int* day, const struct iso8601_date* date);
void iso8601_to_cal(int* year, int* month, int* day,
const struct iso8601_date* date)
#ifndef DOXYGEN
__attribute__((nonnull))
#endif
;
@ -51,11 +56,18 @@ void iso8601_to_cal(int* year, int* month, int* day, const struct iso8601_date*
\retval 0 on success.
\retval -1 on error (and see \a errno).
Converts the date specified in \a year, \a month and \a day into \a date. Does not touch the \a sec
or \a nsec time members of \a date.
Converts the date specified in \a year, \a month and \a day into \a date.
\note Does not touch the \a sec or \a nsec time members of \a date. This means
they will be unchanged after a call to this function. If this will lead to
unexpected results, initialise the structure to 0 first.
*/
int iso8601_from_cal(struct iso8601_date* date, int year, int month, int day);
int iso8601_from_cal(struct iso8601_date* date, int year, int month, int day)
#ifndef DOXYGEN
__attribute__((nonnull))
#endif
;
@ -66,7 +78,11 @@ int iso8601_from_cal(struct iso8601_date* date, int year, int month, int day);
\param date Date to convert.
*/
void iso8601_to_ord(int* year, int* oday, const struct iso8601_date* date);
void iso8601_to_ord(int* year, int* oday, const struct iso8601_date* date)
#ifndef DOXYGEN
__attribute__((nonnull))
#endif
;
@ -78,11 +94,18 @@ void iso8601_to_ord(int* year, int* oday, const struct iso8601_date* date);
\retval 0 on success.
\retval -1 on error (and see \a errno).
Converts the date specified into \a year and \a oday into \a date. Does not touch the \a sec or
\a nsec time members of \a date.
Converts the date specified into \a year and \a oday into \a date.
\note Does not touch the \a sec or \a nsec time members of \a date. This means
they will be unchanged after a call to this functoin. If this will lead to
unexpected results, initialise the structure to 0 first.
*/
int iso8601_from_ord(struct iso8601_date* date, int year, int oday);
int iso8601_from_ord(struct iso8601_date* date, int year, int oday)
#ifndef DOXYGEN
__attribute__((nonnull))
#endif
;
@ -94,7 +117,12 @@ int iso8601_from_ord(struct iso8601_date* date, int year, int oday);
\param date Date to convert.
*/
void iso8601_to_week(int* year, int* week, int* wday, const struct iso8601_date* date);
void iso8601_to_week(int* year, int* week, int* wday,
const struct iso8601_date* date)
#ifndef DOXYGEN
__attribute__((nonnull))
#endif
;
@ -107,8 +135,18 @@ void iso8601_to_week(int* year, int* week, int* wday, const struct iso8601_date*
\retval 0 on success.
\retval -1 on error (and see \a errno).
Converts the date specified into \a year, \a week and \a wday into \a date.
\note Does not touch the \a sec or \a nsec time members of \a date. This means
they will be unchanged after a call to this functoin. If this will lead to
unexpected results, initialise the structure to 0 first.
*/
int iso8601_from_week(struct iso8601_date* date, int year, int week, int wday);
int iso8601_from_week(struct iso8601_date* date, int year, int week, int wday)
#ifndef DOXYGEN
__attribute__((nonnull))
#endif
;
@ -119,11 +157,16 @@ int iso8601_from_week(struct iso8601_date* date, int year, int week, int wday);
\param[out] sec Output second.
\param date Date/time to convert.
Converts the time stored in \a date into wall clock format, storing the result in \a hour, \a min
and \a sec.
Converts the time stored in \a date into wall clock format, storing the result
in \a hour, \a min and \a sec.
*/
void iso8601_to_clocktime(int* hour, int* min, int* sec, const struct iso8601_date* date);
void iso8601_to_clocktime(int* hour, int* min, int* sec,
const struct iso8601_date* date)
#ifndef DOXYGEN
__attribute__((nonnull))
#endif
;
@ -136,16 +179,25 @@ void iso8601_to_clocktime(int* hour, int* min, int* sec, const struct iso8601_da
\retval 0 on success.
\retval -1 on error (and see \a errno).
Converts the time as specified by \a hour, \a min and \a sec, storing the result in \a date. Does
not touch the \a day (date) member of \a date.
Converts the time as specified by \a hour, \a min and \a sec, storing the
result in \a date.
\note Does not touch the \a day (date) member of \a date. This means it will be
unchanged after a call to this function. If this will lead to unexpected
results, initialise the structure to 0 first.
*/
int iso8601_from_clocktime(struct iso8601_date* date, int hour, int min, int sec);
int iso8601_from_clocktime(struct iso8601_date* date, int hour, int min,
int sec)
#ifndef DOXYGEN
__attribute__((nonnull))
#endif
;
/*!@}*/
/* options for text editors
kate: replace-trailing-space-save true; space-indent true; tab-width 4;
vim: expandtab:ts=4:sw=4
vim: expandtab:ts=4:sw=4:syntax=ch.doxygen
*/

View File

@ -1,7 +1,7 @@
/* libiso8601/src/libiso8601/400_leap.h
*
* (c)2006, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv2. See file COPYING or
* (c)2006-2010, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv3. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details.
*/
@ -9,20 +9,23 @@
/*! \defgroup leap Leap second support.
A set of functions for explicitly dealing with leap seconds. All library functions are implicitly
leap second aware, but there are occasions when leap seconds must be dealt with explicitly. These
functions permit this.
A set of functions for explicitly dealing with leap seconds. All library
functions are implicitly leap second aware, but there are occasions when leap
seconds must be dealt with explicitly. These functions permit this.
Internally, leap seconds are represented as a table of day numbers; each day number present in the
table means that the corresponding day has 86401 seconds (a leap second).
Internally, leap seconds are represented as a table of day numbers; each day
number present in the table means that the corresponding day has 86401 seconds
(a leap second).
\note The library does not (yet) have support for negative leap seconds. This support will be added
should a day with a negative leap second ever come. This will need to addressed in the API as
the current API does not support loading a table of negative leap seconds.
\note The library does not (yet) have support for negative leap seconds. This
support will be added should a day with a negative leap second ever come.
This will need to addressed in the API as the current API does not support
loading a table of negative leap seconds.
It is possible to create a disk file containing an updated table and to load that file using
\ref iso8601_leap_table_load (or to explicitly use an existing in-memory table with
\ref iso8601_leap_table_set). The format of the on-disk file is:
It is possible to create a disk file containing an updated table and to load
that file using \ref iso8601_leap_table_load (or to explicitly use an existing
in-memory table with \ref iso8601_leap_table_set). The format of the on-disk
file is:
<pre># integers are stored big-endian
[8*char] signature, "/O9PdPZI"
@ -43,14 +46,19 @@ It is possible to create a disk file containing an updated table and to load tha
\retval 86400 day with no leap second.
\retval 86401 day with one leap second.
Returns the duration of a day \a date, in seconds. This function takes leap seconds into account and
may be used to determine if a day contains a leap second or not.
Returns the duration of a day \a date, in seconds. This function takes leap
seconds into account and may be used to determine if a day contains a leap
second or not.
\note There have not yet been any days requiring a negative leap second, so at present 86399 will
never be returned.
\note There have not yet been any days requiring a negative leap second, so at
present 86399 will never be returned.
*/
int iso8601_seconds_leap(const struct iso8601_date* date);
int iso8601_seconds_leap(const struct iso8601_date* date)
#ifndef DOXYGEN
__attribute__((nonnull))
#endif
;
@ -60,13 +68,19 @@ int iso8601_seconds_leap(const struct iso8601_date* date);
\param end The end date.
\returns Number of leap seconds elapsed.
Computes the number of leap seconds that have elapsed between two days. Note that this is the sum of
such leap seconds, so it will be 0 if (for example) there is one positive leap second and one
negative leap second. The ordering of the dates is important; if \a start is after \a end, then the
value returned will be negative (for positive leap seconds).
Computes the number of leap seconds that have elapsed between two days. Note
that this is the sum of such leap seconds, so it will be 0 if (for example)
there is one positive leap second and one negative leap second. The ordering of
the dates is important; if \a start is after \a end, then the value returned
will be negative (for positive leap seconds).
*/
int iso8601_leap_elapsed(const struct iso8601_date* start, const struct iso8601_date* end);
int iso8601_leap_elapsed(const struct iso8601_date* start,
const struct iso8601_date* end)
#ifndef DOXYGEN
__attribute__((nonnull))
#endif
;
@ -75,33 +89,42 @@ int iso8601_leap_elapsed(const struct iso8601_date* start, const struct iso8601_
\param new_table Array of day numbers on which leap seconds occur.
\param new_size Number of entries in array.
This function can be used to update the table of leap seconds at runtime. The \a new_table argument
points to an array of integers, each entry being the day number containing a leap second. The array
must be sorted so that lower day numbers appear towards the start of the array. \a new_size gives
the number of entries in the array. \a new_table must persist in memory as long as library functions
are in use.
This function can be used to update the table of leap seconds at runtime. The
\a new_table argument points to an array of integers, each entry being the day
number containing a leap second. The array must be sorted so that lower day
numbers appear towards the start of the array. \a new_size gives the number of
entries in the array. \a new_table must persist in memory as long as library
functions are in use.
\warning If negative leap seconds are ever used, this function will not support them. There may need
to be an ABI change in future to solve this problem.
\warning If negative leap seconds are ever used, this function will not support
them. There may need to be an ABI change in future to solve this problem.
*/
void iso8601_leap_table_set(int* new_table, int new_size) __attribute__((nonnull));
void iso8601_leap_table_set(int* new_table, int new_size)
#ifndef DOXYGEN
__attribute__((nonnull))
#endif
;
/*! \brief Load new table of leap seconds from disk.
\param fname Filename.
\param fname Filename. May be 0 for system default.
\retval 0 on success.
\retval -1 on error (and see \a errno).
This function attempts to load a new table of leap seconds from disk, using the filename \a fname.
If the table is loaded successfully, it will be set with \ref iso8601_leap_table_set(). On any
error, -1 will be returned, and \a errno will be set appropriately. If \a errno is \c EINVAL, then
the file does not contain a valid leap second table.
This function attempts to load a new table of leap seconds from disk, using the
filename \a fname. If \a fname is not specified, the system default (set at
compile time) will be used.
If the table is loaded successfully, it will be set with \ref
iso8601_leap_table_set(). On any error, -1 will be returned, and \a errno will
be set appropriately. If \a errno is \c EINVAL, then the file does not contain
a valid leap second table.
*/
int iso8601_leap_table_load(const char* fname) __attribute__((nonnull));
int iso8601_leap_table_load(const char* fname);

View File

@ -1,13 +1,14 @@
/* libiso8601/src/libiso8601/400_manip.c
*
* (c)2006, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv2. See file COPYING or
* (c)2006-2010, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv3. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details.
*/
int iso8601_lt(const struct iso8601_date* d1, const struct iso8601_date* d2)
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;
@ -19,7 +20,8 @@ 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)
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;
@ -31,26 +33,44 @@ int iso8601_lte(const struct iso8601_date* d1, const struct iso8601_date* d2)
int iso8601_eq(const struct iso8601_date* d1, const struct iso8601_date* d2)
int
iso8601_eq(const struct iso8601_date* d1, const struct iso8601_date* d2)
{
return (d1->day == d2->day) && (d1->sec == d2->sec) && (d1->nsec == d2->nsec);
return (d1->day == d2->day) && (d1->sec == d2->sec)
&& (d1->nsec == d2->nsec);
}
void iso8601_add_elapsed(struct iso8601_date* date, const struct iso8601_elapsed* per)
int
iso8601_cmp(const struct iso8601_date* d1, const struct iso8601_date* d2)
{
if(d1->day < d2->day) return -1;
if(d1->day > d2->day) return 1;
if(d1->sec < d2->sec) return -1;
if(d1->sec > d2->sec) return 1;
if(d1->nsec < d2->nsec) return -1;
if(d1->nsec > d2->nsec) return 1;
return 0;
}
void
iso8601_add_elapsed(struct iso8601_date* date,
const struct iso8601_elapsed* per)
{
div_t qr;
int leapcorrect;
/* work out number to advance `day' by */
/* 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;
date->nsec += per->nsec;
if(date->nsec > BILLION) {
if(date->nsec >= BILLION) {
++date->sec;
date->nsec -= BILLION;
}
@ -68,12 +88,14 @@ void iso8601_add_elapsed(struct iso8601_date* date, const struct iso8601_elapsed
void iso8601_subtract_elapsed(struct iso8601_date* date, const struct iso8601_elapsed* per)
void
iso8601_subtract_elapsed(struct iso8601_date* date,
const struct iso8601_elapsed* per)
{
div_t qr;
int leapcorrect;
/* work out number to advance `day' by */
/* 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;
@ -98,7 +120,9 @@ void iso8601_subtract_elapsed(struct iso8601_date* date, const struct iso8601_el
void iso8601_add_multiple(struct iso8601_date* date, const struct iso8601_elapsed* per, int n)
void
iso8601_add_multiple(struct iso8601_date* date,
const struct iso8601_elapsed* per, int n)
{
long long nsec;
lldiv_t qr;
@ -115,7 +139,8 @@ void iso8601_add_multiple(struct iso8601_date* date, const struct iso8601_elapse
void iso8601_difference(const struct iso8601_date* d1, const struct iso8601_date* d2,
void
iso8601_difference(const struct iso8601_date* d1, const struct iso8601_date* d2,
struct iso8601_elapsed* per, int* sign)
{
const struct iso8601_date* e1, * e2;
@ -147,6 +172,32 @@ void iso8601_difference(const struct iso8601_date* d1, const struct iso8601_date
int
iso8601_elapsed_div(const struct iso8601_elapsed* num,
const struct iso8601_elapsed* denom, struct iso8601_elapsed* remain)
{
unsigned long long pnum, pdenom;
lldiv_t val, v2;
pnum = num->sec;
pnum *= BILLION;
pnum += num->nsec;
pdenom = denom->sec;
pdenom *= BILLION;
pdenom += denom->nsec;
val = lldiv(pnum, pdenom);
if(remain) {
v2 = lldiv(val.rem, BILLION);
remain->sec = v2.quot;
remain->nsec = v2.rem;
}
return val.quot;
}
/* options for text editors
kate: replace-trailing-space-save true; space-indent true; tab-width 4;
vim: expandtab:ts=4:sw=4

View File

@ -1,7 +1,7 @@
/* libiso8601/src/libiso8601/400_manip.h
*
* (c)2006, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv2. See file COPYING or
* (c)2006-2010, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv3. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details.
*/
@ -9,8 +9,8 @@
/*! \defgroup manip Manipulation routines.
This set of functions is useful for performing arithmetic etc. on dates. It uses
struct iso8601_elapsed to represent the magnitude of time differences.
This set of functions is useful for performing arithmetic etc. on dates. It
uses struct \ref iso8601_elapsed to represent the magnitude of time differences.
*/
/*!@{*/
@ -25,7 +25,11 @@ struct iso8601_elapsed to represent the magnitude of time differences.
\retval 0 otherwise
*/
int iso8601_lt(const struct iso8601_date* d1, const struct iso8601_date* d2);
int iso8601_lt(const struct iso8601_date* d1, const struct iso8601_date* d2)
#ifndef DOXYGEN
__attribute__((nonnull))
#endif
;
@ -37,7 +41,11 @@ int iso8601_lt(const struct iso8601_date* d1, const struct iso8601_date* d2);
\retval 0 otherwise
*/
int iso8601_lte(const struct iso8601_date* d1, const struct iso8601_date* d2);
int iso8601_lte(const struct iso8601_date* d1, const struct iso8601_date* d2)
#ifndef DOXYGEN
__attribute__((nonnull))
#endif
;
@ -49,7 +57,28 @@ int iso8601_lte(const struct iso8601_date* d1, const struct iso8601_date* d2);
\retval 0 otherwise
*/
int iso8601_eq(const struct iso8601_date* d1, const struct iso8601_date* d2);
int iso8601_eq(const struct iso8601_date* d1, const struct iso8601_date* d2)
#ifndef DOXYGEN
__attribute__((nonnull))
#endif
;
/*! \brief Comparison (for qsort et al.).
\param d1 First date to compare.
\param d2 Second date to compare.
\retval -1 if \a d1 &lt; \a d2
\retval 0 if \a d1 == \a d2
\retval 1 if \a d1 &gt; \a d2
*/
int iso8601_cmp(const struct iso8601_date* d1, const struct iso8601_date* d2)
#ifndef DOXYGEN
__attribute__((nonnull))
#endif
;
@ -59,7 +88,12 @@ int iso8601_eq(const struct iso8601_date* d1, const struct iso8601_date* d2);
\param per Period to advance date/time by.
*/
void iso8601_add_elapsed(struct iso8601_date* date, const struct iso8601_elapsed* per);
void iso8601_add_elapsed(struct iso8601_date* date,
const struct iso8601_elapsed* per)
#ifndef DOXYGEN
__attribute__((nonnull))
#endif
;
@ -69,7 +103,12 @@ void iso8601_add_elapsed(struct iso8601_date* date, const struct iso8601_elapsed
\param per Period to regress date/time by.
*/
void iso8601_subtract_elapsed(struct iso8601_date* date, const struct iso8601_elapsed* per);
void iso8601_subtract_elapsed(struct iso8601_date* date,
const struct iso8601_elapsed* per)
#ifndef DOXYGEN
__attribute__((nonnull))
#endif
;
@ -79,11 +118,17 @@ void iso8601_subtract_elapsed(struct iso8601_date* date, const struct iso8601_el
\param per Period to advance date/time by.
\param n Multiple of \a per.
Adds \a n multiples of \a per to \a date. \a n may be 0 or negative. The result is stored in
\a date. This is an efficient implementation which avoids loops, but it does use 64-bit arithmetic.
Adds \a n multiples of \a per to \a date. \a n may be 0 or negative. The result
is stored in \a date. This is an efficient implementation which avoids loops,
but it does use 64-bit arithmetic.
*/
void iso8601_add_multiple(struct iso8601_date* date, const struct iso8601_elapsed* per, int n);
void iso8601_add_multiple(struct iso8601_date* date,
const struct iso8601_elapsed* per, int n)
#ifndef DOXYGEN
__attribute__((nonnull))
#endif
;
@ -94,13 +139,39 @@ void iso8601_add_multiple(struct iso8601_date* date, const struct iso8601_elapse
\param[out] per Magnitude of period elapsed between two dates. Pointer may be 0.
\param[out] sign Set to sign of difference (-1 or +1). Pointer may be 0.
This function will perform the calculation <code>|d1 - d2|</code>, storing the result in \a per (if
it is not a null pointer). The sign of the result is stored in \a sign (if it is not a null
pointer), i.e. -1 if \a d2 &gt; \a d1 or +1 if \a d2 &lt;= \a d1.
This function will perform the calculation <code>|d1 - d2|</code>, storing the
result in \a per (if it is not a null pointer). The sign of the result is
stored in \a sign (if it is not a null pointer), i.e. -1 if \a d2 &gt; \a d1 or
+1 if \a d2 &lt;= \a d1.
*/
void iso8601_difference(const struct iso8601_date* d1, const struct iso8601_date* d2,
struct iso8601_elapsed* per, int* sign);
void iso8601_difference(const struct iso8601_date* d1,
const struct iso8601_date* d2, struct iso8601_elapsed* per, int* sign)
#ifndef DOXYGEN
__attribute__((nonnull(1,2)))
#endif
;
/*! \brief Divide one period by another.
\param num Numerator.
\param denom Denominator (divisor).
\param[out] remain Remainder. May be 0.
\returns Number of times \a denom divides into \a num.
This function computes the number of times that \a denom can be divided into \a
num, returning that number. If desired, the remaining period which could not be
divided can be written into \a remain. Uses 64-bit arithmetic internally.
*/
int iso8601_elapsed_div(const struct iso8601_elapsed* num,
const struct iso8601_elapsed* denom, struct iso8601_elapsed* remain)
#ifndef DOXYGEN
__attribute__((nonnull(1,2)));
#endif
;

View File

@ -1,10 +1,14 @@
/* libiso8601/src/libiso8601/999_BottomHeader.h
*
* (c)2006, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv2. See file COPYING or
* (c)2006-2010, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv3. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details.
*/
#ifdef __cplusplus
}
#endif
#endif
/* options for text editors

View File

@ -7,6 +7,7 @@ build_dir_tree "${INCLUDEDIR}" || return 1
# install library
echo "Installing libraries into '${LIBDIR}'"
source src/libiso8601/soversion
install_file ${libiso8601} ${LIBDIR} 0755 || return 1
BASE="${libiso8601_BASE}.so"
MAJOR="${BASE}.${SOMAJOR}"
@ -33,5 +34,4 @@ do_cmd_redir "${CONFFILE}" sed \
do_cmd chmod 0755 "${CONFFILE}"
print_success "Done"
# kate: replace-trailing-space-save true; space-indent true; tab-width 4;
# vim: syntax=sh:expandtab:ts=4:sw=4

View File

@ -14,7 +14,9 @@ then
libiso8601="obj/${libiso8601_BASE}.so.${SOMAJOR}.${SOMICRO}"
libiso8601_DEP_CFLAGS=""
libiso8601_DEP_LIBS="-lrt"
SO_EXTRA="-std=gnu99 -D_GNU_SOURCE ${libiso8601_DEP_CFLAGS} ${libiso8601_DEP_LIBS} -lc"
SO_EXTRA="${libiso8601_DEP_CFLAGS} ${libiso8601_DEP_LIBS} -lc \
-D_GNU_SOURCE -std=gnu99 \
-DDEFAULT_LEAP_TABLE=\"${DEFAULT_LEAP_TABLE}\""
echo "Building library ${libiso8601}..."
@ -52,5 +54,4 @@ then
libiso8601_HEADER=${HDR}
fi
# kate: replace-trailing-space-save true; space-indent true; tab-width 4;
# vim: syntax=sh:expandtab:ts=4:sw=4

View File

@ -17,5 +17,4 @@ then
libiso8601_MONOLITHIC=1
MONOLITHIC_DOC="${MONOLITHIC_DOC} ${HDR}"
fi
# kate: replace-trailing-space-save true; space-indent true; tab-width 4;
# vim: syntax=sh:expandtab:ts=4:sw=4

View File

@ -95,4 +95,3 @@ true
# vim: syntax=sh:expandtab:ts=4:sw=4
# kate: replace-trailing-space-save true; space-indent true; tab-width 4;

View File

@ -1,8 +1,8 @@
# libiso8601/src/libiso8601/soversion
#
# (c)2007, Laurence Withers, <l@lwithers.me.uk>.
# Released under the GNU GPLv3. See file COPYING or
# http://www.gnu.org/copyleft/gpl.html for details.
# Copyright: ©20072011, Güralp Systems Ltd.
# Author: Laurence Withers <lwithers@guralp.com>
# License: GPLv3
#
@ -12,4 +12,4 @@
SOMAJOR=1
# SOMICRO is bumped every time there is a binary-compatible release.
SOMICRO=2
SOMICRO=10

View File

@ -8,7 +8,8 @@ build_target libiso8601
if [ -z ${setisodate_BUILT} ]
then
setisodate="obj/setisodate"
EXTRAS="${libiso8601} ${libiso8601_DEP_CFLAGS} ${libiso8601_DEP_LIBS}"
EXTRAS="-std=gnu99 -D_GNU_SOURCE -DAPP_NAME=\"setisodate\" \
${libiso8601} ${libiso8601_DEP_CFLAGS} ${libiso8601_DEP_LIBS}"
echo "Building application ${setisodate}..."
@ -39,5 +40,4 @@ then
fi
# kate: replace-trailing-space-save true; space-indent true; tab-width 4;
# vim: syntax=sh:expandtab:ts=4:sw=4

View File

@ -8,5 +8,4 @@ echo "Installing binaries into '${SBINDIR}'"
install_file "${setisodate}" "${SBINDIR}" 0755 || return 1
print_success "Done"
# kate: replace-trailing-space-save true; space-indent true; tab-width 4;
# vim: syntax=sh:expandtab:ts=4:sw=4

View File

@ -14,5 +14,4 @@ then
MONOLITHIC_DOC="${MONOLITHIC_DOC} ${SRC}"
fi
# kate: replace-trailing-space-save true; space-indent true; tab-width 4;
# vim: syntax=sh:expandtab:ts=4:sw=4

View File

@ -1,3 +1 @@
source src/tests/build.tests
# kate: replace-trailing-space-save true; space-indent true; tab-width 4;
# vim: syntax=sh:expandtab:ts=4:sw=4

View File

@ -7,14 +7,14 @@ build_target libiso8601 || return 1
if [ -z ${tests_BUILT} ]
then
LIBS="${libiso8601} ${libiso8601_DEP_CFLAGS} ${libiso8601_DEP_LIBS} "
EXTRAS="-D_GNU_SOURCE"
EXTRAS="-lm"
echo "Building test programs..."
do_cmd mkdir -p obj/tests || return 1
for SRC in src/tests/*.c
do
TEST="obj/tests/$(basename ${SRC} | sed -e 's,.c$,,')"
TEST="obj/tests/$(basename "${SRC}" ".c")"
MODIFIED=0
for file in ${LIBS} ${SRC} src/tests/build.tests
do
@ -25,14 +25,9 @@ then
fi
done
case "${TEST}" in
obj/tests/manip) TEST_EXTRAS="-lm" ;;
*) TEST_EXTRAS="" ;;
esac
if [ ${MODIFIED} -ne 0 ]
then
do_cmd ${CC} -Iobj ${CFLAGS} -o ${TEST} ${SRC} ${LIBS} ${EXTRAS} ${TEST_EXTRAS} || return 1
do_cmd ${CC} -Iobj ${CFLAGS} -o ${TEST} ${SRC} ${LIBS} ${EXTRAS} || return 1
print_success "Built ${TEST}"
else
print_success "${TEST} is up to date"
@ -44,5 +39,4 @@ then
tests_BUILT=1
fi
# kate: replace-trailing-space-save true; space-indent true; tab-width 4;
# vim: syntax=sh:expandtab:ts=4:sw=4

View File

@ -1,8 +1,8 @@
/* libiso8601/src/tests/???.c
/* libiso8601/src/tests/xxx.c
*
* (c)2007, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv3. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details.
* Copyright: ©20072011, Güralp Systems Ltd.
* Author: Laurence Withers <lwithers@guralp.com>
* License: GPLv3
*/
#include "iso8601.h"
@ -12,7 +12,8 @@
int main(int argc, char* argv[])
int
main(int argc, char* argv[])
{
int ret = 0;
@ -30,7 +31,8 @@ int main(int argc, char* argv[])
return ret;
}
/* options for text editors
kate: replace-trailing-space-save true; space-indent true; tab-width 4;
vim: expandtab:ts=4:sw=4
*/

View File

@ -1,8 +1,8 @@
# libiso8601/version
#
# (c)2007, Laurence Withers, <l@lwithers.me.uk>.
# Released under the GNU GPLv3. See file COPYING or
# http://www.gnu.org/copyleft/gpl.html for details.
# Copyright: ©20072011, Güralp Systems Ltd.
# Author: Laurence Withers <lwithers@guralp.com>
# License: GPLv3
#
@ -11,7 +11,6 @@
# expected to be in 'major.minor.micro' format.
VERMAJOR=0
VERMINOR=3
VERMICRO=4
VERMICRO=15
# kate: replace-trailing-space-save true; space-indent true; tab-width 4;
# vim: expandtab:ts=4:sw=4:syntax=sh