9 #include "locale_impl.h"
10 #include "time_impl.h"
12 static int is_leap(int y
)
15 if (y
>INT_MAX
-1900) y
-= 2000;
17 return !(y
%4) && ((y
%100) || !(y
%400));
20 static int week_num(const struct tm
*tm
)
22 int val
= (tm
->tm_yday
+ 7U - (tm
->tm_wday
+6U)%7) / 7;
23 /* If 1 Jan is just 1-3 days past Monday,
24 * the previous week is also in this year. */
25 if ((tm
->tm_wday
+ 371U - tm
->tm_yday
- 2) % 7 <= 2)
29 /* If 31 December of prev year a Thursday,
30 * or Friday of a leap year, then the
31 * prev year has 53 weeks. */
32 int dec31
= (tm
->tm_wday
+ 7U - tm
->tm_yday
- 1) % 7;
33 if (dec31
== 4 || (dec31
== 5 && is_leap(tm
->tm_year
%400-1)))
35 } else if (val
== 53) {
36 /* If 1 January is not a Thursday, and not
37 * a Wednesday of a leap year, then this
38 * year has only 52 weeks. */
39 int jan1
= (tm
->tm_wday
+ 371U - tm
->tm_yday
) % 7;
40 if (jan1
!= 4 && (jan1
!= 3 || !is_leap(tm
->tm_year
)))
46 const char *__strftime_fmt_1(char (*s
)[100], size_t *l
, int f
, const struct tm
*tm
, locale_t loc
, int pad
)
50 const char *fmt
= "-";
51 int width
= 2, def_pad
= '0';
55 if (tm
->tm_wday
> 6U) goto string
;
56 item
= ABDAY_1
+ tm
->tm_wday
;
59 if (tm
->tm_wday
> 6U) goto string
;
60 item
= DAY_1
+ tm
->tm_wday
;
64 if (tm
->tm_mon
> 11U) goto string
;
65 item
= ABMON_1
+ tm
->tm_mon
;
68 if (tm
->tm_mon
> 11U) goto string
;
69 item
= MON_1
+ tm
->tm_mon
;
75 val
= (1900LL+tm
->tm_year
) / 100;
90 val
= tm
->tm_year
+ 1900LL;
91 if (tm
->tm_yday
< 3 && week_num(tm
) != 1) val
--;
92 else if (tm
->tm_yday
> 360 && week_num(tm
) == 1) val
++;
93 if (f
=='g') val
%= 100;
102 else if (val
> 12) val
-= 12;
118 item
= tm
->tm_hour
>= 12 ? PM_STR
: AM_STR
;
127 val
= __tm_to_secs(tm
) - tm
->__tm_gmtoff
;
140 val
= tm
->tm_wday
? tm
->tm_wday
: 7;
144 val
= (tm
->tm_yday
+ 7U - tm
->tm_wday
) / 7;
147 val
= (tm
->tm_yday
+ 7U - (tm
->tm_wday
+6U)%7) / 7;
163 val
= (tm
->tm_year
+ 1900LL) % 100;
164 if (val
< 0) val
= -val
;
167 val
= tm
->tm_year
+ 1900LL;
169 *l
= snprintf(*s
, sizeof *s
, "+%lld", val
);
175 if (tm
->tm_isdst
< 0) {
179 *l
= snprintf(*s
, sizeof *s
, "%+.4ld",
180 tm
->__tm_gmtoff
/3600*100 + tm
->__tm_gmtoff
%3600/60);
183 if (tm
->tm_isdst
< 0) {
187 fmt
= __tm_to_tzname(tm
);
196 switch (pad
? pad
: def_pad
) {
197 case '-': *l
= snprintf(*s
, sizeof *s
, "%lld", val
); break;
198 case '_': *l
= snprintf(*s
, sizeof *s
, "%*lld", width
, val
); break;
200 default: *l
= snprintf(*s
, sizeof *s
, "%0*lld", width
, val
); break;
204 fmt
= __nl_langinfo_l(item
, loc
);
209 fmt
= __nl_langinfo_l(item
, loc
);
211 *l
= __strftime_l(*s
, sizeof *s
, fmt
, tm
, loc
);
216 size_t __strftime_l(char *restrict s
, size_t n
, const char *restrict f
, const struct tm
*restrict tm
, locale_t loc
)
224 for (l
=0; l
<n
; f
++) {
235 if (*f
== '-' || *f
== '_' || *f
== '0') pad
= *f
++;
236 if ((plus
= (*f
== '+'))) f
++;
238 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
);