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