2 * Copyright (c) 1991 - 1994, Julianne Frances Haugh
3 * Copyright (c) 1996 - 1999, Marek Michałkiewicz
4 * Copyright (c) 2003 - 2005, Tomasz Kłoczko
5 * Copyright (c) 2008 , Nicolas François
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the copyright holders or contributors may not be used to
17 * endorse or promote products derived from this software without
18 * specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #if !defined(__GLIBC__)
34 #define _XOPEN_SOURCE 500
39 #ident "$Id: strtoday.c 2139 2008-06-13 19:48:11Z nekral-guest $"
42 #include "prototypes.h"
50 * strtoday() now uses get_date() (borrowed from GNU shellutils)
51 * which can handle many date formats, for example:
52 * 1970-09-17 # ISO 8601.
53 * 70-9-17 # This century assumed by default.
54 * 70-09-17 # Leading zeros are ignored.
55 * 9/17/72 # Common U.S. writing.
57 * 24 Sept 72 # September has a special abbreviation.
58 * 24 Sep 72 # Three-letter abbreviations always allowed.
63 long strtoday (const char *str)
68 * get_date() interprets an empty string as the current date,
69 * which is not what we expect, unless you're a BOFH :-).
70 * (useradd sets sp_expire = current date for new lusers)
72 if ((NULL == str) || ('\0' == *str)) {
76 t = get_date (str, (time_t *) 0);
77 if ((time_t) - 1 == t) {
80 /* convert seconds to days since 1970-01-01 */
81 return (long) (t + DAY / 2) / DAY;
84 #else /* !USE_GETDATE */
86 * Old code, just in case get_date() doesn't work as expected...
91 * for now we allow just one format, but we can define more later
92 * (we try them all until one succeeds). --marekm
94 static char *date_formats[] = {
100 * days and juldays are used to compute the number of days in the
101 * current month, and the cummulative number of days in the preceding
102 * months. they are declared so that january is 1, not 0.
104 static short days[13] = { 0,
105 31, 28, 31, 30, 31, 30, /* JAN - JUN */
106 31, 31, 30, 31, 30, 31
109 static short juldays[13] = { 0,
110 0, 31, 59, 90, 120, 151, /* JAN - JUN */
111 181, 212, 243, 273, 304, 334
116 * strtoday - compute the number of days since 1970.
118 * the total number of days prior to the current date is
119 * computed. january 1, 1970 is used as the origin with
120 * it having a day number of 0.
123 long strtoday (const char *str)
131 memzero (&tp, sizeof tp);
132 for (fmt = date_formats; *fmt; fmt++) {
133 cp = strptime ((char *) str, *fmt, &tp);
134 if ((NULL == cp) || ('\0' != *cp)) {
138 result = mktime (&tp);
139 if ((time_t) - 1 == result) {
143 return (long) (result / DAY); /* success */
154 * start by separating the month, day and year. the order
158 if (sscanf (str, "%d/%d/%d%c", &year, &month, &day, slop) != 3) {
163 * the month, day of the month, and year are checked for
164 * correctness and the year adjusted so it falls between
168 if ((month < 1) || (month > 12)) {
176 if ( ((2 != month) || ((year % 4) != 0))
177 && (day > days[month])) {
179 } else if ((month == 2) && ((year % 4) == 0) && (day > 29)) {
185 } else if (year <= 69) {
187 } else if (year <= 99) {
192 * On systems with 32-bit signed time_t, time wraps around in 2038
193 * - for now we just limit the year to 2037 (instead of 2069).
194 * This limit can be removed once no one is using 32-bit systems
195 * anymore :-). --marekm
197 if ((year < 1970) || (year > 2037)) {
202 * the total number of days is the total number of days in all
203 * the whole years, plus the number of leap days, plus the
204 * number of days in the whole months preceding, plus the number
205 * of days so far in the month.
208 total = (long) ((year - 1970) * 365L) + (((year + 1) - 1970) / 4);
209 total += (long) juldays[month] + (month > 2 && (year % 4) == 0 ? 1 : 0);
210 total += (long) day - 1;
213 #endif /* HAVE_STRPTIME */
215 #endif /* !USE_GETDATE */