12 /* XXX struct tm on some systems (SunOS4/BSD) contains extra (non POSIX)
13 * fields for which we don't have Configure support yet:
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 temporary workaround to be removed once Configure
23 * support is added and NETaa14816 is considered in full.
24 * It does not address tzname aspects of NETaa14816.
26 #if !defined(HAS_GNULIBC)
27 # ifndef STRUCT_TM_HASZONE
28 # define STRUCT_TM_HASZONE
30 # define USE_TM_GMTOFF
34 #define DAYS_PER_YEAR 365
35 #define DAYS_PER_QYEAR (4*DAYS_PER_YEAR+1)
36 #define DAYS_PER_CENT (25*DAYS_PER_QYEAR-1)
37 #define DAYS_PER_QCENT (4*DAYS_PER_CENT+1)
38 #define SECS_PER_HOUR (60*60)
39 #define SECS_PER_DAY (24*SECS_PER_HOUR)
40 /* parentheses deliberately absent on these two, otherwise they don't work */
41 #define MONTH_TO_DAYS 153/5
42 #define DAYS_TO_MONTH 5/153
43 /* offset to bias by March (month 4) 1st between month/mday & year finding */
44 #define YEAR_ADJUST (4*MONTH_TO_DAYS+1)
45 /* as used here, the algorithm leaves Sunday as day 1 unless we adjust it */
46 #define WEEKDAY_BIAS 6 /* (1+6)%7 makes Sunday 0 again */
48 #ifdef STRUCT_TM_HASZONE
50 my_init_tm(struct tm *ptm) /* see mktime, strftime and asctime */
54 Copy(localtime(&now), ptm, 1, struct tm);
58 # define my_init_tm(ptm)
62 * my_mini_mktime - normalise struct tm values without the localtime()
63 * semantics (and overhead) of mktime().
66 my_mini_mktime(struct tm *ptm)
70 int month, mday, year, jday;
71 int odd_cent, odd_year;
74 * Year/day algorithm notes:
76 * With a suitable offset for numeric value of the month, one can find
77 * an offset into the year by considering months to have 30.6 (153/5) days,
78 * using integer arithmetic (i.e., with truncation). To avoid too much
79 * messing about with leap days, we consider January and February to be
80 * the 13th and 14th month of the previous year. After that transformation,
81 * we need the month index we use to be high by 1 from 'normal human' usage,
82 * so the month index values we use run from 4 through 15.
84 * Given that, and the rules for the Gregorian calendar (leap years are those
85 * divisible by 4 unless also divisible by 100, when they must be divisible
86 * by 400 instead), we can simply calculate the number of days since some
87 * arbitrary 'beginning of time' by futzing with the (adjusted) year number,
88 * the days we derive from our month index, and adding in the day of the
89 * month. The value used here is not adjusted for the actual origin which
90 * it normally would use (1 January A.D. 1), since we're not exposing it.
91 * We're only building the value so we can turn around and get the
92 * normalised values for the year, month, day-of-month, and day-of-year.
94 * For going backward, we need to bias the value we're using so that we find
95 * the right year value. (Basically, we don't want the contribution of
96 * March 1st to the number to apply while deriving the year). Having done
97 * that, we 'count up' the contribution to the year number by accounting for
98 * full quadracenturies (400-year periods) with their extra leap days, plus
99 * the contribution from full centuries (to avoid counting in the lost leap
100 * days), plus the contribution from full quad-years (to count in the normal
101 * leap days), plus the leftover contribution from any non-leap years.
102 * At this point, if we were working with an actual leap day, we'll have 0
103 * days left over. This is also true for March 1st, however. So, we have
104 * to special-case that result, and (earlier) keep track of the 'odd'
105 * century and year contributions. If we got 4 extra centuries in a qcent,
106 * or 4 extra years in a qyear, then it's a leap day and we call it 29 Feb.
107 * Otherwise, we add back in the earlier bias we removed (the 123 from
108 * figuring in March 1st), find the month index (integer division by 30.6),
109 * and the remainder is the day-of-month. We then have to convert back to
110 * 'real' months (including fixing January and February from being 14/15 in
111 * the previous year to being in the proper year). After that, to get
112 * tm_yday, we work with the normalised year and get a new yearday value for
113 * January 1st, which we subtract from the yearday value we had earlier,
114 * representing the date we've re-built. This is done from January 1
115 * because tm_yday is 0-origin.
117 * Since POSIX time routines are only guaranteed to work for times since the
118 * UNIX epoch (00:00:00 1 Jan 1970 UTC), the fact that this algorithm
119 * applies Gregorian calendar rules even to dates before the 16th century
120 * doesn't bother me. Besides, you'd need cultural context for a given
121 * date to know whether it was Julian or Gregorian calendar, and that's
122 * outside the scope for this routine. Since we convert back based on the
123 * same rules we used to build the yearday, you'll only get strange results
124 * for input which needed normalising, or for the 'odd' century years which
125 * were leap years in the Julian calander but not in the Gregorian one.
126 * I can live with that.
128 * This algorithm also fails to handle years before A.D. 1 gracefully, but
129 * that's still outside the scope for POSIX time manipulation, so I don't
133 year = 1900 + ptm->tm_year;
136 /* allow given yday with no month & mday to dominate the result */
137 if (ptm->tm_yday >= 0 && mday <= 0 && month <= 0) {
140 jday = 1 + ptm->tm_yday;
150 yearday = DAYS_PER_YEAR * year + year/4 - year/100 + year/400;
151 yearday += month*MONTH_TO_DAYS + mday + jday;
153 * Note that we don't know when leap-seconds were or will be,
154 * so we have to trust the user if we get something which looks
155 * like a sensible leap-second. Wild values for seconds will
156 * be rationalised, however.
158 if ((unsigned) ptm->tm_sec <= 60) {
165 secs += 60 * ptm->tm_min;
166 secs += SECS_PER_HOUR * ptm->tm_hour;
168 if (secs-(secs/SECS_PER_DAY*SECS_PER_DAY) < 0) {
169 /* got negative remainder, but need positive time */
170 /* back off an extra day to compensate */
171 yearday += (secs/SECS_PER_DAY)-1;
172 secs -= SECS_PER_DAY * (secs/SECS_PER_DAY - 1);
175 yearday += (secs/SECS_PER_DAY);
176 secs -= SECS_PER_DAY * (secs/SECS_PER_DAY);
179 else if (secs >= SECS_PER_DAY) {
180 yearday += (secs/SECS_PER_DAY);
181 secs %= SECS_PER_DAY;
183 ptm->tm_hour = secs/SECS_PER_HOUR;
184 secs %= SECS_PER_HOUR;
185 ptm->tm_min = secs/60;
188 /* done with time of day effects */
190 * The algorithm for yearday has (so far) left it high by 428.
191 * To avoid mistaking a legitimate Feb 29 as Mar 1, we need to
192 * bias it by 123 while trying to figure out what year it
193 * really represents. Even with this tweak, the reverse
194 * translation fails for years before A.D. 0001.
195 * It would still fail for Feb 29, but we catch that one below.
197 jday = yearday; /* save for later fixup vis-a-vis Jan 1 */
198 yearday -= YEAR_ADJUST;
199 year = (yearday / DAYS_PER_QCENT) * 400;
200 yearday %= DAYS_PER_QCENT;
201 odd_cent = yearday / DAYS_PER_CENT;
202 year += odd_cent * 100;
203 yearday %= DAYS_PER_CENT;
204 year += (yearday / DAYS_PER_QYEAR) * 4;
205 yearday %= DAYS_PER_QYEAR;
206 odd_year = yearday / DAYS_PER_YEAR;
208 yearday %= DAYS_PER_YEAR;
209 if (!yearday && (odd_cent==4 || odd_year==4)) { /* catch Feb 29 */
214 yearday += YEAR_ADJUST; /* recover March 1st crock */
215 month = yearday*DAYS_TO_MONTH;
216 yearday -= month*MONTH_TO_DAYS;
217 /* recover other leap-year adjustment */
226 ptm->tm_year = year - 1900;
228 ptm->tm_mday = yearday;
233 ptm->tm_mon = month - 1;
235 /* re-build yearday based on Jan 1 to get tm_yday */
237 yearday = year*DAYS_PER_YEAR + year/4 - year/100 + year/400;
238 yearday += 14*MONTH_TO_DAYS + 1;
239 ptm->tm_yday = jday - yearday;
240 /* fix tm_wday if not overridden by caller */
241 ptm->tm_wday = (jday + WEEKDAY_BIAS) % 7;
244 #if defined(WIN32) || (defined(__QNX__) && defined(__WATCOMC__)) /* No strptime on Win32 or QNX4 */
245 #define strncasecmp(x,y,n) strnicmp(x,y,n)
248 #define alloca _alloca
256 #include "pthread_private.h"
257 #endif /* _THREAD_SAFE */
259 static char * _strptime(const char *, const char *, struct tm *);
262 static struct pthread_mutex _gotgmt_mutexd = PTHREAD_MUTEX_STATIC_INITIALIZER;
263 static pthread_mutex_t gotgmt_mutex = &_gotgmt_mutexd;
267 #define asizeof(a) (sizeof (a) / sizeof ((a)[0]))
270 const char * mon[12];
271 const char * month[12];
272 const char * wday[7];
273 const char * weekday[7];
279 const char * date_fmt;
280 const char * alt_month[12];
285 struct lc_time_T _time_localebuf;
286 int _time_using_locale;
288 const struct lc_time_T _C_time_locale = {
290 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
291 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
293 "January", "February", "March", "April", "May", "June",
294 "July", "August", "September", "October", "November", "December"
296 "Sun", "Mon", "Tue", "Wed",
299 "Sunday", "Monday", "Tuesday", "Wednesday",
300 "Thursday", "Friday", "Saturday"
308 ** Since the C language standard calls for
309 ** "date, using locale's date format," anything goes.
310 ** Using just numbers (as here) makes Quakers happier;
311 ** it's also compatible with SVR4.
316 ** c_fmt (ctime-compatible)
317 ** Not used, just compatibility placeholder.
331 "January", "February", "March", "April", "May", "June",
332 "July", "August", "September", "October", "November", "December"
336 ** To determine short months / day order
341 ** To determine long months / day order
346 #define Locale (&_C_time_locale)
349 _strptime(const char *buf, const char *fmt, struct tm *tm)
355 int Ealternative, Oalternative;
365 if (isspace((unsigned char)c))
366 while (*buf != 0 && isspace((unsigned char)*buf))
368 else if (c != *buf++)
385 buf = _strptime(buf, Locale->date_fmt, tm);
391 if (!isdigit((unsigned char)*buf))
394 /* XXX This will break for 3-digit centuries. */
396 for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
404 tm->tm_year = i * 100 - 1900;
408 /* NOTE: c_fmt is intentionally ignored */
409 buf = _strptime(buf, "%a %Ef %T %Y", tm);
415 buf = _strptime(buf, "%m/%d/%y", tm);
421 if (Ealternative || Oalternative)
427 if (Ealternative || Oalternative)
436 buf = _strptime(buf, (c == 'f') ? Locale->Ef_fmt : Locale->EF_fmt, tm);
442 buf = _strptime(buf, "%H:%M", tm);
448 buf = _strptime(buf, "%I:%M:%S %p", tm);
454 buf = _strptime(buf, "%H:%M:%S", tm);
460 buf = _strptime(buf, Locale->X_fmt, tm);
466 buf = _strptime(buf, Locale->x_fmt, tm);
472 if (!isdigit((unsigned char)*buf))
476 for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
481 if (i < 1 || i > 366)
489 if (*buf == 0 || isspace((unsigned char)*buf))
492 if (!isdigit((unsigned char)*buf))
496 for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
512 if (*buf != 0 && isspace((unsigned char)*buf))
513 while (*ptr != 0 && !isspace((unsigned char)*ptr))
522 * Of these, %l is the only specifier explicitly
523 * documented as not being zero-padded. However,
524 * there is no harm in allowing zero-padding.
526 * XXX The %l specifier may gobble one too many
527 * digits if used incorrectly.
529 if (!isdigit((unsigned char)*buf))
533 for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
538 if (c == 'H' || c == 'k') {
546 if (*buf != 0 && isspace((unsigned char)*buf))
547 while (*ptr != 0 && !isspace((unsigned char)*ptr))
553 * XXX This is bogus if parsed before hour-related
556 len = strlen(Locale->am);
557 if (strncasecmp(buf, Locale->am, len) == 0) {
558 if (tm->tm_hour > 12)
560 if (tm->tm_hour == 12)
566 len = strlen(Locale->pm);
567 if (strncasecmp(buf, Locale->pm, len) == 0) {
568 if (tm->tm_hour > 12)
570 if (tm->tm_hour != 12)
580 for (i = 0; i < asizeof(Locale->weekday); i++) {
582 len = strlen(Locale->weekday[i]);
588 len = strlen(Locale->wday[i]);
595 if (i == asizeof(Locale->weekday))
605 * XXX This is bogus, as we can not assume any valid
606 * information present in the tm structure at this
607 * point to calculate a real value, so just check the
610 if (!isdigit((unsigned char)*buf))
614 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))
628 if (!isdigit((unsigned char)*buf))
637 if (*buf != 0 && isspace((unsigned char)*buf))
638 while (*ptr != 0 && !isspace((unsigned char)*ptr))
645 * The %e specifier is explicitly documented as not
646 * being zero-padded but there is no harm in allowing
649 * XXX The %e specifier may gobble one too many
650 * digits if used incorrectly.
652 if (!isdigit((unsigned char)*buf))
656 for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
666 if (*buf != 0 && isspace((unsigned char)*buf))
667 while (*ptr != 0 && !isspace((unsigned char)*ptr))
674 for (i = 0; i < asizeof(Locale->month); i++) {
677 len = strlen(Locale->alt_month[i]);
679 Locale->alt_month[i],
685 len = strlen(Locale->month[i]);
691 len = strlen(Locale->mon[i]);
699 if (i == asizeof(Locale->month))
707 if (!isdigit((unsigned char)*buf))
711 for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
721 if (*buf != 0 && isspace((unsigned char)*buf))
722 while (*ptr != 0 && !isspace((unsigned char)*ptr))
728 if (*buf == 0 || isspace((unsigned char)*buf))
731 if (!isdigit((unsigned char)*buf))
734 len = (c == 'Y') ? 4 : 2;
735 for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
742 if (c == 'y' && i < 69)
749 if (*buf != 0 && isspace((unsigned char)*buf))
750 while (*ptr != 0 && !isspace((unsigned char)*ptr))
759 for (cp = buf; *cp && isupper((unsigned char)*cp); ++cp)
762 zonestr = (char *)alloca(cp - buf + 1);
763 strncpy(zonestr, buf, cp - buf);
764 zonestr[cp - buf] = '\0';
766 if (0 == strcmp(zonestr, "GMT")) {
782 strptime(const char *buf, const char *fmt, struct tm *tm)
787 pthread_mutex_lock(&gotgmt_mutex);
791 ret = _strptime(buf, fmt, tm);
794 pthread_mutex_unlock(&gotgmt_mutex);
800 #endif /* Mac OS X */
802 MODULE = Time::Piece PACKAGE = Time::Piece
807 _strftime(fmt, sec, min, hour, mday, mon, year, wday = -1, yday = -1, isdst = -1)
823 memset(&mytm, 0, sizeof(mytm));
824 my_init_tm(&mytm); /* XXX workaround - see my_init_tm() above */
833 mytm.tm_isdst = isdst;
834 my_mini_mktime(&mytm);
835 len = strftime(tmpbuf, sizeof tmpbuf, fmt, &mytm);
837 ** The following is needed to handle to the situation where
838 ** tmpbuf overflows. Basically we want to allocate a buffer
839 ** and try repeatedly. The reason why it is so complicated
840 ** is that getting a return value of 0 from strftime can indicate
841 ** one of the following:
842 ** 1. buffer overflowed,
843 ** 2. illegal conversion specifier, or
844 ** 3. the format string specifies nothing to be returned(not
845 ** an error). This could be because format is an empty string
846 ** or it specifies %p that yields an empty string in some locale.
847 ** If there is a better way to make it portable, go ahead by
850 if ((len > 0 && len < sizeof(tmpbuf)) || (len == 0 && *fmt == '\0'))
851 ST(0) = sv_2mortal(newSVpv(tmpbuf, len));
853 /* Possibly buf overflowed - try again with a bigger buf */
854 int fmtlen = strlen(fmt);
855 int bufsize = fmtlen + sizeof(tmpbuf);
859 New(0, buf, bufsize, char);
861 buflen = strftime(buf, bufsize, fmt, &mytm);
862 if (buflen > 0 && buflen < bufsize)
864 /* heuristic to prevent out-of-memory errors */
865 if (bufsize > 100*fmtlen) {
871 Renew(buf, bufsize, char);
874 ST(0) = sv_2mortal(newSVpv(buf, buflen));
878 ST(0) = sv_2mortal(newSVpv(tmpbuf, len));
889 _strptime ( string, format )
900 remainder = (char *)strptime(string, format, &mytm);
902 if (remainder == NULL) {
903 croak("Error parsing time");
906 if (*remainder != '\0') {
907 warn("garbage at end of string in strptime: %s", remainder);
910 my_mini_mktime(&mytm);
912 /* 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); */
915 PUSHs(sv_2mortal(newSViv(mytm.tm_sec)));
916 PUSHs(sv_2mortal(newSViv(mytm.tm_min)));
917 PUSHs(sv_2mortal(newSViv(mytm.tm_hour)));
918 PUSHs(sv_2mortal(newSViv(mytm.tm_mday)));
919 PUSHs(sv_2mortal(newSViv(mytm.tm_mon)));
920 PUSHs(sv_2mortal(newSViv(mytm.tm_year)));
921 PUSHs(sv_2mortal(newSViv(mytm.tm_wday)));
922 PUSHs(sv_2mortal(newSViv(mytm.tm_yday)));
924 PUSHs(sv_2mortal(newSViv(0)));
926 PUSHs(sv_2mortal(newSViv(0)));
928 PUSHs(sv_2mortal(newSViv(0)));