1 /* $Id: date.c,v 1.3 2002/03/02 21:31:53 sverrehu Exp $ */
2 /*------------------------------------------------------------------------
3 | FILE date.c
4 | MODULE OF biorythm - simple biorythm calculation program
5 |
6 | DESCRIPTION Routines handling dates.
7 |
8 | WRITTEN BY Sverre H. Huseby <shh@thathost.com>
9 +----------------------------------------------------------------------*/
10
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <string.h>
14
15 #include <shhmsg.h>
16
17 #include "date.h"
18
19 /*-----------------------------------------------------------------------+
20 | PUBLIC FUNCTIONS |
21 +-----------------------------------------------------------------------*/
22
23 /*------------------------------------------------------------------------
24 | NAME dateSet
25 |
26 | FUNCTION Set the elements of a date.
27 |
28 | INPUT year the year (full year, like 1996).
29 | month the month (1-12).
30 | day the day (1-31).
31 |
32 | OUTPUT date the filled in date.
33 */
34 void
dateSet(Date * date,int year,int month,int day)35 dateSet(Date *date, int year, int month, int day)
36 {
37 date->year = year;
38 date->month = month;
39 date->day = day;
40 }
41
42 /*------------------------------------------------------------------------
43 | NAME dateGet
44 |
45 | FUNCTION Get the elements of a date.
46 |
47 | INPUT date the filled in date.
48 |
49 | OUTPUT year the year (full year, like 1996).
50 | month the month (1-12).
51 | day the day (1-31).
52 */
53 void
dateGet(Date date,int * year,int * month,int * day)54 dateGet(Date date, int *year, int *month, int *day)
55 {
56 *year = date.year;
57 *month = date.month;
58 *day = date.day;
59 }
60
61 /*------------------------------------------------------------------------
62 | NAME dateIsLeapYear
63 |
64 | FUNCTION Determine whether a given year is a leapyear.
65 |
66 | INPUT year the year to test.
67 |
68 | RETURNS boolean value. 1=leapyear.
69 */
70 int
dateIsLeapYear(int year)71 dateIsLeapYear(int year)
72 {
73 return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
74 }
75
76 /*------------------------------------------------------------------------
77 | NAME dateDaysInMonth
78 |
79 | FUNCTION Get number of days in a month.
80 |
81 | INPUT month the month; (1..12)
82 | year the year to test. (full year, like 1996)
83 |
84 | RETURNS boolean value. 1=leapyear.
85 */
86 int
dateDaysInMonth(int month,int year)87 dateDaysInMonth(int month, int year)
88 {
89 static int vec[] = { -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
90
91 if (month == 2)
92 return 28 + dateIsLeapYear(year);
93 return vec[month];
94 }
95
96 /*------------------------------------------------------------------------
97 | NAME dateGetNumDays
98 |
99 | FUNCTION Get number of days from one date to another.
100 |
101 | INPUT d0 the start date.
102 | d1 the end date.
103 |
104 | RETURNS Number of days. Examples:
105 | days are equal; returns 0.
106 | d1 is the day after d0; returns 1.
107 | d1 is the before after d0; returns -1.
108 */
109 int
dateGetNumDays(Date d0,Date d1)110 dateGetNumDays(Date d0, Date d1)
111 {
112 int q, negate = 0, ret = 0;
113 Date tmp;
114
115 if (d0.year > d1.year
116 || (d0.year == d1.year && d0.month > d1.month)
117 || (d0.year == d1.year && d0.month == d1.month && d0.day > d1.day)) {
118 negate = 1;
119 tmp = d0;
120 d0 = d1;
121 d1 = tmp;
122 }
123
124 /* Count the days in all years _between_ the two given years. */
125 for (q = d0.year + 1; q < d1.year; q++)
126 ret += 365 + dateIsLeapYear(q);
127
128 /* */
129 if (d0.year != d1.year) {
130 /* The years are not the same. */
131 /* Add number of days left in first year. */
132 ret += dateDaysInMonth(d0.month, d0.year) - d0.day;
133 for (q = d0.month + 1; q <= 12; q++)
134 ret += dateDaysInMonth(q, d0.year);
135 /* Add number of days `used' in second year. */
136 for (q = 1; q < d1.month; q++)
137 ret += dateDaysInMonth(q, d1.year);
138 ret += d1.day;
139 } else {
140 /* The years are the same. */
141 /* Count the days in all months _between_ the two given months. */
142 for (q = d0.month + 1; q < d1.month; q++)
143 ret += dateDaysInMonth(q, d0.year);
144 /* Add the days in each month. */
145 if (d0.month == d1.month)
146 ret += d1.day - d0.day;
147 else {
148 ret += dateDaysInMonth(d0.month, d0.year) - d0.day;
149 ret += d1.day;
150 }
151 }
152 return negate ? -ret : ret;
153 }
154
155 /*------------------------------------------------------------------------
156 | NAME dateInc
157 |
158 | FUNCTION Increase a date.
159 |
160 | INPUT date the date to increase.
161 |
162 | OUTPUT date the ncreased date.
163 */
164 void
dateInc(Date * date)165 dateInc(Date *date)
166 {
167 if (date->day < dateDaysInMonth(date->month, date->year))
168 ++date->day;
169 else {
170 date->day = 1;
171 if (date->month < 12)
172 ++date->month;
173 else {
174 date->month = 1;
175 ++date->year;
176 }
177 }
178 }
179
180 /*------------------------------------------------------------------------
181 | NAME dateStr
182 |
183 | FUNCTION Get a string representation of a date.
184 |
185 | INPUT date the date to represent as a string.
186 |
187 | RETURNS The date as a string.
188 */
189 char *
dateStr(Date date)190 dateStr(Date date)
191 {
192 static char ret[21];
193
194 sprintf(ret, "%4d-%02d-%02d", date.year, date.month, date.day);
195 return ret;
196 }
197
198 /*------------------------------------------------------------------------
199 | NAME dateFromStr
200 |
201 | FUNCTION Convert a string to a date.
202 |
203 | INPUT s a string of the form YYYY-MM-DD
204 |
205 | RETURNS The date. Aborts if the date is illegal.
206 */
207 Date
dateFromStr(const char * s)208 dateFromStr(const char *s)
209 {
210 Date ret;
211 char *p, *s2;
212
213 if ((s2 = strdup(s)) == NULL)
214 msgFatal("out of memory\n");
215
216 if ((p = strtok(s2, "/-:.")) == NULL)
217 msgFatal("%s is not on the form YYYY-MM-DD\n", s);
218 ret.year = atoi(p);
219
220 if ((p = strtok(NULL, "/-:.")) == NULL)
221 msgFatal("%s is not on the form YYYY-MM-DD\n", s);
222 ret.month = atoi(p);
223 if (ret.month < 1 || ret.month > 12)
224 msgFatal("illegal month in %s (YYYY-MM-DD)\n", s);
225
226 if ((p = strtok(NULL, "/-:.")) == NULL)
227 msgFatal("%s is not on the form YYYY-MM-DD\n", s);
228 ret.day = atoi(p);
229 if (ret.day < 1 || ret.day > dateDaysInMonth(ret.month, ret.year))
230 msgFatal("illegal day in %s (YYYY-MM-DD)\n", s);
231
232 free(s2);
233 return ret;
234 }
235