Initialize Tizen 2.3
[external/shadow-utils.git] / libmisc / strtoday.c
1 /*
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
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
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.
19  *
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.
31  */
32
33 #if !defined(__GLIBC__)
34 #define _XOPEN_SOURCE 500
35 #endif
36
37 #include <config.h>
38
39 #ident "$Id: strtoday.c 2139 2008-06-13 19:48:11Z nekral-guest $"
40
41 #include "defines.h"
42 #include "prototypes.h"
43
44 #ifndef USE_GETDATE
45 #define USE_GETDATE 1
46 #endif
47 #if USE_GETDATE
48 #include "getdate.h"
49 /*
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.
56  *      24 September 1972
57  *      24 Sept 72      # September has a special abbreviation.
58  *      24 Sep 72       # Three-letter abbreviations always allowed.
59  *      Sep 24, 1972
60  *      24-sep-72
61  *      24sep72
62  */
63 long strtoday (const char *str)
64 {
65         time_t t;
66
67         /*
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)
71          */
72         if ((NULL == str) || ('\0' == *str)) {
73                 return -1;
74         }
75
76         t = get_date (str, (time_t *) 0);
77         if ((time_t) - 1 == t) {
78                 return -1;
79         }
80         /* convert seconds to days since 1970-01-01 */
81         return (long) (t + DAY / 2) / DAY;
82 }
83
84 #else                           /* !USE_GETDATE */
85 /*
86  * Old code, just in case get_date() doesn't work as expected...
87  */
88 #include <stdio.h>
89 #ifdef HAVE_STRPTIME
90 /*
91  * for now we allow just one format, but we can define more later
92  * (we try them all until one succeeds).  --marekm
93  */
94 static char *date_formats[] = {
95         "%Y-%m-%d",
96         (char *) 0
97 };
98 #else
99 /*
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.
103  */
104 static short days[13] = { 0,
105         31, 28, 31, 30, 31, 30, /* JAN - JUN */
106         31, 31, 30, 31, 30, 31
107 };                              /* JUL - DEC */
108
109 static short juldays[13] = { 0,
110         0, 31, 59, 90, 120, 151,        /* JAN - JUN */
111         181, 212, 243, 273, 304, 334
112 };                              /* JUL - DEC */
113 #endif
114
115 /*
116  * strtoday - compute the number of days since 1970.
117  *
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.
121  */
122
123 long strtoday (const char *str)
124 {
125 #ifdef HAVE_STRPTIME
126         struct tm tp;
127         char *const *fmt;
128         char *cp;
129         time_t result;
130
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)) {
135                         continue;
136                 }
137
138                 result = mktime (&tp);
139                 if ((time_t) - 1 == result) {
140                         continue;
141                 }
142
143                 return (long) (result / DAY);   /* success */
144         }
145         return -1;
146 #else
147         char slop[2];
148         int month;
149         int day;
150         int year;
151         long total;
152
153         /*
154          * start by separating the month, day and year.  the order
155          * is compiled in ...
156          */
157
158         if (sscanf (str, "%d/%d/%d%c", &year, &month, &day, slop) != 3) {
159                 return -1;
160         }
161
162         /*
163          * the month, day of the month, and year are checked for
164          * correctness and the year adjusted so it falls between
165          * 1970 and 2069.
166          */
167
168         if ((month < 1) || (month > 12)) {
169                 return -1;
170         }
171
172         if (day < 1) {
173                 return -1;
174         }
175
176         if (   ((2 != month) || ((year % 4) != 0))
177             && (day > days[month])) {
178                 return -1;
179         } else if ((month == 2) && ((year % 4) == 0) && (day > 29)) {
180                 return -1;
181         }
182
183         if (year < 0) {
184                 return -1;
185         } else if (year <= 69) {
186                 year += 2000;
187         } else if (year <= 99) {
188                 year += 1900;
189         }
190
191         /*
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
196          */
197         if ((year < 1970) || (year > 2037)) {
198                 return -1;
199         }
200
201         /*
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.
206          */
207
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;
211
212         return total;
213 #endif                          /* HAVE_STRPTIME */
214 }
215 #endif                          /* !USE_GETDATE */