8 #include "locale_impl.h"
10 #include "time_impl.h"
12 char *__nl_langinfo_l(nl_item
, locale_t
);
14 static int is_leap(int y
)
17 if (y
>INT_MAX
-1900) y
-= 2000;
19 return !(y
%4) && ((y
%100) || !(y
%400));
22 static int week_num(const struct tm
*tm
)
24 int val
= (tm
->tm_yday
+ 7U - (tm
->tm_wday
+6U)%7) / 7;
25 /* If 1 Jan is just 1-3 days past Monday,
26 * the previous week is also in this year. */
27 if ((tm
->tm_wday
+ 371U - tm
->tm_yday
- 2) % 7 <= 2)
31 /* If 31 December of prev year a Thursday,
32 * or Friday of a leap year, then the
33 * prev year has 53 weeks. */
34 int dec31
= (tm
->tm_wday
+ 7U - tm
->tm_yday
- 1) % 7;
35 if (dec31
== 4 || (dec31
== 5 && is_leap(tm
->tm_year
%400-1)))
37 } else if (val
== 53) {
38 /* If 1 January is not a Thursday, and not
39 * a Wednesday of a leap year, then this
40 * year has only 52 weeks. */
41 int jan1
= (tm
->tm_wday
+ 371U - tm
->tm_yday
) % 7;
42 if (jan1
!= 4 && (jan1
!= 3 || !is_leap(tm
->tm_year
)))
48 const char *__tm_to_tzname(const struct tm
*);
49 size_t __strftime_l(char *restrict
, size_t, const char *restrict
, const struct tm
*restrict
, locale_t
);
51 const char *__strftime_fmt_1(char (*s
)[100], size_t *l
, int f
, const struct tm
*tm
, locale_t loc
, int pad
)
55 const char *fmt
= "-";
56 int width
= 2, def_pad
= '0';
60 if (tm
->tm_wday
> 6U) goto string
;
61 item
= ABDAY_1
+ tm
->tm_wday
;
64 if (tm
->tm_wday
> 6U) goto string
;
65 item
= DAY_1
+ tm
->tm_wday
;
69 if (tm
->tm_mon
> 11U) goto string
;
70 item
= ABMON_1
+ tm
->tm_mon
;
73 if (tm
->tm_mon
> 11U) goto string
;
74 item
= MON_1
+ tm
->tm_mon
;
80 val
= (1900LL+tm
->tm_year
) / 100;
95 val
= tm
->tm_year
+ 1900LL;
96 if (tm
->tm_yday
< 3 && week_num(tm
) != 1) val
--;
97 else if (tm
->tm_yday
> 360 && week_num(tm
) == 1) val
++;
98 if (f
=='g') val
%= 100;
107 else if (val
> 12) val
-= 12;
123 item
= tm
->tm_hour
>= 12 ? PM_STR
: AM_STR
;
132 val
= __tm_to_secs(tm
) - tm
->__tm_gmtoff
;
145 val
= tm
->tm_wday
? tm
->tm_wday
: 7;
149 val
= (tm
->tm_yday
+ 7U - tm
->tm_wday
) / 7;
152 val
= (tm
->tm_yday
+ 7U - (tm
->tm_wday
+6U)%7) / 7;
168 val
= (tm
->tm_year
+ 1900LL) % 100;
169 if (val
< 0) val
= -val
;
172 val
= tm
->tm_year
+ 1900LL;
174 *l
= snprintf(*s
, sizeof *s
, "+%lld", val
);
180 if (tm
->tm_isdst
< 0) {
184 *l
= snprintf(*s
, sizeof *s
, "%+.4ld",
185 tm
->__tm_gmtoff
/3600*100 + tm
->__tm_gmtoff
%3600/60);
188 if (tm
->tm_isdst
< 0) {
192 fmt
= __tm_to_tzname(tm
);
201 switch (pad
? pad
: def_pad
) {
202 case '-': *l
= snprintf(*s
, sizeof *s
, "%lld", val
); break;
203 case '_': *l
= snprintf(*s
, sizeof *s
, "%*lld", width
, val
); break;
205 default: *l
= snprintf(*s
, sizeof *s
, "%0*lld", width
, val
); break;
209 fmt
= __nl_langinfo_l(item
, loc
);
214 fmt
= __nl_langinfo_l(item
, loc
);
216 *l
= __strftime_l(*s
, sizeof *s
, fmt
, tm
, loc
);
221 size_t __strftime_l(char *restrict s
, size_t n
, const char *restrict f
, const struct tm
*restrict tm
, locale_t loc
)
229 for (l
=0; l
<n
; f
++) {
240 if (*f
== '-' || *f
== '_' || *f
== '0') pad
= *f
++;
241 if ((plus
= (*f
== '+'))) f
++;
242 width
= strtoul(f
, &p
, 10);
243 if (*p
== 'C' || *p
== 'F' || *p
== 'G' || *p
== 'Y') {
244 if (!width
&& p
!=f
) width
= 1;
249 if (*f
== 'E' || *f
== 'O') f
++;
250 t
= __strftime_fmt_1(&buf
, &k
, *f
, tm
, loc
, pad
);
253 /* Trim off any sign and leading zeros, then
254 * count remaining digits to determine behavior
256 if (*t
=='+' || *t
=='-') t
++, k
--;
257 for (; *t
=='0' && t
[1]-'0'<10U; t
++, k
--);
258 if (width
< k
) width
= k
;
260 for (d
=0; t
[d
]-'0'<10U; d
++);
261 if (tm
->tm_year
< -1900) {
264 } else if (plus
&& d
+(width
-k
) >= (*p
=='C'?3:5)) {
268 for (; width
> k
&& l
< n
; width
--)
271 if (k
> n
-l
) k
= n
-l
;
282 size_t strftime(char *restrict s
, size_t n
, const char *restrict f
, const struct tm
*restrict tm
)
284 return __strftime_l(s
, n
, f
, tm
, CURRENT_LOCALE
);
287 weak_alias(__strftime_l
, strftime_l
);