]>
git.proxmox.com Git - mirror_edk2.git/blob - StdLib/LibC/Time/strftime.c
2 Implementation of the strftime function for <time.h>.
4 Based on the UCB version with the ID appearing below.
5 This is ANSIish only when "multibyte character == plain character".
7 Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
8 This program and the accompanying materials are licensed and made available under
9 the terms and conditions of the BSD License that accompanies this distribution.
10 The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php.
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 Copyright (c) 1989, 1993
17 The Regents of the University of California. All rights reserved.
19 Redistribution and use in source and binary forms, with or without
20 modification, are permitted provided that the following conditions
22 1. Redistributions of source code must retain the above copyright
23 notice, this list of conditions and the following disclaimer.
24 2. Redistributions in binary form must reproduce the above copyright
25 notice, this list of conditions and the following disclaimer in the
26 documentation and/or other materials provided with the distribution.
27 3. All advertising materials mentioning features or use of this software
28 must display the following acknowledgement:
29 This product includes software developed by the University of
30 California, Berkeley and its contributors.
31 4. Neither the name of the University nor the names of its contributors
32 may be used to endorse or promote products derived from this software
33 without specific prior written permission.
35 THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
36 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
38 ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
39 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
40 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
41 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
42 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
43 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
44 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47 NetBSD: strftime.c,v 1.17.4.1 2007/08/21 20:08:21 liamjfoy Exp
49 #include <LibConfig.h>
50 #include <sys/EfiCdefs.h>
52 #include "namespace.h"
59 #include "sys/localedef.h"
63 ** We don't use these extensions in strftime operation even when
64 ** supported by the local tzcode configuration. A strictly
65 ** conforming C application may leave them in undefined state.
73 #define Locale _CurrentTimeLocale
75 static char * _add(const char *, char *, const char * const);
76 static char * _conv(const int, const char * const, char * const, const char * const);
77 static char * _fmt(const char *, const struct tm
* const, char *, const char * const, int *);
79 #define NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU
81 #ifndef YEAR_2000_NAME
82 #define YEAR_2000_NAME "CHECK_STRFTIME_FORMATS_FOR_TWO_DIGIT_YEARS"
83 #endif /* !defined YEAR_2000_NAME */
95 const char * __restrict format
,
96 const struct tm
* __restrict timeptr
104 p
= _fmt(((format
== NULL
) ? "%c" : format
), timeptr
, s
, s
+ maxsize
, &warn
);
106 #ifndef NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU
107 if (warn
!= IN_NONE
&& getenv(YEAR_2000_NAME
) != NULL
) {
108 (void) fprintf(stderr
, "\n");
110 (void) fprintf(stderr
, "NULL strftime format ");
111 else (void) fprintf(stderr
, "strftime format \"%s\" ",
113 (void) fprintf(stderr
, "yields only two digits of years in ");
115 (void) fprintf(stderr
, "some locales");
116 else if (warn
== IN_THIS
)
117 (void) fprintf(stderr
, "the current locale");
118 else (void) fprintf(stderr
, "all locales");
119 (void) fprintf(stderr
, "\n");
121 #endif /* !defined NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU */
123 if (p
== s
+ maxsize
)
132 const struct tm
* const t
,
134 const char * const ptlim
,
138 for ( ; *format
; ++format
) {
139 if (*format
== '%') {
146 pt
= _add((t
->tm_wday
< 0 ||
147 t
->tm_wday
>= DAYSPERWEEK
) ?
148 "?" : Locale
->day
[t
->tm_wday
],
152 pt
= _add((t
->tm_wday
< 0 ||
153 t
->tm_wday
>= DAYSPERWEEK
) ?
154 "?" : Locale
->abday
[t
->tm_wday
],
158 pt
= _add((t
->tm_mon
< 0 ||
159 t
->tm_mon
>= MONSPERYEAR
) ?
160 "?" : Locale
->mon
[t
->tm_mon
],
165 pt
= _add((t
->tm_mon
< 0 ||
166 t
->tm_mon
>= MONSPERYEAR
) ?
167 "?" : Locale
->abmon
[t
->tm_mon
],
172 ** %C used to do a...
173 ** _fmt("%a %b %e %X %Y", t);
174 ** ...whereas now POSIX 1003.2 calls for
175 ** something completely different.
178 pt
= _conv((t
->tm_year
+ TM_YEAR_BASE
) / 100,
185 pt
= _fmt(Locale
->d_t_fmt
, t
, pt
, ptlim
, &warn2
);
193 pt
= _fmt("%m/%d/%y", t
, pt
, ptlim
, warnp
);
196 pt
= _conv(t
->tm_mday
, "%02d", pt
, ptlim
);
201 ** C99 locale modifiers.
203 ** %Ec %EC %Ex %EX %Ey %EY
204 ** %Od %oe %OH %OI %Om %OM
205 ** %OS %Ou %OU %OV %Ow %OW %Oy
206 ** are supposed to provide alternate
211 pt
= _conv(t
->tm_mday
, "%2d", pt
, ptlim
);
214 pt
= _fmt("%Y-%m-%d", t
, pt
, ptlim
, warnp
);
217 pt
= _conv(t
->tm_hour
, "%02d", pt
, ptlim
);
220 pt
= _conv((t
->tm_hour
% 12) ?
221 (t
->tm_hour
% 12) : 12,
225 pt
= _conv(t
->tm_yday
+ 1, "%03d", pt
, ptlim
);
229 ** This used to be...
230 ** _conv(t->tm_hour % 12 ?
231 ** t->tm_hour % 12 : 12, 2, ' ');
232 ** ...and has been changed to the below to
233 ** match SunOS 4.1.1 and Arnold Robbins'
234 ** strftime version 3.0. That is, "%k" and
235 ** "%l" have been swapped.
238 pt
= _conv(t
->tm_hour
, "%2d", pt
, ptlim
);
243 ** After all this time, still unclaimed!
245 pt
= _add("kitchen sink", pt
, ptlim
);
247 #endif /* defined KITCHEN_SINK */
250 ** This used to be...
251 ** _conv(t->tm_hour, 2, ' ');
252 ** ...and has been changed to the below to
253 ** match SunOS 4.1.1 and Arnold Robbin's
254 ** strftime version 3.0. That is, "%k" and
255 ** "%l" have been swapped.
258 pt
= _conv((t
->tm_hour
% 12) ?
259 (t
->tm_hour
% 12) : 12,
263 pt
= _conv(t
->tm_min
, "%02d", pt
, ptlim
);
266 pt
= _conv(t
->tm_mon
+ 1, "%02d", pt
, ptlim
);
269 pt
= _add("\n", pt
, ptlim
);
272 pt
= _add((t
->tm_hour
>= (HOURSPERDAY
/ 2)) ?
278 pt
= _fmt("%H:%M", t
, pt
, ptlim
, warnp
);
281 pt
= _fmt(Locale
->t_fmt_ampm
, t
, pt
, ptlim
,
285 pt
= _conv(t
->tm_sec
, "%02d", pt
, ptlim
);
290 char buf
[INT_STRLEN_MAXIMUM(
297 if (TYPE_SIGNED(time_t))
298 (void) sprintf(buf
, "%ld",
300 else (void) sprintf(buf
, "%lu",
301 (unsigned long) mkt
);
302 pt
= _add(buf
, pt
, ptlim
);
306 pt
= _fmt("%H:%M:%S", t
, pt
, ptlim
, warnp
);
309 pt
= _add("\t", pt
, ptlim
);
312 pt
= _conv((t
->tm_yday
+ DAYSPERWEEK
-
313 t
->tm_wday
) / DAYSPERWEEK
,
318 ** From Arnold Robbins' strftime version 3.0:
319 ** "ISO 8601: Weekday as a decimal number
323 pt
= _conv((t
->tm_wday
== 0) ?
324 DAYSPERWEEK
: t
->tm_wday
,
327 case 'V': /* ISO 8601 week number */
328 case 'G': /* ISO 8601 year (four digits) */
329 case 'g': /* ISO 8601 year (two digits) */
331 ** From Arnold Robbins' strftime version 3.0: "the week number of the
332 ** year (the first Monday as the first day of week 1) as a decimal number
336 ** From "http://www.ft.uni-erlangen.de/~mskuhn/iso-time.html" by Markus Kuhn:
337 ** "Week 01 of a year is per definition the first week which has the
338 ** Thursday in this year, which is equivalent to the week which contains
339 ** the fourth day of January. In other words, the first week of a new year
340 ** is the week which has the majority of its days in the new year. Week 01
341 ** might also contain days from the previous year and the week before week
342 ** 01 of a year is the last week (52 or 53) of the previous year even if
343 ** it contains days from the new year. A week starts with Monday (day 1)
344 ** and ends with Sunday (day 7). For example, the first week of the year
345 ** 1997 lasts from 1996-12-30 to 1997-01-05..."
354 year
= t
->tm_year
+ TM_YEAR_BASE
;
366 ** What yday (-3 ... 3) does
367 ** the ISO year begin on?
369 bot
= ((yday
+ 11 - wday
) %
372 ** What yday does the NEXT
373 ** ISO year begin on?
386 w
= 1 + ((yday
- bot
) /
391 yday
+= isleap(year
) ?
395 #ifdef XPG4_1994_04_09
397 && t
->tm_mon
== TM_JANUARY
)
399 && t
->tm_mon
== TM_DECEMBER
))
401 #endif /* defined XPG4_1994_04_09 */
403 pt
= _conv(w
, "%02d",
405 else if (*format
== 'g') {
407 pt
= _conv(year
% 100, "%02d",
409 } else pt
= _conv(year
, "%04d",
415 ** From Arnold Robbins' strftime version 3.0:
416 ** "date as dd-bbb-YYYY"
419 pt
= _fmt("%e-%b-%Y", t
, pt
, ptlim
, warnp
);
422 pt
= _conv((t
->tm_yday
+ DAYSPERWEEK
-
425 (DAYSPERWEEK
- 1))) / DAYSPERWEEK
,
429 pt
= _conv(t
->tm_wday
, "%d", pt
, ptlim
);
432 pt
= _fmt(Locale
->t_fmt
, t
, pt
, ptlim
, warnp
);
438 pt
= _fmt(Locale
->d_fmt
, t
, pt
, ptlim
, &warn2
);
447 pt
= _conv((t
->tm_year
+ TM_YEAR_BASE
) % 100,
451 pt
= _conv(t
->tm_year
+ TM_YEAR_BASE
, "%04d",
456 if (t
->TM_ZONE
!= NULL
)
457 pt
= _add(t
->TM_ZONE
, pt
, ptlim
);
459 #endif /* defined TM_ZONE */
460 if (t
->tm_isdst
>= 0)
461 pt
= _add(tzname
[t
->tm_isdst
!= 0],
464 ** C99 says that %Z must be replaced by the
465 ** empty string if the time zone is not
477 diff
= (int)t
->TM_GMTOFF
;
478 #else /* !defined TM_GMTOFF */
480 ** C99 says that the UTC offset must
481 ** be computed by looking only at
482 ** tm_isdst. This requirement is
483 ** incorrect, since it means the code
484 ** must rely on magic (in this case
485 ** altzone and timezone), and the
486 ** magic might not have the correct
487 ** offset. Doing things correctly is
488 ** tricky and requires disobeying C99;
489 ** see GNU C strftime for details.
490 ** For now, punt and conform to the
491 ** standard, even though it's incorrect.
493 ** C99 says that %z must be replaced by the
494 ** empty string if the time zone is not
495 ** determinable, so output nothing if the
496 ** appropriate variables are not available.
499 if (t
->tm_isdst
== 0)
502 #else /* !defined USG_COMPAT */
504 #endif /* !defined USG_COMPAT */
508 #else /* !defined ALTZONE */
510 #endif /* !defined ALTZONE */
511 #else /* defined STD_INSPIRED */
517 ** Get calendar time from t
518 ** being treated as local.
520 tmp
= *t
; /* mktime discards const */
523 if (lct
== (time_t)-1)
527 ** Get calendar time from t
528 ** being treated as GMT.
530 tmp
= *t
; /* mktime discards const */
533 if (gct
== (time_t)-1)
536 /* LINTED difference will fit int */
537 diff
= (intmax_t)gct
- (intmax_t)lct
;
539 #endif /* defined STD_INSPIRED */
540 #endif /* !defined TM_GMTOFF */
545 pt
= _add(sign
, pt
, ptlim
);
547 pt
= _conv((diff
/60)*100 + diff
%60,
553 pt
= _fmt(Locale
->date_fmt
, t
, pt
, ptlim
,
559 ** X311J/88-090 (4.12.3.5): if conversion char is
560 ** undefined, behavior is undefined. Print out the
561 ** character itself as printf(3) also does.
577 const char * const format
,
579 const char * const ptlim
582 char buf
[INT_STRLEN_MAXIMUM(int) + 1];
584 (void) sprintf(buf
, format
, n
);
585 return _add(buf
, pt
, ptlim
);
592 const char * const ptlim
595 while (pt
< ptlim
&& (*pt
= *str
++) != '\0')