Code:
#define _XOPEN_SOURCE 600
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#include <errno.h>
#include <locale.h>
#include <langinfo.h>
#include <math.h>
static const char *datetime_format[] = {
"%c", /* Local date and time */
"%Ec", /* Alternate local date and time */
"%X", /* Local time */
"%EX", /* Alternate local time */
"%Y-%m-%d %T", /* ISO date-time with seconds */
"%Y-%m-%d %R", /* ISO date-time without seconds */
"%Y-%m-%d T %T", /* ISO date-time using T, with seconds */
"%Y-%m-%d T %R", /* ISO date-time using T, without seconds */
"%r", /* Local 12-hour time */
"%H:%M:%S", /* 24-hour time */
"%I:%M:%S %p", /* 12-hour time */
"%H:%M", /* Just hours and minutes (24-hour clock) */
"%I:%M %p", /* Just hours and minutes (12-hour clock) */
"%H", /* Just hours (24-hour clock) */
"%I %p", /* Just hours (12-hour clock) */
"%a %H:%M:%S", /* Weekday hour:minutes:seconds (24-hour clock) */
"%a %I:%M:%S %p", /* Weekday hour:minutes:seconds (12-hour clock) */
"%a %H:%M", /* Weekday hour:minutes (24-hour clock) */
"%a %I:%M %p", /* Weekday hour:minutes (12-hour clock) */
"%a %H", /* Weekday hour (24-hour clock) */
"%a %I %p", /* Weekday hour (12-hour clock) */
NULL /* End of list */
};
/* Parse specified date or time string.
* Unset fields are set to -1.
*/
int datetime(const char *const string, struct tm *const ptr)
{
char *ends;
size_t i;
/* Neither pointer can be NULL. */
if (!string || !ptr)
return errno = EINVAL;
/* Check each datetime_format in order. */
for (i = 0; datetime_format[i]; i++) {
/* Make all date/time fields invalid. */
ptr->tm_sec = -1;
ptr->tm_min = -1;
ptr->tm_hour = -1;
ptr->tm_mday = -1;
ptr->tm_mon = -1;
ptr->tm_year = -1;
ptr->tm_wday = -1;
ptr->tm_yday = -1;
ptr->tm_isdst = -1;
ends = strptime(string, datetime_format[i], ptr);
/* No match? */
if (!ends)
continue;
/* Skip trailing garbage (ignore all but letters and digits) */
while (*ends && !isalpha(*ends))
ends++;
/* If there is trailing garbage, no match. */
if (*ends)
continue;
/* We had a match. */
return 0;
}
/* No match. */
return errno = EINVAL;
}
char *sdup(const char *const original, const char *const empty)
{
if (original && *original)
return strdup(original);
else
return strdup(empty);
}
int main(int argc, char *argv[])
{
struct tm now_tm, enter_tm, exit_tm;
time_t now_time, enter_time, exit_time;
char buffer[1024];
const char *datetime_format;
int days, hours, minutes;
/* Our time functions are locale-aware. */
setlocale(LC_TIME, ""); /* Time defaults (from user environment) */
setlocale(LC_MESSAGES, ""); /* Message defaults (from user environment) */
/* Get strftime() formats based on current locale. */
datetime_format = sdup(nl_langinfo(D_T_FMT), "%c");
/* Get current time. */
now_time = time(NULL);
now_tm = *(struct tm *)localtime(&now_time);
/* Check for correct number of arguments. */
if (argc != 3) {
fprintf(stderr, "\nUsage: %s when-entered when-exited\n\n", argv[0]);
return 1;
}
/* Parse enter date/time. */
if (datetime(argv[1], &enter_tm)) {
fprintf(stderr, "%s: Sorry, cannot understand that date/time format.\n", argv[1]);
return 1;
}
/* Weekday only? */
if (enter_tm.tm_mday == -1 && enter_tm.tm_wday != -1) {
enter_tm.tm_year = now_tm.tm_year;
enter_tm.tm_mon = now_tm.tm_mon;
enter_tm.tm_mday = now_tm.tm_mday;
while (enter_tm.tm_wday != now_tm.tm_wday) {
enter_tm.tm_mday--; /* mktime() will normalize this! */
enter_tm.tm_wday = (enter_tm.tm_wday + 1) % 7;
}
} else {
/* Missing year/month/day? */
if (enter_tm.tm_year == -1)
enter_tm.tm_year = now_tm.tm_year;
if (enter_tm.tm_mon == -1)
enter_tm.tm_mon = now_tm.tm_mon;
if (enter_tm.tm_mday == -1)
enter_tm.tm_mday = now_tm.tm_mday;
}
/* Hours? */
if (enter_tm.tm_hour == -1) {
fprintf(stderr, "%s: No entering time specified.\n", argv[1]);
return 1;
} else {
if (enter_tm.tm_min == -1) {
/* No minutes specified, only hour */
enter_tm.tm_min = 0;
enter_tm.tm_sec = 0;
} else
if (enter_tm.tm_sec == -1) {
/* No seconds specified, only hour and minutes */
enter_tm.tm_sec = 0;
}
}
/* Normalize enter_tm, and also get it as seconds since epoch. */
enter_time = mktime(&enter_tm);
if (enter_time == (time_t)-1) {
fprintf(stderr, "%s: Sorry, something is wonky about that date/time.\n", argv[1]);
return 1;
}
/* Parse exit date/time. */
if (datetime(argv[2], &exit_tm)) {
fprintf(stderr, "%s: Sorry, cannot understand that date/time format.\n", argv[2]);
return 1;
}
/* Weekday only? */
if (exit_tm.tm_mday == -1 && exit_tm.tm_wday != -1) {
exit_tm.tm_year = now_tm.tm_year;
exit_tm.tm_mon = now_tm.tm_mon;
exit_tm.tm_mday = now_tm.tm_mday;
while (exit_tm.tm_wday != now_tm.tm_wday) {
exit_tm.tm_mday--; /* mktime() will normalize this! */
exit_tm.tm_wday = (exit_tm.tm_wday + 1) % 7;
}
} else {
/* Missing year/month/day? Use enter date, if so. */
if (exit_tm.tm_year == -1)
exit_tm.tm_year = enter_tm.tm_year;
if (exit_tm.tm_mon == -1)
exit_tm.tm_mon = enter_tm.tm_mon;
if (exit_tm.tm_mday == -1)
exit_tm.tm_mday = enter_tm.tm_mday;
}
/* Hours? */
if (exit_tm.tm_hour == -1) {
fprintf(stderr, "%s: No entering time specified.\n", argv[2]);
return 1;
} else {
if (exit_tm.tm_min == -1) {
/* No minutes specified, only hour */
exit_tm.tm_min = 0;
exit_tm.tm_sec = 0;
} else
if (exit_tm.tm_sec == -1) {
/* No seconds specified, only hour and minutes */
exit_tm.tm_sec = 0;
}
}
/* Normalize exit_tm, and also get it as seconds since epoch. */
exit_time = mktime(&exit_tm);
if (exit_time == (time_t)-1) {
fprintf(stderr, "%s: Sorry, something is wonky about that date/time.\n", argv[2]);
return 1;
}
/* Show enter date/time in current locale. */
if (strftime(buffer, sizeof buffer, datetime_format, &enter_tm))
printf("Entered: %s\n", buffer);
else
printf("Entered: %s\n", asctime(&enter_tm));
/* Show enter date/time in current locale. */
if (strftime(buffer, sizeof buffer, datetime_format, &exit_tm))
printf("Exited: %s\n", buffer);
else
printf("Exited: %s\n", asctime(&exit_tm));
printf("Difference: %.0f seconds", difftime(exit_time, enter_time));
/* Round minutes. */
minutes = (int)round(difftime(exit_time, enter_time) / 60.0);
printf(" (or about %d minutes, or about %.0f hours)\n", minutes, minutes / 60.0);
days = minutes / 1440;
minutes = minutes % 1440; /* or minutes - 1440*days */
hours = minutes / 60;
minutes = minutes % 60; /* or minutes - 60*hours */
if (days > 0)
printf("Duration: %d days, %d hours, %d minutes\n", days, hours, minutes);
else
if (hours > 0)
printf("Duration: %d hours, %d minutes\n", hours, minutes);
else
if (minutes > 0)
printf("Duration: %d minutes\n", minutes);
else
if (minutes < 0)
printf("Exited before entered.\n");
free((void *)datetime_format);
return 0;
}
Compile using for example