/* * Copyright (C) 2012 Andy Spencer * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ /* Time Keeping Bugs Abound! */ #define _POSIX_C_SOURCE 200112L #include #include #include #include #include "util.h" #include "conf.h" #include "date.h" /* Global data */ date_t NOW; date_t SEL; /* Initialize */ void date_init(void) { /* Sync current time */ NOW = get_date(0); /* Sync selection */ SEL.year = NOW.year; SEL.month = NOW.month; SEL.day = NOW.day; } void date_config(const char *group, const char *name, const char *key, const char *value) { if (match(group, "date") && match(key, "timezone") && value) setenv("TZ", get_string(value), 1); } void date_sync(void) { NOW = get_date(0); } /* Time functions */ int is_leap_year(year_t year) { return (year % 400 == 0) ? 1 : (year % 100 == 0) ? 0 : (year % 4 == 0) ? 1 : 0; } int days_in_year(year_t year) { return 365 + is_leap_year(year); } int days_in_month(year_t year, month_t month) { static int mdays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; int days = mdays[month]; if (month == FEB) days += is_leap_year(year); return days; } int weeks_in_month(year_t year, month_t month) { int start = start_of_month(year, month); int days = days_in_month(year, month); return ((start + days)-1) / 7 + 1; } wday_t day_of_week(year_t year, month_t month, day_t day) { static int tmp[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4}; if (month < MAR) year--; int start = year + year / 4 - year / 100 + year / 400 + tmp[month]; return (start + day + 1) % 7; } wday_t start_of_month(year_t year, month_t month) { return day_of_week(year, month, 0); } void add_days(year_t *year, month_t *month, day_t *day, int days) { date_t date = { .year = *year, .month = *month, .day = *day, .hour = 12 }; stamp_t stamp = get_stamp(date); date_t then = get_date(stamp + days*24*60*60); *year = then.year; *month = then.month; *day = then.day; } void add_months(year_t *year, month_t *month, int months) { int total = *year*12 + *month + months; *year = total / 12; *month = total % 12; } /* Date functions */ date_t get_date(stamp_t stamp) { time_t t = stamp ? stamp : time(NULL); struct tm *tm = localtime(&t); date_t date = { .year = tm->tm_year+1900, .month = tm->tm_mon, .day = tm->tm_mday-1, .hour = tm->tm_hour, .min = tm->tm_min, .sec = tm->tm_sec, }; return date; } stamp_t get_stamp(date_t date) { struct tm tm = { .tm_year = date.year-1900, .tm_mon = date.month, .tm_mday = date.day+1, .tm_hour = date.hour, .tm_min = date.min, .tm_sec = date.sec, }; time_t t = mktime(&tm); return (stamp_t)t; } int get_mins(date_t *start, date_t *end) { return (get_stamp(*end)-get_stamp(*start))/60; } int get_secs(date_t *start, date_t *end) { return (get_stamp(*end)-get_stamp(*start)); } int compare(date_t *a, date_t *b) { int rval = a->year < b->year ? -1 : a->year > b->year ? 1 : a->month < b->month ? -1 : a->month > b->month ? 1 : a->day < b->day ? -1 : a->day > b->day ? 1 : a->hour < b->hour ? -1 : a->hour > b->hour ? 1 : a->min < b->min ? -1 : a->min > b->min ? 1 : 0; return rval; } int same_day(date_t *a, date_t *b) { return a->year == b->year && a->month == b->month && a->day == b->day; } int before(date_t *start, int year, int month, int day, int hour, int min) { return compare(start, &(date_t){year, month, day, hour, min}) < 0; } int all_day(date_t *start, date_t *end) { date_t test = *start; add_days(&test.year, &test.month, &test.day, 1); return compare(&test, end) <= 0; } int no_date(date_t *date) { return date->year == 0; } /* Debug functions */ const char *month_to_str(month_t month) { static const char *map[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", }; return map[month%12]; } const char *month_to_string(month_t month) { static const char *map[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; return map[month%12]; } const char *day_to_st(wday_t day) { static const char *map[] = { "Su","Mo", "Tu", "We", "Th", "Fr", "Sa" }; return map[day%7]; } const char *day_to_str(wday_t day) { static const char *map[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; return map[day%7]; } const char *day_to_string(wday_t day) { static const char *map[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; return map[day%7]; } /* Test functions */ void date_test(void) { setenv("TZ", "US/Central", 1); time_t timet = time(NULL); date_t date = get_date(timet); stamp_t stamp = get_stamp(date); printf("Time\n"); printf(" time %ld\n", timet); printf(" stamp %lld\n", stamp); printf(" date %04d-%02d-%02d %02d:%02d %02ds\n", date.year, date.month, date.day, date.hour, date.min, date.sec); printf("Info\n"); printf(" Year Month Start Weeks Days\n"); for (int y = 2012; y <= 2012; y++) for (int m = JAN; m <= DEC; m++) { printf(" %-5d", y); printf(" %-10s", month_to_string(m)); printf(" %-6s", day_to_str(start_of_month(y,m))); printf(" %-6d", weeks_in_month(y,m)); printf(" %-2d", days_in_month(y,m)); printf("\n"); } }