12 /* XXX struct tm on some systems (SunOS4/BSD) contains extra (non POSIX)
13 * fields for which we don't have Configure support prior to Perl 5.8.0:
14 * char *tm_zone; -- abbreviation of timezone name
15 * long tm_gmtoff; -- offset from GMT in seconds
16 * To workaround core dumps from the uninitialised tm_zone we get the
17 * system to give us a reasonable struct to copy. This fix means that
18 * strftime uses the tm_zone and tm_gmtoff values returned by
19 * localtime(time()). That should give the desired result most of the
20 * time. But probably not always!
22 * This is a vestigial workaround for Perls prior to 5.8.0. We now
23 * rely on the initialization (still likely a workaround) in util.c.
25 #if !defined(PERL_VERSION) || PERL_VERSION < 8
27 #if defined(HAS_GNULIBC)
28 # ifndef STRUCT_TM_HASZONE
29 # define STRUCT_TM_HASZONE
31 # define USE_TM_GMTOFF
35 #endif /* end of pre-5.8 */
37 #define DAYS_PER_YEAR 365
38 #define DAYS_PER_QYEAR (4*DAYS_PER_YEAR+1)
39 #define DAYS_PER_CENT (25*DAYS_PER_QYEAR-1)
40 #define DAYS_PER_QCENT (4*DAYS_PER_CENT+1)
41 #define SECS_PER_HOUR (60*60)
42 #define SECS_PER_DAY (24*SECS_PER_HOUR)
43 /* parentheses deliberately absent on these two, otherwise they don't work */
44 #define MONTH_TO_DAYS 153/5
45 #define DAYS_TO_MONTH 5/153
46 /* offset to bias by March (month 4) 1st between month/mday & year finding */
47 #define YEAR_ADJUST (4*MONTH_TO_DAYS+1)
48 /* as used here, the algorithm leaves Sunday as day 1 unless we adjust it */
49 #define WEEKDAY_BIAS 6 /* (1+6)%7 makes Sunday 0 again */
51 #if !defined(PERL_VERSION) || PERL_VERSION < 8
53 #ifdef STRUCT_TM_HASZONE
55 my_init_tm(struct tm *ptm) /* see mktime, strftime and asctime */
59 Copy(localtime(&now), ptm, 1, struct tm);
63 # define my_init_tm(ptm)
67 /* use core version from util.c in 5.8.0 and later */
68 # define my_init_tm init_tm
74 * (1) The CRT maintains its own copy of the environment, separate from
77 * (2) CRT getenv() retrieves from this copy. CRT putenv() updates this
78 * copy, and then calls SetEnvironmentVariableA() to update the Win32API
81 * (3) win32_getenv() and win32_putenv() call GetEnvironmentVariableA() and
82 * SetEnvironmentVariableA() directly, bypassing the CRT copy of the
85 * (4) The CRT strftime() "%Z" implementation calls __tzset(). That
86 * calls CRT tzset(), but only the first time it is called, and in turn
87 * that uses CRT getenv("TZ") to retrieve the timezone info from the CRT
88 * local copy of the environment and hence gets the original setting as
89 * perl never updates the CRT copy when assigning to $ENV{TZ}.
91 * Therefore, we need to retrieve the value of $ENV{TZ} and call CRT
92 * putenv() to update the CRT copy of the environment (if it is different)
93 * whenever we're about to call tzset().
95 * In addition to all that, when perl is built with PERL_IMPLICIT_SYS
98 * (a) Each interpreter has its own copy of the environment inside the
99 * perlhost structure. That allows applications that host multiple
100 * independent Perl interpreters to isolate environment changes from
101 * each other. (This is similar to how the perlhost mechanism keeps a
102 * separate working directory for each Perl interpreter, so that calling
103 * chdir() will not affect other interpreters.)
105 * (b) Only the first Perl interpreter instantiated within a process will
106 * "write through" environment changes to the process environment.
108 * (c) Even the primary Perl interpreter won't update the CRT copy of the
109 * the environment, only the Win32API copy (it calls win32_putenv()).
111 * As with CPerlHost::Getenv() and CPerlHost::Putenv() themselves, it makes
112 * sense to only update the process environment when inside the main
113 * interpreter, but we don't have access to CPerlHost's m_bTopLevel member
114 * from here so we'll just have to check PL_curinterp instead.
116 * Therefore, we can simply #undef getenv() and putenv() so that those names
117 * always refer to the CRT functions, and explicitly call win32_getenv() to
118 * access perl's %ENV.
120 * We also #undef malloc() and free() to be sure we are using the CRT
121 * functions otherwise under PERL_IMPLICIT_SYS they are redefined to calls
122 * into VMem::Malloc() and VMem::Free() and all allocations will be freed
123 * when the Perl interpreter is being destroyed so we'd end up with a pointer
124 * into deallocated memory in environ[] if a program embedding a Perl
125 * interpreter continues to operate even after the main Perl interpreter has
128 * Note that we don't free() the malloc()ed memory unless and until we call
129 * malloc() again ourselves because the CRT putenv() function simply puts its
130 * pointer argument into the environ[] arrary (it doesn't make a copy of it)
131 * so this memory must otherwise be leaked.
140 fix_win32_tzenv(void)
142 static char* oldenv = NULL;
144 const char* perl_tz_env = win32_getenv("TZ");
145 const char* crt_tz_env = getenv("TZ");
146 if (perl_tz_env == NULL)
148 if (crt_tz_env == NULL)
150 if (strcmp(perl_tz_env, crt_tz_env) != 0) {
151 newenv = (char*)malloc((strlen(perl_tz_env) + 4) * sizeof(char));
152 if (newenv != NULL) {
153 sprintf(newenv, "TZ=%s", perl_tz_env);
168 #if defined(USE_ITHREADS) && defined(PERL_IMPLICIT_SYS)
169 if (PL_curinterp == aTHX)
177 * my_mini_mktime - normalise struct tm values without the localtime()
178 * semantics (and overhead) of mktime(). Stolen shamelessly from Perl's
179 * Perl_mini_mktime() in util.c - for details on the algorithm, see that
183 my_mini_mktime(struct tm *ptm)
187 int month, mday, year, jday;
188 int odd_cent, odd_year;
190 year = 1900 + ptm->tm_year;
193 /* allow given yday with no month & mday to dominate the result */
194 if (ptm->tm_yday >= 0 && mday <= 0 && month <= 0) {
197 jday = 1 + ptm->tm_yday;
207 yearday = DAYS_PER_YEAR * year + year/4 - year/100 + year/400;
208 yearday += month*MONTH_TO_DAYS + mday + jday;
210 * Note that we don't know when leap-seconds were or will be,
211 * so we have to trust the user if we get something which looks
212 * like a sensible leap-second. Wild values for seconds will
213 * be rationalised, however.
215 if ((unsigned) ptm->tm_sec <= 60) {
222 secs += 60 * ptm->tm_min;
223 secs += SECS_PER_HOUR * ptm->tm_hour;
225 if (secs-(secs/SECS_PER_DAY*SECS_PER_DAY) < 0) {
226 /* got negative remainder, but need positive time */
227 /* back off an extra day to compensate */
228 yearday += (secs/SECS_PER_DAY)-1;
229 secs -= SECS_PER_DAY * (secs/SECS_PER_DAY - 1);
232 yearday += (secs/SECS_PER_DAY);
233 secs -= SECS_PER_DAY * (secs/SECS_PER_DAY);
236 else if (secs >= SECS_PER_DAY) {
237 yearday += (secs/SECS_PER_DAY);
238 secs %= SECS_PER_DAY;
240 ptm->tm_hour = secs/SECS_PER_HOUR;
241 secs %= SECS_PER_HOUR;
242 ptm->tm_min = secs/60;
245 /* done with time of day effects */
247 * The algorithm for yearday has (so far) left it high by 428.
248 * To avoid mistaking a legitimate Feb 29 as Mar 1, we need to
249 * bias it by 123 while trying to figure out what year it
250 * really represents. Even with this tweak, the reverse
251 * translation fails for years before A.D. 0001.
252 * It would still fail for Feb 29, but we catch that one below.
254 jday = yearday; /* save for later fixup vis-a-vis Jan 1 */
255 yearday -= YEAR_ADJUST;
256 year = (yearday / DAYS_PER_QCENT) * 400;
257 yearday %= DAYS_PER_QCENT;
258 odd_cent = yearday / DAYS_PER_CENT;
259 year += odd_cent * 100;
260 yearday %= DAYS_PER_CENT;
261 year += (yearday / DAYS_PER_QYEAR) * 4;
262 yearday %= DAYS_PER_QYEAR;
263 odd_year = yearday / DAYS_PER_YEAR;
265 yearday %= DAYS_PER_YEAR;
266 if (!yearday && (odd_cent==4 || odd_year==4)) { /* catch Feb 29 */
271 yearday += YEAR_ADJUST; /* recover March 1st crock */
272 month = yearday*DAYS_TO_MONTH;
273 yearday -= month*MONTH_TO_DAYS;
274 /* recover other leap-year adjustment */
283 ptm->tm_year = year - 1900;
285 ptm->tm_mday = yearday;
290 ptm->tm_mon = month - 1;
292 /* re-build yearday based on Jan 1 to get tm_yday */
294 yearday = year*DAYS_PER_YEAR + year/4 - year/100 + year/400;
295 yearday += 14*MONTH_TO_DAYS + 1;
296 ptm->tm_yday = jday - yearday;
297 /* fix tm_wday if not overridden by caller */
298 ptm->tm_wday = (jday + WEEKDAY_BIAS) % 7;
302 /* Assume everyone has strptime except Win32 and QNX4 */
303 # define HAS_STRPTIME 1
304 # if defined(WIN32) || (defined(__QNX__) && defined(__WATCOMC__))
310 #define strncasecmp(x,y,n) strnicmp(x,y,n)
313 #if defined(__BORLANDC__)
314 void * __cdecl _EXPFUNC alloca(_SIZE_T __size);
316 #define alloca _alloca
320 /* strptime copied from freebsd with the following copyright: */
322 * Copyright (c) 1994 Powerdog Industries. All rights reserved.
324 * Redistribution and use in source and binary forms, with or without
325 * modification, are permitted provided that the following conditions
327 * 1. Redistributions of source code must retain the above copyright
328 * notice, this list of conditions and the following disclaimer.
329 * 2. Redistributions in binary form must reproduce the above copyright
330 * notice, this list of conditions and the following disclaimer
331 * in the documentation and/or other materials provided with the
333 * 3. All advertising materials mentioning features or use of this
334 * software must display the following acknowledgement:
335 * This product includes software developed by Powerdog Industries.
336 * 4. The name of Powerdog Industries may not be used to endorse or
337 * promote products derived from this software without specific prior
338 * written permission.
340 * THIS SOFTWARE IS PROVIDED BY POWERDOG INDUSTRIES ``AS IS'' AND ANY
341 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
342 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
343 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE POWERDOG INDUSTRIES BE
344 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
345 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
346 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
347 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
348 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
349 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
350 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
355 static char copyright[] =
356 "@(#) Copyright (c) 1994 Powerdog Industries. All rights reserved.";
357 static char sccsid[] = "@(#)strptime.c 0.1 (Powerdog) 94/03/27";
358 #endif /* !defined NOID */
359 #endif /* not lint */
366 #include "pthread_private.h"
367 #endif /* _THREAD_SAFE */
369 static char * _strptime(pTHX_ const char *, const char *, struct tm *);
372 static struct pthread_mutex _gotgmt_mutexd = PTHREAD_MUTEX_STATIC_INITIALIZER;
373 static pthread_mutex_t gotgmt_mutex = &_gotgmt_mutexd;
377 #define asizeof(a) (sizeof (a) / sizeof ((a)[0]))
380 const char * mon[12];
381 const char * month[12];
382 const char * wday[7];
383 const char * weekday[7];
389 const char * date_fmt;
390 const char * alt_month[12];
395 struct lc_time_T _time_localebuf;
396 int _time_using_locale;
398 const struct lc_time_T _C_time_locale = {
400 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
401 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
403 "January", "February", "March", "April", "May", "June",
404 "July", "August", "September", "October", "November", "December"
406 "Sun", "Mon", "Tue", "Wed",
409 "Sunday", "Monday", "Tuesday", "Wednesday",
410 "Thursday", "Friday", "Saturday"
418 ** Since the C language standard calls for
419 ** "date, using locale's date format," anything goes.
420 ** Using just numbers (as here) makes Quakers happier;
421 ** it's also compatible with SVR4.
426 ** c_fmt (ctime-compatible)
427 ** Not used, just compatibility placeholder.
441 "January", "February", "March", "April", "May", "June",
442 "July", "August", "September", "October", "November", "December"
446 ** To determine short months / day order
451 ** To determine long months / day order
456 #define Locale (&_C_time_locale)
459 _strptime(pTHX_ const char *buf, const char *fmt, struct tm *tm)
465 int Ealternative, Oalternative;
475 if (isspace((unsigned char)c))
476 while (*buf != 0 && isspace((unsigned char)*buf))
478 else if (c != *buf++)
495 buf = _strptime(aTHX_ buf, Locale->date_fmt, tm);
501 if (!isdigit((unsigned char)*buf))
504 /* XXX This will break for 3-digit centuries. */
506 for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
514 tm->tm_year = i * 100 - 1900;
518 /* NOTE: c_fmt is intentionally ignored */
519 buf = _strptime(aTHX_ buf, "%a %Ef %T %Y", tm);
525 buf = _strptime(aTHX_ buf, "%m/%d/%y", tm);
531 if (Ealternative || Oalternative)
537 if (Ealternative || Oalternative)
546 buf = _strptime(aTHX_ buf, (c == 'f') ? Locale->Ef_fmt : Locale->EF_fmt, tm);
552 buf = _strptime(aTHX_ buf, "%H:%M", tm);
558 buf = _strptime(aTHX_ buf, "%I:%M:%S %p", tm);
564 buf = _strptime(aTHX_ buf, "%H:%M:%S", tm);
570 buf = _strptime(aTHX_ buf, Locale->X_fmt, tm);
576 buf = _strptime(aTHX_ buf, Locale->x_fmt, tm);
582 if (!isdigit((unsigned char)*buf))
586 for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
591 if (i < 1 || i > 366)
599 if (*buf == 0 || isspace((unsigned char)*buf))
602 if (!isdigit((unsigned char)*buf))
606 for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
622 if (*buf != 0 && isspace((unsigned char)*buf))
623 while (*ptr != 0 && !isspace((unsigned char)*ptr))
632 * Of these, %l is the only specifier explicitly
633 * documented as not being zero-padded. However,
634 * there is no harm in allowing zero-padding.
636 * XXX The %l specifier may gobble one too many
637 * digits if used incorrectly.
639 if (!isdigit((unsigned char)*buf))
643 for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
648 if (c == 'H' || c == 'k') {
656 if (*buf != 0 && isspace((unsigned char)*buf))
657 while (*ptr != 0 && !isspace((unsigned char)*ptr))
663 * XXX This is bogus if parsed before hour-related
666 len = strlen(Locale->am);
667 if (strncasecmp(buf, Locale->am, len) == 0) {
668 if (tm->tm_hour > 12)
670 if (tm->tm_hour == 12)
676 len = strlen(Locale->pm);
677 if (strncasecmp(buf, Locale->pm, len) == 0) {
678 if (tm->tm_hour > 12)
680 if (tm->tm_hour != 12)
690 for (i = 0; i < asizeof(Locale->weekday); i++) {
692 len = strlen(Locale->weekday[i]);
698 len = strlen(Locale->wday[i]);
705 if (i == asizeof(Locale->weekday))
715 * XXX This is bogus, as we can not assume any valid
716 * information present in the tm structure at this
717 * point to calculate a real value, so just check the
720 if (!isdigit((unsigned char)*buf))
724 for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
732 if (*buf != 0 && isspace((unsigned char)*buf))
733 while (*ptr != 0 && !isspace((unsigned char)*ptr))
738 if (!isdigit((unsigned char)*buf))
747 if (*buf != 0 && isspace((unsigned char)*buf))
748 while (*ptr != 0 && !isspace((unsigned char)*ptr))
755 * The %e specifier is explicitly documented as not
756 * being zero-padded but there is no harm in allowing
759 * XXX The %e specifier may gobble one too many
760 * digits if used incorrectly.
762 if (!isdigit((unsigned char)*buf))
766 for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
776 if (*buf != 0 && isspace((unsigned char)*buf))
777 while (*ptr != 0 && !isspace((unsigned char)*ptr))
784 for (i = 0; i < asizeof(Locale->month); i++) {
787 len = strlen(Locale->alt_month[i]);
789 Locale->alt_month[i],
795 len = strlen(Locale->month[i]);
801 len = strlen(Locale->mon[i]);
809 if (i == asizeof(Locale->month))
817 if (!isdigit((unsigned char)*buf))
821 for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
831 if (*buf != 0 && isspace((unsigned char)*buf))
832 while (*ptr != 0 && !isspace((unsigned char)*ptr))
838 if (*buf == 0 || isspace((unsigned char)*buf))
841 if (!isdigit((unsigned char)*buf))
844 len = (c == 'Y') ? 4 : 2;
845 for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
852 if (c == 'y' && i < 69)
859 if (*buf != 0 && isspace((unsigned char)*buf))
860 while (*ptr != 0 && !isspace((unsigned char)*ptr))
869 for (cp = buf; *cp && isupper((unsigned char)*cp); ++cp)
872 zonestr = (char *)alloca(cp - buf + 1);
873 strncpy(zonestr, buf, cp - buf);
874 zonestr[cp - buf] = '\0';
876 if (0 == strcmp(zonestr, "GMT")) {
892 strptime(pTHX_ const char *buf, const char *fmt, struct tm *tm)
897 pthread_mutex_lock(&gotgmt_mutex);
901 ret = _strptime(aTHX_ buf, fmt, tm);
904 pthread_mutex_unlock(&gotgmt_mutex);
910 #endif /* !HAS_STRPTIME */
912 MODULE = Time::Piece PACKAGE = Time::Piece
917 _strftime(fmt, sec, min, hour, mday, mon, year, wday = -1, yday = -1, isdst = -1)
933 memset(&mytm, 0, sizeof(mytm));
934 my_init_tm(&mytm); /* XXX workaround - see my_init_tm() above */
943 mytm.tm_isdst = isdst;
944 my_mini_mktime(&mytm);
945 len = strftime(tmpbuf, sizeof tmpbuf, fmt, &mytm);
947 ** The following is needed to handle to the situation where
948 ** tmpbuf overflows. Basically we want to allocate a buffer
949 ** and try repeatedly. The reason why it is so complicated
950 ** is that getting a return value of 0 from strftime can indicate
951 ** one of the following:
952 ** 1. buffer overflowed,
953 ** 2. illegal conversion specifier, or
954 ** 3. the format string specifies nothing to be returned(not
955 ** an error). This could be because format is an empty string
956 ** or it specifies %p that yields an empty string in some locale.
957 ** If there is a better way to make it portable, go ahead by
960 if ((len > 0 && len < sizeof(tmpbuf)) || (len == 0 && *fmt == '\0'))
961 ST(0) = sv_2mortal(newSVpv(tmpbuf, len));
963 /* Possibly buf overflowed - try again with a bigger buf */
964 int fmtlen = strlen(fmt);
965 int bufsize = fmtlen + sizeof(tmpbuf);
969 New(0, buf, bufsize, char);
971 buflen = strftime(buf, bufsize, fmt, &mytm);
972 if (buflen > 0 && buflen < bufsize)
974 /* heuristic to prevent out-of-memory errors */
975 if (bufsize > 100*fmtlen) {
981 Renew(buf, bufsize, char);
984 ST(0) = sv_2mortal(newSVpv(buf, buflen));
988 ST(0) = sv_2mortal(newSVpv(tmpbuf, len));
999 _strptime ( string, format )
1010 remainder = (char *)strptime(string, format, &mytm);
1012 remainder = (char *)strptime(aTHX_ string, format, &mytm);
1014 if (remainder == NULL) {
1015 croak("Error parsing time");
1017 if (*remainder != '\0') {
1018 warn("garbage at end of string in strptime: %s", remainder);
1021 my_mini_mktime(&mytm);
1023 /* warn("tm: %d-%d-%d %d:%d:%d\n", mytm.tm_year, mytm.tm_mon, mytm.tm_mday, mytm.tm_hour, mytm.tm_min, mytm.tm_sec); */
1026 PUSHs(sv_2mortal(newSViv(mytm.tm_sec)));
1027 PUSHs(sv_2mortal(newSViv(mytm.tm_min)));
1028 PUSHs(sv_2mortal(newSViv(mytm.tm_hour)));
1029 PUSHs(sv_2mortal(newSViv(mytm.tm_mday)));
1030 PUSHs(sv_2mortal(newSViv(mytm.tm_mon)));
1031 PUSHs(sv_2mortal(newSViv(mytm.tm_year)));
1032 PUSHs(sv_2mortal(newSViv(mytm.tm_wday)));
1033 PUSHs(sv_2mortal(newSViv(mytm.tm_yday)));
1035 PUSHs(sv_2mortal(newSViv(0)));
1037 PUSHs(sv_2mortal(newSViv(0)));
1039 PUSHs(sv_2mortal(newSViv(0)));
1042 _mini_mktime(int sec, int min, int hour, int mday, int mon, int year)
1052 mytm.tm_hour = hour;
1053 mytm.tm_mday = mday;
1055 mytm.tm_year = year;
1057 my_mini_mktime(&mytm);
1060 PUSHs(sv_2mortal(newSViv(mytm.tm_sec)));
1061 PUSHs(sv_2mortal(newSViv(mytm.tm_min)));
1062 PUSHs(sv_2mortal(newSViv(mytm.tm_hour)));
1063 PUSHs(sv_2mortal(newSViv(mytm.tm_mday)));
1064 PUSHs(sv_2mortal(newSViv(mytm.tm_mon)));
1065 PUSHs(sv_2mortal(newSViv(mytm.tm_year)));
1066 PUSHs(sv_2mortal(newSViv(mytm.tm_wday)));
1067 PUSHs(sv_2mortal(newSViv(mytm.tm_yday)));
1069 PUSHs(sv_2mortal(newSViv(0)));
1071 PUSHs(sv_2mortal(newSViv(0)));
1073 PUSHs(sv_2mortal(newSViv(0)));