4
// Date to string conversion
6
// Copyright (C) 2002 Michael Ringgaard. All rights reserved.
8
// Redistribution and use in source and binary forms, with or without
9
// modification, are permitted provided that the following conditions
12
// 1. Redistributions of source code must retain the above copyright
13
// notice, this list of conditions and the following disclaimer.
14
// 2. Redistributions in binary form must reproduce the above copyright
15
// notice, this list of conditions and the following disclaimer in the
16
// documentation and/or other materials provided with the distribution.
17
// 3. Neither the name of the project nor the names of its contributors
18
// may be used to endorse or promote products derived from this software
19
// without specific prior written permission.
21
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
22
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
25
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34
/////////////////////////////////////////////////////////////////////////////////////////////
38
/////////////////////////////////////////////////////////////////////////////////////////////
52
GetLocalTime(&systime);
54
tmtime.tm_year = systime.wYear-1900;
55
tmtime.tm_mon = systime.wMonth-1;
56
tmtime.tm_mday = systime.wDay;
57
tmtime.tm_wday = systime.wDayOfWeek;
58
tmtime.tm_hour = systime.wHour;
59
tmtime.tm_min = systime.wMinute;
60
tmtime.tm_sec = systime.wSecond;
71
/////////////////////////////////////////////////////////////////////////////////////////////
75
/////////////////////////////////////////////////////////////////////////////////////////////
77
static int month_to_day[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
79
time_t mktime(struct tm *t)
85
year = t->tm_year + month / 12 + 1900;
92
result = (year - 1970) * 365 + (year - 1969) / 4 + month_to_day[month];
93
result = (year - 1970) * 365 + month_to_day[month];
96
result += (year - 1968) / 4;
97
result -= (year - 1900) / 100;
98
result += (year - 1600) / 400;
102
result += t->tm_hour;
111
/////////////////////////////////////////////////////////////////////////////////////////////
113
// strftime() - taken from OpenBSD //
115
/////////////////////////////////////////////////////////////////////////////////////////////
123
#define TYPE_BIT(type) (sizeof (type) * CHAR_BIT)
124
#define TYPE_SIGNED(type) (((type) -1) < 0)
126
#define INT_STRLEN_MAXIMUM(type) \
127
((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + 1 + TYPE_SIGNED(type))
129
#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
131
#define MONSPERYEAR 12
132
#define DAYSPERWEEK 7
133
#define TM_YEAR_BASE 1900
134
#define HOURSPERDAY 24
135
#define DAYSPERNYEAR 365
136
#define DAYSPERLYEAR 366
138
static char wildabbr[] = "WILDABBR";
140
static char * tzname[2] = {
146
#define Locale (&C_time_locale)
149
const char * mon[MONSPERYEAR];
150
const char * month[MONSPERYEAR];
151
const char * wday[DAYSPERWEEK];
152
const char * weekday[DAYSPERWEEK];
158
const char * date_fmt;
161
static const struct lc_time_T C_time_locale = {
163
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
164
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
166
"January", "February", "March", "April", "May", "June",
167
"July", "August", "September", "October", "November", "December"
169
"Sun", "Mon", "Tue", "Wed",
172
"Sunday", "Monday", "Tuesday", "Wednesday",
173
"Thursday", "Friday", "Saturday"
181
** C99 requires this format.
182
** Using just numbers (as here) makes Quakers happier;
183
** it's also compatible with SVR4.
189
** C99 requires this format.
190
** Previously this code used "%D %X", but we now conform to C99.
192
** "%a %b %d %H:%M:%S %Y"
193
** is used by Solaris 2.3.
204
"%a %b %e %H:%M:%S %Z %Y"
209
_add(const char * str, char * pt, const char * const ptlim)
211
while (pt < ptlim && (*pt = *str++) != '\0')
218
_conv(const int n, const char * const format, char * const pt, const char * const ptlim)
220
char buf[INT_STRLEN_MAXIMUM(int) + 1];
222
(void) _snprintf(buf, sizeof buf, format, n);
223
return _add(buf, pt, ptlim);
228
_fmt(const char * format, const struct tm * const t, char * pt, const char * const ptlim, int * warnp)
230
for ( ; *format; ++format) {
231
if (*format == '%') {
238
pt = _add((t->tm_wday < 0 ||
239
t->tm_wday >= DAYSPERWEEK) ?
240
"?" : Locale->weekday[t->tm_wday],
244
pt = _add((t->tm_wday < 0 ||
245
t->tm_wday >= DAYSPERWEEK) ?
246
"?" : Locale->wday[t->tm_wday],
250
pt = _add((t->tm_mon < 0 ||
251
t->tm_mon >= MONSPERYEAR) ?
252
"?" : Locale->month[t->tm_mon],
257
pt = _add((t->tm_mon < 0 ||
258
t->tm_mon >= MONSPERYEAR) ?
259
"?" : Locale->mon[t->tm_mon],
264
** %C used to do a...
265
** _fmt("%a %b %e %X %Y", t);
266
** ...whereas now POSIX 1003.2 calls for
267
** something completely different.
270
pt = _conv((t->tm_year + TM_YEAR_BASE) / 100,
277
pt = _fmt(Locale->c_fmt, t, pt, ptlim, warnp);
285
pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp);
288
pt = _conv(t->tm_mday, "%02d", pt, ptlim);
293
** C99 locale modifiers.
295
** %Ec %EC %Ex %EX %Ey %EY
296
** %Od %oe %OH %OI %Om %OM
297
** %OS %Ou %OU %OV %Ow %OW %Oy
298
** are supposed to provide alternate
303
pt = _conv(t->tm_mday, "%2d", pt, ptlim);
306
pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp);
309
pt = _conv(t->tm_hour, "%02d", pt, ptlim);
312
pt = _conv((t->tm_hour % 12) ?
313
(t->tm_hour % 12) : 12,
317
pt = _conv(t->tm_yday + 1, "%03d", pt, ptlim);
321
** This used to be...
322
** _conv(t->tm_hour % 12 ?
323
** t->tm_hour % 12 : 12, 2, ' ');
324
** ...and has been changed to the below to
325
** match SunOS 4.1.1 and Arnold Robbins'
326
** strftime version 3.0. That is, "%k" and
327
** "%l" have been swapped.
330
pt = _conv(t->tm_hour, "%2d", pt, ptlim);
335
** After all this time, still unclaimed!
337
pt = _add("kitchen sink", pt, ptlim);
339
#endif /* defined KITCHEN_SINK */
342
** This used to be...
343
** _conv(t->tm_hour, 2, ' ');
344
** ...and has been changed to the below to
345
** match SunOS 4.1.1 and Arnold Robbin's
346
** strftime version 3.0. That is, "%k" and
347
** "%l" have been swapped.
350
pt = _conv((t->tm_hour % 12) ?
351
(t->tm_hour % 12) : 12,
355
pt = _conv(t->tm_min, "%02d", pt, ptlim);
358
pt = _conv(t->tm_mon + 1, "%02d", pt, ptlim);
361
pt = _add("\n", pt, ptlim);
364
pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ?
370
pt = _fmt("%H:%M", t, pt, ptlim, warnp);
373
pt = _fmt("%I:%M:%S %p", t, pt, ptlim, warnp);
376
pt = _conv(t->tm_sec, "%02d", pt, ptlim);
381
char buf[INT_STRLEN_MAXIMUM(
387
if (TYPE_SIGNED(time_t))
388
(void) _snprintf(buf, sizeof buf,
390
else (void) _snprintf(buf, sizeof buf,
391
"%lu", (unsigned long) mkt);
392
pt = _add(buf, pt, ptlim);
396
pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp);
399
pt = _add("\t", pt, ptlim);
402
pt = _conv((t->tm_yday + DAYSPERWEEK -
403
t->tm_wday) / DAYSPERWEEK,
408
** From Arnold Robbins' strftime version 3.0:
409
** "ISO 8601: Weekday as a decimal number
413
pt = _conv((t->tm_wday == 0) ?
414
DAYSPERWEEK : t->tm_wday,
417
case 'V': /* ISO 8601 week number */
418
case 'G': /* ISO 8601 year (four digits) */
419
case 'g': /* ISO 8601 year (two digits) */
426
year = t->tm_year + TM_YEAR_BASE;
438
** What yday (-3 ... 3) does
439
** the ISO year begin on?
441
bot = ((yday + 11 - wday) %
444
** What yday does the NEXT
445
** ISO year begin on?
458
w = 1 + ((yday - bot) /
463
yday += isleap(year) ?
468
pt = _conv(w, "%02d",
470
else if (*format == 'g') {
472
pt = _conv(year % 100, "%02d",
474
} else pt = _conv(year, "%04d",
479
pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp);
482
pt = _conv((t->tm_yday + DAYSPERWEEK -
485
(DAYSPERWEEK - 1))) / DAYSPERWEEK,
489
pt = _conv(t->tm_wday, "%d", pt, ptlim);
492
pt = _fmt(Locale->X_fmt, t, pt, ptlim, warnp);
498
pt = _fmt(Locale->x_fmt, t, pt, ptlim, &warn2);
507
pt = _conv((t->tm_year + TM_YEAR_BASE) % 100,
511
pt = _conv(t->tm_year + TM_YEAR_BASE, "%04d",
515
if (t->tm_isdst >= 0)
516
pt = _add(tzname[t->tm_isdst != 0],
519
** C99 says that %Z must be replaced by the
520
** empty string if the time zone is not
536
pt = _add(sign, pt, ptlim);
538
pt = _conv((diff/60)*100 + diff%60,
543
pt = _fmt(Locale->date_fmt, t, pt, ptlim,
560
strftime(char * const s, const size_t maxsize, const char * const format, const struct tm * const t)
568
p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize, &warn);
570
if (p == s + maxsize) {
572
s[maxsize - 1] = '\0';
581
/////////////////////////////////////////////////////////////////////////////////////////////
585
/////////////////////////////////////////////////////////////////////////////////////////////
589
static struct tm mytm;
591
static int DMonth[13] = { 0,31,59,90,120,151,181,212,243,273,304,334,365 };
592
static int monthCodes[12] = { 6, 2, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4 };
596
calcDayOfWeek(const struct tm* nTM)
600
day = (nTM->tm_year%100);
602
day += monthCodes[nTM->tm_mon];
612
gmtime(const time_t *timer)
614
unsigned long x = *timer;
615
int imin, ihrs, iday, iyrs;
616
int sec, min, hrs, day, mon, yrs;
617
int lday, qday, jday, mday;
620
imin = x / 60; // whole minutes since 1/1/70
621
sec = x - (60 * imin); // leftover seconds
622
ihrs = imin / 60; // whole hours since 1/1/70
623
min = imin - 60 * ihrs; // leftover minutes
624
iday = ihrs / 24; // whole days since 1/1/70
625
hrs = ihrs - 24 * iday; // leftover hours
626
iday = iday + 365 + 366; // whole days since 1/1/68
627
lday = iday / (( 4* 365) + 1); // quadyr = 4 yr period = 1461 days
628
qday = iday % (( 4 * 365) + 1); // days since current quadyr began
629
if(qday >= (31 + 29)) // if past feb 29 then
630
lday = lday + 1; // add this quadyr�s leap day to the
631
// # of quadyrs (leap days) since 68
632
iyrs = (iday - lday) / 365; // whole years since 1968
633
jday = iday - (iyrs * 365) - lday; // days since 1 /1 of current year.
634
if(qday <= 365 && qday >= 60) // if past 2/29 and a leap year then
635
jday = jday + 1; // add a leap day to the # of whole
636
// days since 1/1 of current year
637
yrs = iyrs + 1968; // compute year
638
mon = 13; // estimate month ( +1)
639
mday = 366; // max days since 1/1 is 365
640
while(jday < mday) // mday = # of days passed from 1/1
641
{ // until first day of current month
642
mon = mon - 1; // mon = month (estimated)
643
mday = DMonth[mon]; // # elapsed days at first of �mon�
644
if((mon > 2) && (yrs % 4) == 0) // if past 2/29 and leap year then
645
mday = mday + 1; // add leap day
646
// compute month by decrementing
647
} // month until found
649
day = jday - mday + 1; // compute day of month
656
mytm.tm_year = yrs - 1900;
658
mytm.tm_wday = calcDayOfWeek(&mytm);
666
/////////////////////////////////////////////////////////////////////////////////////////////
668
// localtime() - simply using gmtime() //
670
/////////////////////////////////////////////////////////////////////////////////////////////
674
localtime(const time_t *timer)
676
return gmtime(timer);