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 <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <inttypes.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
|
||||||
/* Useful define to alleviate typos */
|
/* 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,
|
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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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.
|
/*! \brief Find difference between dates.
|
||||||
|
|
||||||
\param d1 First date.
|
\param d1 First date.
|
||||||
|
@ -93,5 +107,5 @@ void iso8601_difference(const struct iso8601_date* d1, const struct iso8601_date
|
||||||
/*!@}*/
|
/*!@}*/
|
||||||
/* 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: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()
|
/* 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;
|
||||||
|
@ -110,11 +123,7 @@ 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;
|
||||||
}
|
}
|
||||||
|
@ -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)
|
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;
|
||||||
|
@ -138,17 +145,40 @@ 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.
|
||||||
*/
|
*/
|
||||||
|
@ -159,11 +189,14 @@ 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);
|
||||||
|
@ -175,7 +208,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;
|
struct iso8601_elapsed period, num;
|
||||||
double period_d;
|
double period_d;
|
||||||
char date_str[40];
|
char date_str[40];
|
||||||
int ret = 0, sign;
|
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")) {
|
} 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;
|
||||||
|
@ -259,6 +313,9 @@ 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;
|
||||||
|
|
Loading…
Reference in New Issue