/* daymath.c
 *
 * The author places the following code in the public domain.
 *
 * Contact: Andy Goth <unununium@openverse.com>
 *
 * For useful information on dates and calendars, visit
 * <URL:http://www.merlyn.demon.co.uk/datelinx.htm> */

#include <stdio.h>
#include <stdlib.h>

/* Returns true if and only iff [y-m-d] is a valid date. */
static int dayvalidate (int y, int m, int d)
{
    int length[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

    /* Months must be in the range [1..12]. */
    if (m < 1 || m > 12) {
        return 0;
    }

    /* Years must be AD. */
    if (y < 1) {
        return 0;
    }

    /* Days must be within the month.  Allow Feb 29 for leap years. */
    if (d < 1 || (d > length[m - 1] &&
    (m != 2 || d != 29 || y % 4 != 0 || (y % 100 == 0 && y % 400 != 0)))) {
        return 0;
    }

    /* Valid. */
    return 1;
}

/* Returns the number of days between [y-m-d] and [2000-01-01].  Positive
 * indicates [y-m-d] occurs after [2000-01-01]. */
static int daycount (int y, int m, int d)
{
    /* Treat January and February as extensions to the previous year,
     * as in Zeller's congruence. */
    if (m < 3) {
        m += 12;
        y -=  1;
    }

    return -730517             /* Constant gives base date 2000-01-01 AD. */
         + d                   /* Start with the day of the month.        */
         + ((153 * m - 2) / 5) /* Add the beginning of the month.         */
         + 365 * y             /* Most years are 365 days in length,      */
         + (y / 4)             /* but every fourth year has an extra day, */
         - (y / 100)           /* except for every hundredth year         */
         + (y / 400);          /* that isn't a multiple of 400.           */
}

/* Returns the number of days between [y1-m1-d1] and [y2-m2-d2].  Positive
 * indicates [y1-m1-d1] occurs after [y2-m2-d2]. */
static int daydifference (int y1, int m1, int d1, int y2, int m2, int d2)
{
    return daycount(y1, m1, d1) - daycount(y2, m2, d2);
}

int main(int argc, char** argv)
{
    int args[6];
    int i;
    int count;
    char* end;

    /* Check for correct number of arguments. */
    if (argc != 7) {
        fprintf(stderr, "Usage: %s YYYY MM DD YYYY MM DD\n", argv[0]);
        return EXIT_FAILURE;
    }

    /* Get integers from command-line arguments. */
    for (i = 0; i < 6; ++i) {
        args[i] = strtol(argv[i + 1], &end, 10);
        if (argv[i + 1][0] == '\0' || end[0] != '\0') {
            fprintf(stderr, "Bad integer \"%s\"\n", argv[i + 1]);
            return EXIT_FAILURE;
        }
    }

    /* Check validity of dates. */
    for (i = 0; i < 6; i += 3) {
        if (!dayvalidate(args[i + 0], args[i + 1], args[i + 2])) {
            fprintf(stderr, "Bad date [%04d-%02d-%02d]\n",
                    args[i + 0], args[i + 1], args[i + 2]);
            return EXIT_FAILURE;
        }
    }

    /* Do it! */
    count = abs(daycount(args[0], args[1], args[2]) -
            daycount(args[3], args[4], args[5])) + 1;
    printf("Number of days in range [%04d-%02d-%02d] - [%04d-%02d-%02d]: %d \n",
            args[0], args[1], args[2], args[3], args[4], args[5], count);

    /* Done. */
    return EXIT_SUCCESS;
}

/* vim: set ts=4 sts=4 sw=4 tw=80 et: */

