]>
git.saurik.com Git - apple/libc.git/blob - stdtime/strftime.c
2 * Copyright (c) 1989 The Regents of the University of California.
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19 static const char rcsid
[] =
20 "$FreeBSD: src/lib/libc/stdtime/strftime.c,v 1.25.2.3 2001/02/18 04:06:49 kris Exp $";
25 static const char elsieid
[] = "@(#)strftime.c 7.38";
27 ** Based on the UCB version with the ID appearing below.
28 ** This is ANSIish only when "multibyte character == plain character".
30 #endif /* !defined NOID */
31 #endif /* !defined lint */
37 static const char sccsid
[] = "@(#)strftime.c 5.4 (Berkeley) 3/14/89";
38 #endif /* !defined lint */
39 #endif /* !defined LIBC_SCCS */
44 #include "timelocal.h"
46 static char * _add
P((const char *, char *, const char *));
47 static char * _conv
P((int, const char *, char *, const char *));
48 static char * _fmt
P((const char *, const struct tm
*, char *, const char *));
50 size_t strftime
P((char *, size_t, const char *, const struct tm
*));
52 extern char * tzname
[];
55 strftime(s
, maxsize
, format
, t
)
58 const char *const format
;
59 const struct tm
*const t
;
64 p
= _fmt(((format
== NULL
) ? "%c" : format
), t
, s
, s
+ maxsize
);
72 _fmt(format
, t
, pt
, ptlim
)
74 const struct tm
*const t
;
76 const char *const ptlim
;
78 int Ealternative
, Oalternative
;
80 for ( ; *format
; ++format
) {
90 pt
= _add((t
->tm_wday
< 0 || t
->tm_wday
> 6) ?
91 "?" : Locale
->weekday
[t
->tm_wday
],
95 pt
= _add((t
->tm_wday
< 0 || t
->tm_wday
> 6) ?
96 "?" : Locale
->wday
[t
->tm_wday
],
100 pt
= _add((t
->tm_mon
< 0 || t
->tm_mon
> 11) ?
101 "?" : (Oalternative
? Locale
->alt_month
:
102 Locale
->month
)[t
->tm_mon
],
107 pt
= _add((t
->tm_mon
< 0 || t
->tm_mon
> 11) ?
108 "?" : Locale
->mon
[t
->tm_mon
],
113 ** %C used to do a...
114 ** _fmt("%a %b %e %X %Y", t);
115 ** ...whereas now POSIX 1003.2 calls for
116 ** something completely different.
119 pt
= _conv((t
->tm_year
+ TM_YEAR_BASE
) / 100,
123 /* NOTE: c_fmt is intentionally ignored */
124 pt
= _fmt("%a %Ef %T %Y", t
, pt
, ptlim
);
127 pt
= _fmt("%m/%d/%y", t
, pt
, ptlim
);
130 pt
= _conv(t
->tm_mday
, "%02d", pt
, ptlim
);
133 if (Ealternative
|| Oalternative
)
139 ** POSIX locale extensions, a la
140 ** Arnold Robbins' strftime version 3.0.
142 ** %Ec %EC %Ex %EX %Ey %EY
143 ** %Od %oe %OH %OI %Om %OM
144 ** %OS %Ou %OU %OV %Ow %OW %Oy
145 ** are supposed to provide alternate
149 ** FreeBSD extensions
152 if (Ealternative
|| Oalternative
)
157 pt
= _conv(t
->tm_mday
, "%2d", pt
, ptlim
);
162 pt
= _fmt(Locale
->Ef_fmt
, t
, pt
, ptlim
);
167 pt
= _fmt(Locale
->EF_fmt
, t
, pt
, ptlim
);
170 pt
= _conv(t
->tm_hour
, "%02d", pt
, ptlim
);
173 pt
= _conv((t
->tm_hour
% 12) ?
174 (t
->tm_hour
% 12) : 12,
178 pt
= _conv(t
->tm_yday
+ 1, "%03d", pt
, ptlim
);
182 ** This used to be...
183 ** _conv(t->tm_hour % 12 ?
184 ** t->tm_hour % 12 : 12, 2, ' ');
185 ** ...and has been changed to the below to
186 ** match SunOS 4.1.1 and Arnold Robbins'
187 ** strftime version 3.0. That is, "%k" and
188 ** "%l" have been swapped.
191 pt
= _conv(t
->tm_hour
, "%2d", pt
, ptlim
);
196 ** After all this time, still unclaimed!
198 pt
= _add("kitchen sink", pt
, ptlim
);
200 #endif /* defined KITCHEN_SINK */
203 ** This used to be...
204 ** _conv(t->tm_hour, 2, ' ');
205 ** ...and has been changed to the below to
206 ** match SunOS 4.1.1 and Arnold Robbin's
207 ** strftime version 3.0. That is, "%k" and
208 ** "%l" have been swapped.
211 pt
= _conv((t
->tm_hour
% 12) ?
212 (t
->tm_hour
% 12) : 12,
216 pt
= _conv(t
->tm_min
, "%02d", pt
, ptlim
);
219 pt
= _conv(t
->tm_mon
+ 1, "%02d", pt
, ptlim
);
222 pt
= _add("\n", pt
, ptlim
);
225 pt
= _add((t
->tm_hour
>= 12) ?
231 pt
= _fmt("%H:%M", t
, pt
, ptlim
);
234 pt
= _fmt("%I:%M:%S %p", t
, pt
, ptlim
);
237 pt
= _conv(t
->tm_sec
, "%02d", pt
, ptlim
);
242 char buf
[INT_STRLEN_MAXIMUM(
248 if (TYPE_SIGNED(time_t))
249 (void) sprintf(buf
, "%ld",
251 else (void) sprintf(buf
, "%lu",
252 (unsigned long) mkt
);
253 pt
= _add(buf
, pt
, ptlim
);
257 pt
= _fmt("%H:%M:%S", t
, pt
, ptlim
);
260 pt
= _add("\t", pt
, ptlim
);
263 pt
= _conv((t
->tm_yday
+ 7 - t
->tm_wday
) / 7,
268 ** From Arnold Robbins' strftime version 3.0:
269 ** "ISO 8601: Weekday as a decimal number
273 pt
= _conv((t
->tm_wday
== 0) ? 7 : t
->tm_wday
,
276 case 'V': /* ISO 8601 week number */
277 case 'G': /* ISO 8601 year (four digits) */
278 case 'g': /* ISO 8601 year (two digits) */
280 ** From Arnold Robbins' strftime version 3.0: "the week number of the
281 ** year (the first Monday as the first day of week 1) as a decimal number
285 ** From "http://www.ft.uni-erlangen.de/~mskuhn/iso-time.html" by Markus Kuhn:
286 ** "Week 01 of a year is per definition the first week which has the
287 ** Thursday in this year, which is equivalent to the week which contains
288 ** the fourth day of January. In other words, the first week of a new year
289 ** is the week which has the majority of its days in the new year. Week 01
290 ** might also contain days from the previous year and the week before week
291 ** 01 of a year is the last week (52 or 53) of the previous year even if
292 ** it contains days from the new year. A week starts with Monday (day 1)
293 ** and ends with Sunday (day 7). For example, the first week of the year
294 ** 1997 lasts from 1996-12-30 to 1997-01-05..."
303 year
= t
->tm_year
+ TM_YEAR_BASE
;
315 ** What yday (-3 ... 3) does
316 ** the ISO year begin on?
318 bot
= ((yday
+ 11 - wday
) %
321 ** What yday does the NEXT
322 ** ISO year begin on?
335 w
= 1 + ((yday
- bot
) /
340 yday
+= isleap(year
) ?
344 #ifdef XPG4_1994_04_09
346 && t
->tm_mon
== TM_JANUARY
)
348 && t
->tm_mon
== TM_DECEMBER
))
350 #endif /* defined XPG4_1994_04_09 */
352 pt
= _conv(w
, "%02d",
354 else if (*format
== 'g') {
355 pt
= _conv(year
% 100, "%02d",
357 } else pt
= _conv(year
, "%04d",
363 ** From Arnold Robbins' strftime version 3.0:
364 ** "date as dd-bbb-YYYY"
367 pt
= _fmt("%e-%b-%Y", t
, pt
, ptlim
);
370 pt
= _conv((t
->tm_yday
+ 7 -
372 (t
->tm_wday
- 1) : 6)) / 7,
376 pt
= _conv(t
->tm_wday
, "%d", pt
, ptlim
);
379 pt
= _fmt(Locale
->X_fmt
, t
, pt
, ptlim
);
382 pt
= _fmt(Locale
->x_fmt
, t
, pt
, ptlim
);
385 pt
= _conv((t
->tm_year
+ TM_YEAR_BASE
) % 100,
389 pt
= _conv(t
->tm_year
+ TM_YEAR_BASE
, "%04d",
393 if (t
->tm_zone
!= NULL
)
394 pt
= _add(t
->tm_zone
, pt
, ptlim
);
396 if (t
->tm_isdst
== 0 || t
->tm_isdst
== 1) {
397 pt
= _add(tzname
[t
->tm_isdst
],
399 } else pt
= _add("?", pt
, ptlim
);
404 if (t
->tm_gmtoff
>= 0) {
405 absoff
= t
->tm_gmtoff
;
406 pt
= _add("+", pt
, ptlim
);
408 absoff
= -t
->tm_gmtoff
;
409 pt
= _add("-", pt
, ptlim
);
411 pt
= _conv(absoff
/ 3600, "%02d",
413 pt
= _conv((absoff
% 3600) / 60, "%02d",
418 pt
= _fmt(Locale
->date_fmt
, t
, pt
, ptlim
);
422 * X311J/88-090 (4.12.3.5): if conversion char is
423 * undefined, behavior is undefined. Print out the
424 * character itself as printf(3) also does.
438 _conv(n
, format
, pt
, ptlim
)
440 const char *const format
;
442 const char *const ptlim
;
444 char buf
[INT_STRLEN_MAXIMUM(int) + 1];
446 (void) sprintf(buf
, format
, n
);
447 return _add(buf
, pt
, ptlim
);
454 const char *const ptlim
;
456 while (pt
< ptlim
&& (*pt
= *str
++) != '\0')