]> Pileus Git - lackey/blob - src/date.c
Add simple notification daemon mode
[lackey] / src / date.c
1 /*
2  * Copyright (C) 2012 Andy Spencer <andy753421@gmail.com>
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 /* Time Keeping Bugs Abound! */
19
20 #define _POSIX_C_SOURCE 200112L
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <time.h>
26
27 #include "util.h"
28 #include "conf.h"
29 #include "date.h"
30
31 /* Global data */
32 date_t  NOW;
33 date_t  SEL;
34
35 /* Initialize */
36 void date_init(void)
37 {
38         /* Sync current time */
39         NOW = get_date(0);
40
41         /* Sync selection */
42         SEL.year  = NOW.year;
43         SEL.month = NOW.month;
44         SEL.day   = NOW.day;
45 }
46
47 void date_config(const char *group, const char *name, const char *key, const char *value)
48 {
49         if (match(group, "date") && match(key, "timezone") && value)
50                 setenv("TZ", get_string(value), 1);
51 }
52
53 void date_sync(void)
54 {
55         NOW = get_date(0);
56 }
57
58 /* Time functions */
59 int is_leap_year(year_t year)
60 {
61         return (year % 400 == 0) ? 1 :
62                (year % 100 == 0) ? 0 :
63                (year % 4   == 0) ? 1 : 0;
64 }
65
66 int days_in_year(year_t year)
67 {
68         return 365 + is_leap_year(year);
69 }
70
71 int days_in_month(year_t year, month_t month)
72 {
73         static int mdays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
74         int days = mdays[month];
75         if (month == FEB)
76                 days += is_leap_year(year);
77         return days;
78 }
79
80 int weeks_in_month(year_t year, month_t month)
81 {
82         int start = start_of_month(year, month);
83         int days  = days_in_month(year, month);
84         return ((start + days)-1) / 7 + 1;
85 }
86
87 wday_t day_of_week(year_t year, month_t month, day_t day)
88 {
89         static int tmp[] = {0, 3, 2, 5, 0, 3,
90                             5, 1, 4, 6, 2, 4};
91         if (month < MAR)
92                 year--;
93         int start = year + year / 4
94                          - year / 100
95                          + year / 400
96                          + tmp[month];
97         return (start + day + 1) % 7;
98 }
99
100 wday_t start_of_month(year_t year, month_t month)
101 {
102         return day_of_week(year, month, 0);
103 }
104
105 void add_days(year_t *year, month_t *month, day_t *day, int days)
106 {
107         date_t date = {
108                 .year  = *year,
109                 .month = *month,
110                 .day   = *day,
111                 .hour  = 12
112         };
113         stamp_t stamp = get_stamp(date);
114         date_t  then  = get_date(stamp + days*24*60*60);
115         *year  = then.year;
116         *month = then.month;
117         *day   = then.day;
118 }
119
120 void add_months(year_t *year, month_t *month, int months)
121 {
122         int total = *year*12 + *month + months;
123         *year  = total / 12;
124         *month = total % 12;
125 }
126
127 /* Date functions */
128 date_t get_date(stamp_t stamp)
129 {
130         time_t t = stamp ? stamp : time(NULL);
131         struct tm *tm = localtime(&t);
132         date_t date = {
133                 .year  = tm->tm_year+1900,
134                 .month = tm->tm_mon,
135                 .day   = tm->tm_mday-1,
136                 .hour  = tm->tm_hour,
137                 .min   = tm->tm_min,
138                 .sec   = tm->tm_sec,
139         };
140         return date;
141 }
142
143 stamp_t get_stamp(date_t date)
144 {
145         struct tm tm = {
146                 .tm_year = date.year-1900,
147                 .tm_mon  = date.month,
148                 .tm_mday = date.day+1,
149                 .tm_hour = date.hour,
150                 .tm_min  = date.min,
151                 .tm_sec  = date.sec,
152         };
153         time_t t = mktime(&tm);
154         return (stamp_t)t;
155 }
156
157 int get_mins(date_t *start, date_t *end)
158 {
159         return (get_stamp(*end)-get_stamp(*start))/60;
160 }
161
162 int get_secs(date_t *start, date_t *end)
163 {
164         return (get_stamp(*end)-get_stamp(*start));
165 }
166
167 int compare(date_t *a, date_t *b)
168 {
169         int rval = a->year  < b->year  ? -1 : a->year  > b->year  ? 1 :
170                    a->month < b->month ? -1 : a->month > b->month ? 1 :
171                    a->day   < b->day   ? -1 : a->day   > b->day   ? 1 :
172                    a->hour  < b->hour  ? -1 : a->hour  > b->hour  ? 1 :
173                    a->min   < b->min   ? -1 : a->min   > b->min   ? 1 : 0;
174         return rval;
175 }
176
177 int same_day(date_t *a, date_t *b)
178 {
179         return a->year  == b->year  &&
180                a->month == b->month &&
181                a->day   == b->day;
182 }
183
184 int before(date_t *start, int year, int month, int day, int hour, int min)
185 {
186         return compare(start, &(date_t){year, month, day, hour, min}) < 0;
187 }
188
189 int all_day(date_t *start, date_t *end)
190 {
191         date_t test = *start;
192         add_days(&test.year, &test.month, &test.day, 1);
193         return compare(&test, end) <= 0;
194 }
195
196 int no_date(date_t *date)
197 {
198         return date->year == 0;
199 }
200
201 /* Debug functions */
202 const char *month_to_str(month_t month)
203 {
204         static const char *map[] =
205                 { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
206                   "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", };
207         return map[month%12];
208 }
209 const char *month_to_string(month_t month)
210 {
211         static const char *map[] =
212                 { "January",   "February", "March",    "April",
213                   "May",       "June",     "July",     "August",
214                   "September", "October",  "November", "December" };
215         return map[month%12];
216 }
217
218 const char *day_to_st(wday_t day)
219 {
220         static const char *map[] =
221                 { "Su","Mo", "Tu", "We", "Th", "Fr", "Sa" };
222         return map[day%7];
223 }
224 const char *day_to_str(wday_t day)
225 {
226         static const char *map[] =
227                 { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
228         return map[day%7];
229 }
230 const char *day_to_string(wday_t day)
231 {
232         static const char *map[] =
233                 { "Sunday",   "Monday", "Tuesday", "Wednesday",
234                   "Thursday", "Friday", "Saturday" };
235         return map[day%7];
236 }
237
238 /* Test functions */
239 void date_test(void)
240 {
241         setenv("TZ", "US/Central", 1);
242
243         time_t  timet = time(NULL);
244         date_t  date  = get_date(timet);
245         stamp_t stamp = get_stamp(date);
246
247         printf("Time\n");
248         printf("  time  %ld\n",  timet);
249         printf("  stamp %lld\n", stamp);
250         printf("  date  %04d-%02d-%02d %02d:%02d %02ds\n",
251                         date.year, date.month, date.day,
252                         date.hour, date.min,   date.sec);
253
254         printf("Info\n");
255         printf("  Year   Month       Start   Weeks   Days\n");
256         for (int y = 2012; y <= 2012; y++)
257         for (int m = JAN;  m <= DEC;  m++) {
258                 printf("  %-5d",  y);
259                 printf("  %-10s", month_to_string(m));
260                 printf("  %-6s",  day_to_str(start_of_month(y,m)));
261                 printf("  %-6d",  weeks_in_month(y,m));
262                 printf("  %-2d",  days_in_month(y,m));
263                 printf("\n");
264         }
265 }