8 #include "locale_impl.h"
10 #include "time_impl.h"
12 const 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
)
55 const char *fmt
= "-";
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;
89 *l
= snprintf(*s
, sizeof *s
, "%2d", tm
->tm_mday
);
96 val
= tm
->tm_year
+ 1900LL;
97 if (tm
->tm_yday
< 3 && week_num(tm
) != 1) val
--;
98 else if (tm
->tm_yday
> 360 && week_num(tm
) == 1) val
++;
99 if (f
=='g') val
%= 100;
108 else if (val
> 12) val
-= 12;
124 item
= tm
->tm_hour
>= 12 ? PM_STR
: AM_STR
;
133 val
= __tm_to_secs(tm
) - tm
->__tm_gmtoff
;
146 val
= tm
->tm_wday
? tm
->tm_wday
: 7;
150 val
= (tm
->tm_yday
+ 7U - tm
->tm_wday
) / 7;
153 val
= (tm
->tm_yday
+ 7U - (tm
->tm_wday
+6U)%7) / 7;
169 val
= (tm
->tm_year
+ 1900LL) % 100;
170 if (val
< 0) val
= -val
;
173 val
= tm
->tm_year
+ 1900LL;
175 *l
= snprintf(*s
, sizeof *s
, "+%lld", val
);
181 if (tm
->tm_isdst
< 0) {
185 *l
= snprintf(*s
, sizeof *s
, "%+.2d%.2d",
186 (tm
->__tm_gmtoff
)/3600,
187 abs(tm
->__tm_gmtoff
%3600)/60);
190 if (tm
->tm_isdst
< 0) {
194 fmt
= __tm_to_tzname(tm
);
203 *l
= snprintf(*s
, sizeof *s
, "%0*lld", width
, val
);
206 fmt
= __nl_langinfo_l(item
, loc
);
211 fmt
= __nl_langinfo_l(item
, loc
);
213 *l
= __strftime_l(*s
, sizeof *s
, fmt
, tm
, loc
);
218 size_t __strftime_l(char *restrict s
, size_t n
, const char *restrict f
, const struct tm
*restrict tm
, locale_t loc
)
226 for (l
=0; l
<n
; f
++) {
236 if ((plus
= (*f
== '+'))) f
++;
237 width
= strtoul(f
, &p
, 10);
238 if (*p
== 'C' || *p
== 'F' || *p
== 'G' || *p
== 'Y') {
239 if (!width
&& p
!=f
) width
= 1;
244 if (*f
== 'E' || *f
== 'O') f
++;
245 t
= __strftime_fmt_1(&buf
, &k
, *f
, tm
, loc
);
248 for (; *t
=='+' || *t
=='-' || (*t
=='0'&&t
[1]); t
++, k
--);
250 if (plus
&& tm
->tm_year
>= 10000-1900)
252 else if (tm
->tm_year
< -1900)
256 for (; width
> k
&& l
< n
; width
--)
259 if (k
> n
-l
) k
= n
-l
;
270 size_t strftime(char *restrict s
, size_t n
, const char *restrict f
, const struct tm
*restrict tm
)
272 return __strftime_l(s
, n
, f
, tm
, CURRENT_LOCALE
);
275 weak_alias(__strftime_l
, strftime_l
);