1 /*
2 Anacron - run commands periodically
3 Copyright (C) 1998 Itai Tzur <itzur@actcom.co.il>
4 Copyright (C) 1999 Sean 'Shaleh' Perry <shaleh@debian.org>
5 Copyright (C) 2004 Pascal Hakim <pasc@redellipse.net>
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License along
18 with this program; if not, write to the Free Software Foundation, Inc.,
19 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
21 The GNU General Public License can also be found in the file
22 `COPYING' that comes with the Anacron source distribution.
23 */
24
25
26 #include <limits.h>
27 #include <time.h>
28 #include "gregor.h"
29
30 static const int
31 days_in_month[] = {
32 31, /* Jan */
33 28, /* Feb (non-leap) */
34 31, /* Mar */
35 30, /* Apr */
36 31, /* May */
37 30, /* Jun */
38 31, /* Jul */
39 31, /* Aug */
40 30, /* Sep */
41 31, /* Oct */
42 30, /* Nov */
43 31 /* Dec */
44 };
45
46 static int leap(int year);
47
48 int
49 day_num(int year, int month, int day)
/* ![[previous]](../icons/n_left.png)
![[next]](../icons/right.png)
![[first]](../icons/n_first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
50 /* Return the "day number" of the date year-month-day according to the
51 * "proleptic Gregorian calendar".
52 * If the given date is invalid, return -1.
53 *
54 * Here, "day number" is defined as the number of days since December 31,
55 * 1 B.C. (Gregorian). (January 1, 1 A.D. is day number 1 etc...)
56 *
57 * The Gregorian calendar was instituted by Pope Gregory XIII in 1582,
58 * and has gradually spread to become the international standard calendar.
59 * The proleptic Gregorian calendar is formed by projecting the date system
60 * of the Gregorian calendar to dates before its adoption.
61 *
62 * For more details, see:
63 * http://astro.nmsu.edu/~lhuber/leaphist.html
64 * http://www.magnet.ch/serendipity/hermetic/cal_stud/cal_art.htm
65 * and your local library.
66 */
67 {
68 int dn;
69 int i;
70 int isleap; /* save three calls to leap() */
71
72 /* Some validity checks */
73
74 /* we don't deal with B.C. years here */
75 if (year < 1) return - 1;
76 /* conservative overflow estimate */
77 if (year > (INT_MAX / 366)) return - 1;
78 if (month > 12 || month < 1) return - 1;
79 if (day < 1) return - 1;
80
81 isleap = leap(year);
82
83 if (month != 2) {
84 if(day > days_in_month[month - 1]) return - 1;
85 }
86 else if ((isleap && day > 29) || (!isleap && day > 28))
87 return - 1;
88
89 /* First calculate the day number of December 31 last year */
90
91 /* save us from doing (year - 1) over and over */
92 i = year - 1;
93 /* 365 days in a "regular" year + number of leap days */
94 dn = (i * 365) + ((i / 4) - (i / 100) + (i / 400));
95
96 /* Now, day number of the last day of the previous month */
97
98 for (i = month - 1; i > 0; --i)
99 dn += days_in_month[i - 1];
100 /* Add 29 February ? */
101 if (month > 2 && isleap) ++dn;
102
103 /* How many days into month are we */
104
105 dn += day;
106
107 return dn;
108 }
109
110 static int
111 leap(int year)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
112 /* Is this a leap year ? */
113 {
114 /* every year exactly divisible by 4 is "leap" */
115 /* unless it is exactly divisible by 100 */
116 /* but not by 400 */
117 return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
118 }
119
120 int
121 days_last_month (void)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
122 /* How many days did last month have? */
123 {
124 struct tm time_record;
125 time_t current_time;
126 time (¤t_time);
127 localtime_r (¤t_time, &time_record);
128
129 switch (time_record.tm_mon) {
130 case 0: return days_in_month[11];
131 case 2: return days_in_month[1] + (leap (time_record.tm_year + 1900) ? 1 : 0);
132 default: return days_in_month[time_record.tm_mon - 1];
133 }
134 }
135
136 int
137 days_this_month (void)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
138 /* How many days does this month have? */
139 {
140 struct tm time_record;
141 time_t current_time;
142 time (¤t_time);
143 localtime_r (¤t_time, &time_record);
144
145 switch (time_record.tm_mon) {
146 case 1: return days_in_month[1] + (leap (time_record.tm_year + 1900) ? 1 : 0);
147 default: return days_in_month[time_record.tm_mon];
148 }
149 }
150
151 int
152 days_last_year (void)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
153 /* How many days this last year have? */
154 {
155 struct tm time_record;
156 time_t current_time;
157 time (¤t_time);
158 localtime_r (¤t_time, &time_record);
159
160 if (leap(time_record.tm_year - 1 + 1900)) {
161 return 366;
162 }
163
164 return 365;
165 }
166
167 int
168 days_this_year (void)
/* ![[previous]](../icons/left.png)
![[next]](../icons/n_right.png)
![[first]](../icons/first.png)
![[last]](../icons/n_last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
169 /* How many days does this year have */
170 {
171 struct tm time_record;
172 time_t current_time;
173 time (¤t_time);
174 localtime_r (¤t_time, &time_record);
175
176 if (leap(time_record.tm_year + 1900)) {
177 return 366;
178 }
179
180 return 365;
181 }