1 /* strftime( char * restrict, size_t, const char * restrict, const struct tm * restrict )
3 This file is part of the Public Domain C Library (PDCLib).
4 Permission is granted to use, modify, and / or redistribute at will.
14 /* TODO: Alternative representations / numerals not supported. */
16 /* This implementation's code is highly repetitive, but I did not really
17 care for putting it into a number of macros / helper functions.
20 size_t strftime( char * _PDCLIB_restrict s, size_t maxsize, const char * _PDCLIB_restrict format, const struct tm * _PDCLIB_restrict timeptr )
24 while ( rc < maxsize )
28 if ( ( *s++ = *format++ ) == '\0' )
44 /* flag = *format++; */
54 /* tm_wday abbreviated */
55 const char * day = _PDCLIB_lconv.day_name_abbr[ timeptr->tm_wday ];
56 size_t len = strlen( day );
57 if ( rc < ( maxsize - len ) )
71 const char * day = _PDCLIB_lconv.day_name_full[ timeptr->tm_wday ];
72 size_t len = strlen( day );
73 if ( rc < ( maxsize - len ) )
87 /* tm_mon abbreviated */
88 const char * month = _PDCLIB_lconv.month_name_abbr[ timeptr->tm_mon ];
89 size_t len = strlen( month );
90 if ( rc < ( maxsize - len ) )
104 const char * month = _PDCLIB_lconv.month_name_full[ timeptr->tm_mon ];
105 size_t len = strlen( month );
106 if ( rc < ( maxsize - len ) )
119 /* locale's date / time representation, %a %b %e %T %Y for C locale */
120 /* 'E' for locale's alternative representation */
121 size_t count = strftime( s, maxsize - rc, _PDCLIB_lconv.date_time_format, timeptr );
134 /* tm_year divided by 100, truncated to decimal (00-99) */
135 /* 'E' for base year (period) in locale's alternative representation */
136 if ( rc < ( maxsize - 2 ) )
138 div_t period = div( ( timeptr->tm_year / 100 ), 10 );
139 *s++ = '0' + period.quot;
140 *s++ = '0' + period.rem;
151 /* tm_mday as decimal (01-31) */
152 /* 'O' for locale's alternative numeric symbols */
153 if ( rc < ( maxsize - 2 ) )
155 div_t day = div( timeptr->tm_mday, 10 );
156 *s++ = '0' + day.quot;
157 *s++ = '0' + day.rem;
169 size_t count = strftime( s, maxsize - rc, "%m/%d/%y", timeptr );
182 /* tm_mday as decimal ( 1-31) */
183 /* 'O' for locale's alternative numeric symbols */
184 if ( rc < ( maxsize - 2 ) )
186 div_t day = div( timeptr->tm_mday, 10 );
187 *s++ = ( day.quot > 0 ) ? '0' + day.quot : ' ';
188 *s++ = '0' + day.rem;
200 size_t count = strftime( s, maxsize - rc, "%Y-%m-%d", timeptr );
213 /* last 2 digits of the week-based year as decimal (00-99) */
219 /* week-based year as decimal (e.g. 1997) */
225 /* tm_hour as 24h decimal (00-23) */
226 /* 'O' for locale's alternative numeric symbols */
227 if ( rc < ( maxsize - 2 ) )
229 div_t hour = div( timeptr->tm_hour, 10 );
230 *s++ = '0' + hour.quot;
231 *s++ = '0' + hour.rem;
242 /* tm_hour as 12h decimal (01-12) */
243 /* 'O' for locale's alternative numeric symbols */
244 if ( rc < ( maxsize - 2 ) )
246 div_t hour = div( ( timeptr->tm_hour + 1 ) % 12, 10 );
247 *s++ = '0' + hour.quot;
248 *s++ = '0' + hour.rem;
259 /* tm_yday as decimal (001-366) */
260 if ( rc < ( maxsize - 3 ) )
262 div_t yday = div( timeptr->tm_yday, 100 );
263 *s++ = '0' + yday.quot;
264 *s++ = '0' + yday.rem / 10;
265 *s++ = '0' + yday.rem % 10;
276 /* tm_mon as decimal (01-12) */
277 /* 'O' for locale's alternative numeric symbols */
278 if ( rc < ( maxsize - 2 ) )
280 div_t mon = div( timeptr->tm_mon + 1, 10 );
281 *s++ = '0' + mon.quot;
282 *s++ = '0' + mon.rem;
293 /* tm_min as decimal (00-59) */
294 /* 'O' for locale's alternative numeric symbols */
295 if ( rc < ( maxsize - 2 ) )
297 div_t min = div( timeptr->tm_min + 1, 10 );
298 *s++ = '0' + min.quot;
299 *s++ = '0' + min.rem;
317 /* tm_hour locale's AM/PM designations */
318 const char * designation = _PDCLIB_lconv.am_pm[ timeptr->tm_hour > 11 ];
319 size_t len = strlen( designation );
320 if ( rc < ( maxsize - len ) )
322 strcpy( s, designation );
333 /* tm_hour / tm_min / tm_sec as locale's 12-hour clock time, %I:%M:%S %p for C locale */
334 size_t count = strftime( s, maxsize - rc, _PDCLIB_lconv.time_format_12h, timeptr );
348 size_t count = strftime( s, maxsize - rc, "%H:%M", timeptr );
361 /* tm_sec as decimal (00-60) */
362 /* 'O' for locale's alternative numeric symbols */
363 if ( rc < ( maxsize - 2 ) )
365 div_t sec = div( timeptr->tm_sec + 1, 10 );
366 *s++ = '0' + sec.quot;
367 *s++ = '0' + sec.rem;
386 size_t count = strftime( s, maxsize - rc, "%H:%M:%S", timeptr );
399 /* tm_wday as decimal (1-7) with Monday == 1 */
400 /* 'O' for locale's alternative numeric symbols */
401 *s++ = ( timeptr->tm_wday == 0 ) ? '7' : '0' + timeptr->tm_wday;
407 /* week number of the year (first Sunday as the first day of week 1) as decimal (00-53) */
408 /* 'O' for locale's alternative numeric symbols */
414 /* week number as decimal (01-53) */
415 /* 'O' for locale's alternative numeric symbols */
421 /* tm_wday as decimal number (0-6) with Sunday == 0 */
422 /* 'O' for locale's alternative numeric symbols */
423 *s++ = '0' + timeptr->tm_wday;
429 /* week number of the year (first Monday as the first day of week 1) as decimal (00-53) */
430 /* 'O' for locale's alternative numeric symbols */
436 /* locale's date representation, %m/%d/%y for C locale */
437 /* 'E' for locale's alternative representation */
438 size_t count = strftime( s, maxsize - rc, _PDCLIB_lconv.date_format, timeptr );
451 /* locale's time representation, %T for C locale */
452 /* 'E' for locale's alternative representation */
453 size_t count = strftime( s, maxsize - rc, _PDCLIB_lconv.time_format, timeptr );
466 /* last 2 digits of tm_year as decimal (00-99) */
467 /* 'E' for offset from %EC (year only) in locale's alternative representation */
468 /* 'O' for locale's alternative numeric symbols */
469 if ( rc < ( maxsize - 2 ) )
471 div_t year = div( ( timeptr->tm_year % 100 ), 10 );
472 *s++ = '0' + year.quot;
473 *s++ = '0' + year.rem;
484 /* tm_year as decimal (e.g. 1997) */
485 /* 'E' for locale's alternative representation */
486 if ( rc < ( maxsize - 4 ) )
488 int year = timeptr->tm_year;
490 for ( int i = 3; i >= 0; --i )
492 div_t digit = div( year, 10 );
493 s[i] = '0' + digit.rem;
507 /* tm_isdst / UTC offset in ISO8601 format (e.g. -0430 meaning 4 hours 30 minutes behind Greenwich), or no characters */
513 /* tm_isdst / locale's time zone name or abbreviation, or no characters */
535 #include "_PDCLIB_test.h"
539 TESTCASE( NO_TESTDRIVER );