Compare commits

..

No commits in common. "master" and "0.3.2" have entirely different histories.

44 changed files with 518 additions and 3273 deletions

1
.gitignore vendored
View File

@ -1,3 +1,2 @@
obj obj
html html
.*.swp

2
config
View File

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

11
make.sh
View File

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

View File

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

1
scripts/.gitignore vendored
View File

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

View File

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

View File

@ -1,63 +1,85 @@
# libiso8601/scripts/paths # libiso8601/scripts/paths
# #
# Copyright: ©2011, Güralp Systems Ltd. # (c)2007, Laurence Withers, <l@lwithers.me.uk>.
# Author: Laurence Withers, <lwithers@guralp.com> # Released under the GNU GPLv3. See file COPYING or
# License: GPLv3 # http://www.gnu.org/copyleft/gpl.html for details.
# #
# Default path setup. Not meant for editing; use environment variables # Default path setup. Not meant for editing; use environment variables
# to override values if needed. # to override values if needed.
# #
MY_PREFIX="${PREFIX}" # build proposed paths
[ "${MY_PREFIX}" == "/" ] && MY_PREFIX="" case "${PREFIX}" in
/)
MY_BINDIR="/bin"
MY_SBINDIR="/sbin"
MY_LIBDIR="/lib"
MY_INCLUDEDIR="/usr/include"
MY_CONFIGDIR="/etc"
MY_VARDIR="/var"
MY_SHAREDIR="/usr/share/libiso8601"
MY_DOCSDIR="/usr/share/doc/libiso8601"
MY_WEBDIR="/srv/http"
;;
[ -z "${BINDIR}" ] && BINDIR="${PREFIX}/bin" /usr)
[ -z "${SBINDIR}" ] && SBINDIR="${PREFIX}/sbin" MY_BINDIR="/usr/bin"
[ -z "${LIBDIR}" ] && LIBDIR="${PREFIX}/lib" MY_SBINDIR="/usr/sbin"
MY_LIBDIR="/usr/lib"
MY_INCLUDEDIR="/usr/include"
MY_CONFIGDIR="/etc"
MY_VARDIR="/var"
MY_SHAREDIR="/usr/share/libiso8601"
MY_DOCSDIR="/usr/share/doc/libiso8601"
MY_WEBDIR="/srv/http"
;;
if [ -z "${INCLUDEDIR}" ] /usr/local)
then MY_BINDIR="/usr/local/bin"
case "${PREFIX}" in MY_SBINDIR="/usr/local/sbin"
/) INCLUDEDIR="/usr/include" ;; MY_LIBDIR="/usr/local/lib"
*) INCLUDEDIR="${PREFIX}/include" ;; MY_INCLUDEDIR="/usr/local/include"
esac MY_CONFIGDIR="/usr/local/etc"
fi MY_VARDIR="/var"
MY_SHAREDIR="/usr/local/share/libiso8601"
MY_DOCSDIR="/usr/local/share/doc/libiso8601"
MY_WEBDIR="/srv/http"
;;
if [ -z "${CONFIGDIR}" ] /opt/*)
then MY_BINDIR="${PREFIX}/bin"
case "${PREFIX}" in MY_SBINDIR="${PREFIX}/sbin"
/ | /usr) CONFIGDIR="/etc" ;; MY_LIBDIR="${PREFIX}/lib"
/opt*) CONFIGDIR="/etc${PREFIX}" ;; MY_INCLUDEDIR="${PREFIX}/include"
*) CONFIGDIR="${PREFIX}/etc" ;; MY_CONFIGDIR="/etc${PREFIX}"
esac MY_VARDIR="/var${PREFIX}"
fi MY_SHAREDIR="/var${PREFIX}"
MY_DOCSDIR="${PREFIX}/doc"
MY_WEBDIR="${PREFIX}/http"
;;
if [ -z "${VARDIR}" ] **)
then MY_BINDIR="${PREFIX}/bin"
case "${PREFIX}" in MY_SBINDIR="${PREFIX}/sbin"
/ | /usr | /usr/local) VARDIR="/var" ;; MY_LIBDIR="${PREFIX}/lib"
/opt*) VARDIR="/var${PREFIX}" ;; MY_INCLUDEDIR="${PREFIX}/include"
*) VARDIR="${PREFIX}/var" ;; MY_CONFIGDIR="${PREFIX}/etc"
esac MY_VARDIR="${PREFIX}/var"
fi MY_DOCSDIR="${PREFIX}/share/doc"
MY_WEBDIR="${PREFIX}/srv/http"
;;
esac
if [ -z "${SHAREDIR}" ] # assign paths allowing user to override
then [ -z "${BINDIR}" ] && BINDIR="${MY_BINDIR}"
case "${PREFIX}" in [ -z "${SBINDIR}" ] && SBINDIR="${MY_SBINDIR}"
/) SHAREDIR="/usr/share" ;; [ -z "${LIBDIR}" ] && LIBDIR="${MY_LIBDIR}"
*) SHAREDIR="${PREFIX}/share" ;; [ -z "${INCLUDEDIR}" ] && INCLUDEDIR="${MY_INCLUDEDIR}"
esac [ -z "${CONFIGDIR}" ] && CONFIGDIR="${MY_CONFIGDIR}"
fi [ -z "${VARDIR}" ] && VARDIR="${MY_VARDIR}"
[ -z "${DOCSDIR}" ] && DOCSDIR="${SHAREDIR}/doc" [ -z "${DOCSDIR}" ] && DOCSDIR="${MY_DOCSDIR}"
[ -z "${WEBDIR}" ] && WEBDIR="${MY_WEBDIR}"
if [ -z "${SRVDIR}" ]
then
case "${PREFIX}" in
/ | /usr | /usr/local) SRVDIR="/srv" ;;
*) SRVDIR="${PREFIX}/srv" ;;
esac
fi
[ -z "${WEBDIR}" ] && WEBDIR="${SRVDIR}/http"
[ -z "${CGIDIR}" ] && CGIDIR="${WEBDIR}/cgi-bin" [ -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 # vim: syntax=sh:expandtab:ts=4:sw=4

File diff suppressed because it is too large Load Diff

View File

@ -1,16 +1,11 @@
/* libiso8601/src/docs/MainPage.dox /* libiso8601/src/docs/MainPage.dox
* *
* (c)2007-2010, Laurence Withers, <l@lwithers.me.uk>. * (c)2007, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv3. See file COPYING or * Released under the GNU GPLv3. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details. * http://www.gnu.org/copyleft/gpl.html for details.
*/ */
/*! \mainpage Library for manipulating ISO8601-format dates and times /*! \mainpage
\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,4 +39,5 @@ then
docs_BUILT=1 docs_BUILT=1
fi fi
# kate: replace-trailing-space-save true; space-indent true; tab-width 4;
# vim: syntax=sh:expandtab:ts=4:sw=4 # vim: syntax=sh:expandtab:ts=4:sw=4

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
/* libiso8601/src/libiso8601/000_TopSource.c /* libiso8601/src/libiso8601/000_TopSource.c
* *
* (c)2006-2010, Laurence Withers, <l@lwithers.me.uk>. * (c)2006, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv3. See file COPYING or * Released under the GNU GPLv2. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details. * http://www.gnu.org/copyleft/gpl.html for details.
*/ */
@ -10,12 +10,9 @@
/* Below are all the includes used throughout the library. */ /* Below are all the includes used throughout the library. */
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/time.h> #include <sys/time.h>
/* Useful define to alleviate typos */ /* Useful define to alleviate typos */

View File

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

View File

@ -1,92 +1,59 @@
/* libiso8601/src/libiso8601/100_leap.c /* libiso8601/src/libiso8601/100_leap.c
* *
* (c)2006-2010, Laurence Withers, <l@lwithers.me.uk>. * (c)2006, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv3. See file COPYING or * Released under the GNU GPLv2. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details. * http://www.gnu.org/copyleft/gpl.html for details.
*/ */
/* leap_second_days_table[] static int leap_second_days[] = {
* This is a sorted array of days (in libiso8601 format) on which a positive 720439, // 19720630
* leap second occurred. This table is built in to the library, but may be 720623, // 19721231
* overridden at runtime by changing what leap_second_days points to. There 720988, // 19731231
* should be no other references to this table, therefore. 721353, // 19741231
*/ 721718, // 19751231
static int 722084, // 19761231
leap_second_days_table[] = { 722449, // 19771231
720439, /* 1972-06-30 */ 722814, // 19781231
720623, /* 1972-12-31 */ 723179, // 19791231
720988, /* 1973-12-31 */ 723726, // 19810630
721353, /* 1974-12-31 */ 724091, // 19820630
721718, /* 1975-12-31 */ 724456, // 19830630
722084, /* 1976-12-31 */ 725187, // 19850630
722449, /* 1977-12-31 */ 726101, // 19871231
722814, /* 1978-12-31 */ 726832, // 19891231
723179, /* 1979-12-31 */ 727197, // 19901231
723726, /* 1981-06-30 */ 727744, // 19920630
724091, /* 1982-06-30 */ 728109, // 19930630
724456, /* 1983-06-30 */ 728474, // 19940630
725187, /* 1985-06-30 */ 729023, // 19951231
726101, /* 1987-12-31 */ 729570, // 19970630
726832, /* 1989-12-31 */ 730119, // 19981231
727197, /* 1990-12-31 */ 732676 // 20051231
727744, /* 1992-06-30 */
728109, /* 1993-06-30 */
728474, /* 1994-06-30 */
729023, /* 1995-12-31 */
729570, /* 1997-06-30 */
730119, /* 1998-12-31 */
732676, /* 2005-12-31 */
733772, /* 2008-12-31 */
735049, /* 2012-06-30 */
736144, /* 2015-06-30 */
}; };
/* leap_second_days[], leap_second_days_num int iso8601_seconds_leap(const struct iso8601_date* date)
* 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);
/* 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; int num_ly = 0, i = 0;
for(i = 0; i < leap_second_days_num; ++i) {
if(leap_second_days[i] == date->day) return 86401; num_ly = sizeof(leap_second_days) / sizeof(int);
} for(i = 0; i < num_ly; ++i) if(leap_second_days[i] == date->day) return 86401;
return 86400; return 86400;
} }
/* _leap_elapsed_day() static int _leap_elapsed_day(int sday, int eday)
* 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; int spos, epos;
for(spos = 0; spos < leap_second_days_num; ++spos) { for(spos = 0; (unsigned)spos < sizeof(leap_second_days) / sizeof(int); ++spos) {
if(sday <= leap_second_days[spos]) break; if(sday <= leap_second_days[spos]) break;
} }
for(epos = 0; epos < leap_second_days_num; ++epos) { for(epos = 0; (unsigned)epos < sizeof(leap_second_days) / sizeof(int); ++epos) {
if(eday <= leap_second_days[epos]) break; if(eday <= leap_second_days[epos]) break;
} }
@ -95,121 +62,13 @@ _leap_elapsed_day(int sday, int eday)
/* iso8601_leap_elapsed() int iso8601_leap_elapsed(const struct iso8601_date* start, const struct iso8601_date* end)
* 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); 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;
/* 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;
leap_second_days = new_table;
leap_second_days_num = new_size;
}
/* 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";
/* 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;
return -1;
}
fd = open(fname, O_RDONLY);
if(fd == -1) return -1;
if(TEMP_FAILURE_RETRY( read(fd, buf, 12) ) != 12) goto outerr;
if(memcmp(buf, leap_table_signature, 8)) {
errno = EINVAL;
return -1;
}
#define GET_UINT32(_from) ( \
( ((uint8_t*)_from)[0] << 24 ) | \
( ((uint8_t*)_from)[1] << 16 ) | \
( ((uint8_t*)_from)[2] << 8 ) | \
( ((uint8_t*)_from)[3] ) \
)
new_size = GET_UINT32(buf + 8);
if((12 + new_size * 4) != st.st_size) {
errno = EINVAL;
goto outerr;
}
days = malloc(sizeof(int) * new_size);
if(!days) goto outerr;
for(i = 0; i < new_size; ++i) {
if(TEMP_FAILURE_RETRY( read(fd, buf, 4) ) != 4) goto outerr;
days[i] = GET_UINT32(buf);
if(i && days[i] <= days[i - 1]) {
errno = EINVAL;
goto outerr;
}
}
TEMP_FAILURE_RETRY( close(fd) );
iso8601_leap_table_set(days, new_size);
leap_table_free_old = 1;
return 0;
#undef GET_UINT32
outerr:
saved_errno = errno;
free(days);
TEMP_FAILURE_RETRY( close(fd) );
errno = saved_errno;
return -1;
}
/* 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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
/* libiso8601/src/libiso8601/400_c_library.h /* libiso8601/src/libiso8601/400_c_library.h
* *
* (c)2006-2010, Laurence Withers, <l@lwithers.me.uk>. * (c)2006, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv3. See file COPYING or * Released under the GNU GPLv2. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details. * http://www.gnu.org/copyleft/gpl.html for details.
*/ */
@ -9,8 +9,7 @@
/*! \defgroup c_library C library integration. /*! \defgroup c_library C library integration.
These functions enable integration with the C library (system call wrappers and These functions enable integration with the C library (system call wrappers and conversion).
conversion).
*/ */
/*!@{*/ /*!@{*/
@ -19,11 +18,11 @@ conversion).
/*! \brief Retrieve the current time. /*! \brief Retrieve the current time.
\param[out] date Current date/time (may be 0), in UTC. May be 0. \param[out] date Current date/time (may be 0), in UTC.
\param[out] details Details (may be 0), including timezone. May be 0. \param[out] details Details (may be 0), including timezone.
Retrieves the current time from the system clock, storing it into \a date and Retrieves the current time from the system clock, storing it into \a date and \a details (both
\a details (both parameters optional). parameters optional).
*/ */
void iso8601_now(struct iso8601_date* date, struct iso8601_details* details); void iso8601_now(struct iso8601_date* date, struct iso8601_details* details);
@ -36,65 +35,32 @@ void iso8601_now(struct iso8601_date* date, struct iso8601_details* details);
\retval 0 on success. \retval 0 on success.
\retval -1 on error (and see \a errno). \retval -1 on error (and see \a errno).
Attempts to set the system clock using \c clock_settime(), falling back to \c Attempts to set the system clock using \c clock_settime(), falling back to \c settimeofday(). The
settimeofday(). The user will need the \c CAP_SYS_TIME capability to set the user will need the \c CAP_SYS_TIME capability to set the clock, otherwise \a errno will be set to
clock, otherwise \a errno will be set to \c EPERM. \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. */ /*! \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. */ /*! \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. */ /*! \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. */ /*! \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. */ /*! \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. */ /*! \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 /* 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:syntax=ch.doxygen vim: expandtab:ts=4:sw=4
*/ */

View File

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

View File

@ -1,7 +1,7 @@
/* libiso8601/src/libiso8601/400_leap.h /* libiso8601/src/libiso8601/400_leap.h
* *
* (c)2006-2010, Laurence Withers, <l@lwithers.me.uk>. * (c)2006, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv3. See file COPYING or * Released under the GNU GPLv2. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details. * http://www.gnu.org/copyleft/gpl.html for details.
*/ */
@ -9,30 +9,7 @@
/*! \defgroup leap Leap second support. /*! \defgroup leap Leap second support.
A set of functions for explicitly dealing with leap seconds. All library A set of functions for explicitly dealing with leap seconds.
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).
\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:
<pre># integers are stored big-endian
[8*char] signature, "/O9PdPZI"
[uint32] number of entries, 'n'
# entries are repeated 'n' times, and stored lowest day number first
[uint32] day number of entry</pre>
*/ */
/*!@{*/ /*!@{*/
@ -46,19 +23,14 @@ file is:
\retval 86400 day with no leap second. \retval 86400 day with no leap second.
\retval 86401 day with one leap second. \retval 86401 day with one leap second.
Returns the duration of a day \a date, in seconds. This function takes leap Returns the duration of a day \a date, in seconds. This function takes leap seconds into account and
seconds into account and may be used to determine if a day contains a leap may be used to determine if a day contains a leap second or not.
second or not.
\note There have not yet been any days requiring a negative leap second, so at \note There have not yet been any days requiring a negative leap second, so at present 86399 will
present 86399 will never be returned. 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
;
@ -68,68 +40,18 @@ int iso8601_seconds_leap(const struct iso8601_date* date)
\param end The end date. \param end The end date.
\returns Number of leap seconds elapsed. \returns Number of leap seconds elapsed.
Computes the number of leap seconds that have elapsed between two days. Note Computes the number of leap seconds that have elapsed between two days. Note that this is the sum of
that this is the sum of such leap seconds, so it will be 0 if (for example) such leap seconds, so it will be 0 if (for example) there is one positive leap second and one
there is one positive leap second and one negative leap second. The ordering of negative leap second. The ordering of the dates is important; if \a start is after \a end, then the
the dates is important; if \a start is after \a end, then the value returned value returned will be negative (for positive leap seconds).
will be negative (for positive leap seconds).
*/ */
int iso8601_leap_elapsed(const struct iso8601_date* start, int iso8601_leap_elapsed(const struct iso8601_date* start, const struct iso8601_date* end);
const struct iso8601_date* end)
#ifndef DOXYGEN
__attribute__((nonnull))
#endif
;
/*! \brief Update table of leap seconds.
\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.
\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)
#ifndef DOXYGEN
__attribute__((nonnull))
#endif
;
/*! \brief Load new table of leap seconds from disk.
\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 \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);
/*!@}*/ /*!@}*/
/* 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:syntax=ch.doxygen vim: expandtab:ts=4:sw=4
*/ */

View File

@ -1,14 +1,13 @@
/* libiso8601/src/libiso8601/400_manip.c /* libiso8601/src/libiso8601/400_manip.c
* *
* (c)2006-2010, Laurence Withers, <l@lwithers.me.uk>. * (c)2006, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv3. See file COPYING or * Released under the GNU GPLv2. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details. * http://www.gnu.org/copyleft/gpl.html for details.
*/ */
int int iso8601_lt(const struct iso8601_date* d1, const struct iso8601_date* d2)
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 1;
if(d1->day > d2->day) return 0; if(d1->day > d2->day) return 0;
@ -20,8 +19,7 @@ iso8601_lt(const struct iso8601_date* d1, const struct iso8601_date* d2)
int int iso8601_lte(const struct iso8601_date* d1, const struct iso8601_date* d2)
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 1;
if(d1->day > d2->day) return 0; if(d1->day > d2->day) return 0;
@ -33,44 +31,26 @@ iso8601_lte(const struct iso8601_date* d1, const struct iso8601_date* d2)
int int iso8601_eq(const struct iso8601_date* d1, const struct iso8601_date* d2)
iso8601_eq(const struct iso8601_date* d1, const struct iso8601_date* d2)
{ {
return (d1->day == d2->day) && (d1->sec == d2->sec) return (d1->day == d2->day) && (d1->sec == d2->sec) && (d1->nsec == d2->nsec);
&& (d1->nsec == d2->nsec);
} }
int void iso8601_add_elapsed(struct iso8601_date* date, const struct iso8601_elapsed* per)
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; div_t qr;
int leapcorrect; int leapcorrect;
/* work out number to advance day by */ /* work out number to advance `day' by */
qr = div(per->sec, 86400); qr = div(per->sec, 86400);
leapcorrect = _leap_elapsed_day(date->day, date->day + qr.quot); leapcorrect = _leap_elapsed_day(date->day, date->day + qr.quot);
date->day += qr.quot; date->day += qr.quot;
date->sec += qr.rem - leapcorrect; date->sec += qr.rem - leapcorrect;
date->nsec += per->nsec; date->nsec += per->nsec;
if(date->nsec >= BILLION) { if(date->nsec > BILLION) {
++date->sec; ++date->sec;
date->nsec -= BILLION; date->nsec -= BILLION;
} }
@ -88,14 +68,12 @@ iso8601_add_elapsed(struct iso8601_date* date,
void void iso8601_subtract_elapsed(struct iso8601_date* date, const struct iso8601_elapsed* per)
iso8601_subtract_elapsed(struct iso8601_date* date,
const struct iso8601_elapsed* per)
{ {
div_t qr; div_t qr;
int leapcorrect; int leapcorrect;
/* work out number to advance day by */ /* work out number to advance `day' by */
qr = div(per->sec, 86400); qr = div(per->sec, 86400);
leapcorrect = _leap_elapsed_day(date->day - qr.quot, date->day); leapcorrect = _leap_elapsed_day(date->day - qr.quot, date->day);
date->day -= qr.quot; date->day -= qr.quot;
@ -120,27 +98,7 @@ iso8601_subtract_elapsed(struct iso8601_date* date,
void void iso8601_difference(const struct iso8601_date* d1, const struct iso8601_date* d2,
iso8601_add_multiple(struct iso8601_date* date,
const struct iso8601_elapsed* per, int n)
{
long long nsec;
lldiv_t qr;
struct iso8601_elapsed mult;
nsec = per->nsec * llabs(n);
qr = lldiv(nsec, BILLION);
mult.sec = qr.quot + per->sec * llabs(n);
mult.nsec = qr.rem;
if(n < 0) iso8601_subtract_elapsed(date, &mult);
else iso8601_add_elapsed(date, &mult);
}
void
iso8601_difference(const struct iso8601_date* d1, const struct iso8601_date* d2,
struct iso8601_elapsed* per, int* sign) struct iso8601_elapsed* per, int* sign)
{ {
const struct iso8601_date* e1, * e2; const struct iso8601_date* e1, * e2;
@ -172,32 +130,6 @@ iso8601_difference(const struct iso8601_date* d1, const struct iso8601_date* d2,
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 /* 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

View File

@ -1,7 +1,7 @@
/* libiso8601/src/libiso8601/400_manip.h /* libiso8601/src/libiso8601/400_manip.h
* *
* (c)2006-2010, Laurence Withers, <l@lwithers.me.uk>. * (c)2006, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv3. See file COPYING or * Released under the GNU GPLv2. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details. * http://www.gnu.org/copyleft/gpl.html for details.
*/ */
@ -9,8 +9,8 @@
/*! \defgroup manip Manipulation routines. /*! \defgroup manip Manipulation routines.
This set of functions is useful for performing arithmetic etc. on dates. It This set of functions is useful for performing arithmetic etc. on dates. It uses
uses struct \ref iso8601_elapsed to represent the magnitude of time differences. struct iso8601_elapsed to represent the magnitude of time differences.
*/ */
/*!@{*/ /*!@{*/
@ -25,11 +25,7 @@ uses struct \ref iso8601_elapsed to represent the magnitude of time differences.
\retval 0 otherwise \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
;
@ -41,11 +37,7 @@ int iso8601_lt(const struct iso8601_date* d1, const struct iso8601_date* d2)
\retval 0 otherwise \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
;
@ -57,28 +49,7 @@ int iso8601_lte(const struct iso8601_date* d1, const struct iso8601_date* d2)
\retval 0 otherwise \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
;
@ -88,12 +59,7 @@ int iso8601_cmp(const struct iso8601_date* d1, const struct iso8601_date* d2)
\param per Period to advance date/time by. \param per Period to advance date/time by.
*/ */
void iso8601_add_elapsed(struct iso8601_date* date, void iso8601_add_elapsed(struct iso8601_date* date, const struct iso8601_elapsed* per);
const struct iso8601_elapsed* per)
#ifndef DOXYGEN
__attribute__((nonnull))
#endif
;
@ -103,32 +69,7 @@ void iso8601_add_elapsed(struct iso8601_date* date,
\param per Period to regress date/time by. \param per Period to regress date/time by.
*/ */
void iso8601_subtract_elapsed(struct iso8601_date* date, void iso8601_subtract_elapsed(struct iso8601_date* date, const struct iso8601_elapsed* per);
const struct iso8601_elapsed* per)
#ifndef DOXYGEN
__attribute__((nonnull))
#endif
;
/*! \brief Add a multiple of a period to a date.
\param[in,out] date Date to modify.
\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.
*/
void iso8601_add_multiple(struct iso8601_date* date,
const struct iso8601_elapsed* per, int n)
#ifndef DOXYGEN
__attribute__((nonnull))
#endif
;
@ -139,44 +80,18 @@ void iso8601_add_multiple(struct iso8601_date* date,
\param[out] per Magnitude of period elapsed between two dates. Pointer may be 0. \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. \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 This function will perform the calculation <code>|d1 - d2|</code>, storing the result in \a per (if
result in \a per (if it is not a null pointer). The sign of the result is it is not a null pointer). The sign of the result is stored in \a sign (if it is not a null
stored in \a sign (if it is not a null pointer), i.e. -1 if \a d2 &gt; \a d1 or pointer), i.e. -1 if \a d2 &gt; \a d1 or +1 if \a d2 &lt;= \a d1.
+1 if \a d2 &lt;= \a d1.
*/ */
void iso8601_difference(const struct iso8601_date* d1, void iso8601_difference(const struct iso8601_date* d1, const struct iso8601_date* d2,
const struct iso8601_date* d2, struct iso8601_elapsed* per, int* sign) 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
;
/*!@}*/ /*!@}*/
/* 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:syntax=ch.doxygen vim: expandtab:ts=4:sw=4
*/ */

View File

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

View File

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

View File

@ -14,9 +14,7 @@ then
libiso8601="obj/${libiso8601_BASE}.so.${SOMAJOR}.${SOMICRO}" libiso8601="obj/${libiso8601_BASE}.so.${SOMAJOR}.${SOMICRO}"
libiso8601_DEP_CFLAGS="" libiso8601_DEP_CFLAGS=""
libiso8601_DEP_LIBS="-lrt" libiso8601_DEP_LIBS="-lrt"
SO_EXTRA="${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}..." echo "Building library ${libiso8601}..."
@ -41,9 +39,8 @@ then
-Wl,-soname,${SONAME} \ -Wl,-soname,${SONAME} \
${SRC} ${SO_EXTRA} || return 1 ${SRC} ${SO_EXTRA} || return 1
# make tests and linking work # make tests work
do_cmd ln -sf "$(basename "${libiso8601}")" "obj/${SONAME}" || return 1 do_cmd ln -sf $(basename ${libiso8601}) obj/${SONAME} || return 1
do_cmd ln -sf "$(basename "${libiso8601}")" "obj/${libiso8601_BASE}.so" || return 1
print_success "Library built" print_success "Library built"
else else
@ -54,4 +51,5 @@ then
libiso8601_HEADER=${HDR} libiso8601_HEADER=${HDR}
fi fi
# kate: replace-trailing-space-save true; space-indent true; tab-width 4;
# vim: syntax=sh:expandtab:ts=4:sw=4 # vim: syntax=sh:expandtab:ts=4:sw=4

View File

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

View File

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

21
src/libiso8601/pkgconf.in Normal file
View File

@ -0,0 +1,21 @@
# libiso8601/src/lib/clib/pkgconf.in
#
# Metadata file for pkg-config
# ( http://www.freedesktop.org/software/pkgconfig/ )
#
# (c)2006, Laurence Withers, <l@lwithers.me.uk>.
# Released under the GNU GPLv2. See file COPYING or
# http://www.gnu.org/copyleft/gpl.html for details.
#
# Name, description
Name: @TODO@
Description: @TODO@
Version: @VERSION@
# Requirements
Requires:
# Compilation information
Libs: -L@LIBDIR@ -liso8601
Cflags: -I@INCLUDEDIR@

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -92,26 +92,13 @@ void date_stack_push_elapsed(const struct iso8601_elapsed* per)
/* date_stack_pop()
* Pops an element from the date stack.
*/
void date_stack_pop(void)
{
struct date_stack* next;
--date_stack_size;
next = date_stack_top->next;
free(date_stack_top);
date_stack_top = next;
}
/* date_stack_pop_date() /* date_stack_pop_date()
* Pops a date from the stack, returning non-0 on error (underflow or type mismatch). * Pops a date from the stack, returning non-0 on error (underflow or type mismatch).
*/ */
int date_stack_pop_date(struct iso8601_date* d, struct iso8601_details* det) int date_stack_pop_date(struct iso8601_date* d, struct iso8601_details* det)
{ {
struct date_stack* next;
if(!date_stack_top) { if(!date_stack_top) {
fputs("Stack underflow.\n", stderr); fputs("Stack underflow.\n", stderr);
return -1; return -1;
@ -123,7 +110,11 @@ int date_stack_pop_date(struct iso8601_date* d, struct iso8601_details* det)
*d = date_stack_top->u.date.d; *d = date_stack_top->u.date.d;
*det = date_stack_top->u.date.det; *det = date_stack_top->u.date.det;
date_stack_pop();
--date_stack_size;
next = date_stack_top->next;
free(date_stack_top);
date_stack_top = next;
return 0; return 0;
} }
@ -135,6 +126,8 @@ int date_stack_pop_date(struct iso8601_date* d, struct iso8601_details* det)
*/ */
int date_stack_pop_elapsed(struct iso8601_elapsed* per) int date_stack_pop_elapsed(struct iso8601_elapsed* per)
{ {
struct date_stack* next;
if(!date_stack_top) { if(!date_stack_top) {
fputs("Stack underflow.\n", stderr); fputs("Stack underflow.\n", stderr);
return -1; return -1;
@ -145,40 +138,17 @@ int date_stack_pop_elapsed(struct iso8601_elapsed* per)
} }
*per = date_stack_top->u.per; *per = date_stack_top->u.per;
date_stack_pop();
--date_stack_size;
next = date_stack_top->next;
free(date_stack_top);
date_stack_top = next;
return 0; return 0;
} }
/* date_stack_dump()
* Dumps and clears the contents of the date stack.
*/
void date_stack_dump(void)
{
while(date_stack_top) {
switch(date_stack_top->type) {
case date_stack_type_date:
fprintf(stderr, "Date (day=%d, sec=%d, nsec=%d)\n",
date_stack_top->u.date.d.day, date_stack_top->u.date.d.sec, date_stack_top->u.date.d.nsec);
break;
case date_stack_type_per:
fprintf(stderr, "Period (sec=%d, nsec=%d)\n",
date_stack_top->u.per.sec, date_stack_top->u.per.nsec);
break;
default:
fprintf(stderr, "Unknown type %d.\n", date_stack_top->type);
break;
}
date_stack_pop();
}
}
/* usage() /* usage()
* Displays help. * Displays help.
*/ */
@ -189,14 +159,11 @@ void usage(void)
"Operators:\n" "Operators:\n"
" + (date, period) Advance date by elapsed time, push date.\n" " + (date, period) Advance date by elapsed time, push date.\n"
" - (date, period) Regress date by elapsed time, push date.\n" " - (date, period) Regress date by elapsed time, push date.\n"
" +* (date, period, num) Advance date by elapsed time multiplied by num, push date.\n"
" -* (date, period, num) Regress date by elapsed time multiplied by num, push date.\n"
" dp (date, date) Compute difference, print elapsed time.\n" " dp (date, date) Compute difference, print elapsed time.\n"
" < (date, date) Prints 1 if first date less than second.\n" " < (date, date) Prints 1 if first date less than second.\n"
" <= (date, date) Prints 1 if first date less than or equal to second.\n" " <= (date, date) Prints 1 if first date less than or equal to second.\n"
" == (date, date) Prints 1 if dates equal.\n" " == (date, date) Prints 1 if dates equal.\n"
" p (date) Prints a date.\n" " p (date) Prints a date.\n"
" ds Dump stack.\n"
"\n" "\n"
"Type help for this screen at any point.\n" "Type help for this screen at any point.\n"
"\n", stdout); "\n", stdout);
@ -208,7 +175,7 @@ int parse_command(char* cmd)
{ {
struct iso8601_date date, date2; struct iso8601_date date, date2;
struct iso8601_details details, details2; struct iso8601_details details, details2;
struct iso8601_elapsed period, num; struct iso8601_elapsed period;
double period_d; double period_d;
char date_str[40]; char date_str[40];
int ret = 0, sign; int ret = 0, sign;
@ -242,27 +209,6 @@ int parse_command(char* cmd)
} }
} else if(!strcmp(cmd, "+*") || !strcmp(cmd, "-*")) {
if(date_stack_pop_elapsed(&num)) {
ret = 1;
} else if(num.nsec) {
ret = 1;
fputs("Number cannot be fractional.\n", stderr);
} else {
if(date_stack_pop_elapsed(&period) || date_stack_pop_date(&date, &details)) {
ret = 1;
} else {
iso8601_add_multiple(&date, &period, ((cmd[0] == '-') ? -1 : 1) * num.sec);
date_stack_push_date(&date, &details);
}
}
} else if(!strcmp(cmd, "dp")) { } else if(!strcmp(cmd, "dp")) {
if(date_stack_pop_date(&date, &details) || date_stack_pop_date(&date2, &details2)) { if(date_stack_pop_date(&date, &details) || date_stack_pop_date(&date2, &details2)) {
ret = 1; ret = 1;
@ -313,9 +259,6 @@ int parse_command(char* cmd)
putc('\n', stdout); putc('\n', stdout);
} }
} else if(!strcmp(cmd, "ds")) {
date_stack_dump();
} else { } else {
fputs("Unrecognised command or argument.\n", stderr); fputs("Unrecognised command or argument.\n", stderr);
ret = 1; ret = 1;

View File

@ -204,7 +204,7 @@ int main(int argc, char* argv[])
int ret = 0; int ret = 0;
struct iso8601_date dt; struct iso8601_date dt;
struct iso8601_details details, details2; struct iso8601_details details, details2;
char buf[40], buf2[40]; char buf[100], buf2[100];
const struct test* test; const struct test* test;
if(argc == 2 && !strcmp(argv[1], "--print-summary")) { if(argc == 2 && !strcmp(argv[1], "--print-summary")) {
@ -215,11 +215,7 @@ int main(int argc, char* argv[])
iso8601_now(&dt, &details); iso8601_now(&dt, &details);
printf("%-30s %-30s %s\n", "Name", "Basic format", "Extended format"); printf("%-30s %-30s %s\n", "Name", "Basic format", "Extended format");
for(test = tests; test->desc; ++test) { for(test = tests; test->desc; ++test) {
memset(buf, 'X', sizeof(buf));
memset(buf2, 'X', sizeof(buf2)); /* test null-termination */
test->do_details(&details2, &details); test->do_details(&details2, &details);
iso8601_print(buf, sizeof(buf), &dt, &details2); iso8601_print(buf, sizeof(buf), &dt, &details2);
++details2.extended; ++details2.extended;
iso8601_print(buf2, sizeof(buf2), &dt, &details2); iso8601_print(buf2, sizeof(buf2), &dt, &details2);

View File

@ -1,9 +1,9 @@
/* libiso8601/src/tests/xxx.c /* libiso8601/src/tests/???.c
* *
* Copyright: ©20072011, Güralp Systems Ltd. * (c)2007, Laurence Withers, <l@lwithers.me.uk>.
* Author: Laurence Withers <lwithers@guralp.com> * Released under the GNU GPLv3. See file COPYING or
* License: GPLv3 * http://www.gnu.org/copyleft/gpl.html for details.
*/ */
#include "iso8601.h" #include "iso8601.h"
@ -12,13 +12,12 @@
int int main(int argc, char* argv[])
main(int argc, char* argv[])
{ {
int ret = 0; int ret = 0;
if(argc == 2 && !strcmp(argv[1], "--print-summary")) { if(argc == 2 && !strcmp(argv[1], "--print-summary")) {
fputs("One line summary.\n", stdout); printf("One line summary.\n");
return 0; return 0;
} }
@ -31,8 +30,7 @@ main(int argc, char* argv[])
return ret; return ret;
} }
/* options for text editors /* 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
*/ */

View File

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