Add iso8601_add_multiple()
Add a function to efficiently add (or subtract) a multiple of a period to a timestamp.
This commit is contained in:
parent
d431f68054
commit
cad2283f6a
|
@ -13,6 +13,7 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
/* Useful define to alleviate typos */
|
||||
|
|
|
@ -98,6 +98,23 @@ void iso8601_subtract_elapsed(struct iso8601_date* date, const struct iso8601_el
|
|||
|
||||
|
||||
|
||||
void iso8601_add_multiple(struct iso8601_date* date, const struct iso8601_elapsed* per, int n)
|
||||
{
|
||||
intmax_t nsec;
|
||||
imaxdiv_t qr;
|
||||
struct iso8601_elapsed mult;
|
||||
|
||||
nsec = per->nsec * imaxabs(n);
|
||||
qr = imaxdiv(nsec, BILLION);
|
||||
mult.sec = qr.quot + per->sec * imaxabs(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)
|
||||
{
|
||||
|
|
|
@ -73,6 +73,20 @@ void iso8601_subtract_elapsed(struct iso8601_date* date, const struct iso8601_el
|
|||
|
||||
|
||||
|
||||
/*! \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);
|
||||
|
||||
|
||||
|
||||
/*! \brief Find difference between dates.
|
||||
|
||||
\param d1 First date.
|
||||
|
@ -93,5 +107,5 @@ void iso8601_difference(const struct iso8601_date* d1, const struct iso8601_date
|
|||
/*!@}*/
|
||||
/* options for text editors
|
||||
kate: replace-trailing-space-save true; space-indent true; tab-width 4;
|
||||
vim: expandtab:ts=4:sw=4
|
||||
vim: expandtab:ts=4:sw=4:syntax=ch.doxygen
|
||||
*/
|
||||
|
|
|
@ -92,13 +92,26 @@ 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()
|
||||
* 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)
|
||||
{
|
||||
struct date_stack* next;
|
||||
|
||||
if(!date_stack_top) {
|
||||
fputs("Stack underflow.\n", stderr);
|
||||
return -1;
|
||||
|
@ -110,11 +123,7 @@ int date_stack_pop_date(struct iso8601_date* d, struct iso8601_details* det)
|
|||
|
||||
*d = date_stack_top->u.date.d;
|
||||
*det = date_stack_top->u.date.det;
|
||||
|
||||
--date_stack_size;
|
||||
next = date_stack_top->next;
|
||||
free(date_stack_top);
|
||||
date_stack_top = next;
|
||||
date_stack_pop();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -126,8 +135,6 @@ int date_stack_pop_date(struct iso8601_date* d, struct iso8601_details* det)
|
|||
*/
|
||||
int date_stack_pop_elapsed(struct iso8601_elapsed* per)
|
||||
{
|
||||
struct date_stack* next;
|
||||
|
||||
if(!date_stack_top) {
|
||||
fputs("Stack underflow.\n", stderr);
|
||||
return -1;
|
||||
|
@ -138,17 +145,40 @@ int date_stack_pop_elapsed(struct iso8601_elapsed* per)
|
|||
}
|
||||
|
||||
*per = date_stack_top->u.per;
|
||||
|
||||
--date_stack_size;
|
||||
next = date_stack_top->next;
|
||||
free(date_stack_top);
|
||||
date_stack_top = next;
|
||||
date_stack_pop();
|
||||
|
||||
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()
|
||||
* Displays help.
|
||||
*/
|
||||
|
@ -159,11 +189,14 @@ void usage(void)
|
|||
"Operators:\n"
|
||||
" + (date, period) Advance 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"
|
||||
" < (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 dates equal.\n"
|
||||
" p (date) Prints a date.\n"
|
||||
" ds Dump stack.\n"
|
||||
"\n"
|
||||
"Type help for this screen at any point.\n"
|
||||
"\n", stdout);
|
||||
|
@ -175,7 +208,7 @@ int parse_command(char* cmd)
|
|||
{
|
||||
struct iso8601_date date, date2;
|
||||
struct iso8601_details details, details2;
|
||||
struct iso8601_elapsed period;
|
||||
struct iso8601_elapsed period, num;
|
||||
double period_d;
|
||||
char date_str[40];
|
||||
int ret = 0, sign;
|
||||
|
@ -209,6 +242,27 @@ 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")) {
|
||||
if(date_stack_pop_date(&date, &details) || date_stack_pop_date(&date2, &details2)) {
|
||||
ret = 1;
|
||||
|
@ -259,6 +313,9 @@ int parse_command(char* cmd)
|
|||
putc('\n', stdout);
|
||||
}
|
||||
|
||||
} else if(!strcmp(cmd, "ds")) {
|
||||
date_stack_dump();
|
||||
|
||||
} else {
|
||||
fputs("Unrecognised command or argument.\n", stderr);
|
||||
ret = 1;
|
||||
|
|
Loading…
Reference in New Issue