PostgreSQL Source Code git master
Loading...
Searching...
No Matches
strftime.c File Reference
#include "postgres.h"
#include <fcntl.h>
#include "private.h"
Include dependency graph for strftime.c:

Go to the source code of this file.

Data Structures

struct  lc_time_T
 

Enumerations

enum  warn { IN_NONE , IN_SOME , IN_THIS , IN_ALL }
 

Functions

static char_add (const char *str, char *pt, const char *ptlim)
 
static char_conv (int n, const char *format, char *pt, const char *ptlim)
 
static char_fmt (const char *format, const struct pg_tm *t, char *pt, const char *ptlim, enum warn *warnp)
 
static char_yconv (int a, int b, bool convert_top, bool convert_yy, char *pt, char const *ptlim)
 
size_t pg_strftime (char *s, size_t maxsize, const char *format, const struct pg_tm *t)
 

Variables

static const struct lc_time_T C_time_locale
 

Enumeration Type Documentation

◆ warn

enum warn ( void  )
Enumerator
IN_NONE 
IN_SOME 
IN_THIS 
IN_ALL 

Definition at line 103 of file strftime.c.

104{
106};
@ IN_ALL
Definition strftime.c:105
@ IN_NONE
Definition strftime.c:105
@ IN_SOME
Definition strftime.c:105
@ IN_THIS
Definition strftime.c:105

Function Documentation

◆ _add()

static char * _add ( const char str,
char pt,
const char ptlim 
)
static

Definition at line 530 of file strftime.c.

531{
532 while (pt < ptlim && (*pt = *str++) != '\0')
533 ++pt;
534 return pt;
535}
const char * str
static int fb(int x)

References fb(), and str.

Referenced by _conv(), _fmt(), and _yconv().

◆ _conv()

static char * _conv ( int  n,
const char format,
char pt,
const char ptlim 
)
static

Definition at line 521 of file strftime.c.

522{
523 char buf[INT_STRLEN_MAXIMUM(int) + 1];
524
525 sprintf(buf, format, n);
526 return _add(buf, pt, ptlim);
527}
static char format
static char buf[DEFAULT_XLOG_SEG_SIZE]
#define sprintf
Definition port.h:263
#define INT_STRLEN_MAXIMUM(type)
Definition private.h:178
static char * _add(const char *str, char *pt, const char *ptlim)
Definition strftime.c:530

References _add(), buf, fb(), format, INT_STRLEN_MAXIMUM, and sprintf.

Referenced by _fmt(), and _yconv().

◆ _fmt()

static char * _fmt ( const char format,
const struct pg_tm t,
char pt,
const char ptlim,
enum warn warnp 
)
static

Definition at line 156 of file strftime.c.

158{
160
161 for (; *format; ++format)
162 {
163 if (*format == '%')
164 {
165 label:
166 switch (*++format)
167 {
168 default:
169
170 /*
171 * Output unknown conversion specifiers as-is, to aid
172 * debugging. This includes '%' at format end. This
173 * conforms to C23 section 7.29.3.5 paragraph 6, which
174 * says behavior is undefined here.
175 */
176 --format;
177 break;
178 case 'A':
179 pt = _add((t->tm_wday < 0 ||
180 t->tm_wday >= DAYSPERWEEK) ?
181 "?" : Locale->weekday[t->tm_wday],
182 pt, ptlim);
183 continue;
184 case 'a':
185 pt = _add((t->tm_wday < 0 ||
186 t->tm_wday >= DAYSPERWEEK) ?
187 "?" : Locale->wday[t->tm_wday],
188 pt, ptlim);
189 continue;
190 case 'B':
191 pt = _add((t->tm_mon < 0 ||
192 t->tm_mon >= MONSPERYEAR) ?
193 "?" : Locale->month[t->tm_mon],
194 pt, ptlim);
195 continue;
196 case 'b':
197 case 'h':
198 pt = _add((t->tm_mon < 0 ||
199 t->tm_mon >= MONSPERYEAR) ?
200 "?" : Locale->mon[t->tm_mon],
201 pt, ptlim);
202 continue;
203 case 'C':
204
205 /*
206 * %C used to do a... _fmt("%a %b %e %X %Y", t);
207 * ...whereas now POSIX 1003.2 calls for something
208 * completely different. (ado, 1993-05-24)
209 */
211 true, false, pt, ptlim);
212 continue;
213 case 'c':
214 {
215 enum warn warn2 = IN_SOME;
216
217 pt = _fmt(Locale->c_fmt, t, pt, ptlim, &warn2);
218 if (warn2 == IN_ALL)
219 warn2 = IN_THIS;
220 if (warn2 > *warnp)
221 *warnp = warn2;
222 }
223 continue;
224 case 'D':
225 pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp);
226 continue;
227 case 'd':
228 pt = _conv(t->tm_mday, "%02d", pt, ptlim);
229 continue;
230 case 'E':
231 case 'O':
232
233 /*
234 * Locale modifiers of C99 and later. The sequences %Ec
235 * %EC %Ex %EX %Ey %EY %Od %oe %OH %OI %Om %OM %OS %Ou %OU
236 * %OV %Ow %OW %Oy are supposed to provide alternative
237 * representations.
238 */
239 goto label;
240 case 'e':
241 pt = _conv(t->tm_mday, "%2d", pt, ptlim);
242 continue;
243 case 'F':
244 pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp);
245 continue;
246 case 'H':
247 pt = _conv(t->tm_hour, "%02d", pt, ptlim);
248 continue;
249 case 'I':
250 pt = _conv((t->tm_hour % 12) ?
251 (t->tm_hour % 12) : 12,
252 "%02d", pt, ptlim);
253 continue;
254 case 'j':
255 pt = _conv(t->tm_yday + 1, "%03d", pt, ptlim);
256 continue;
257 case 'k':
258
259 /*
260 * This used to be... _conv(t->tm_hour % 12 ? t->tm_hour %
261 * 12 : 12, 2, ' '); ...and has been changed to the below
262 * to match SunOS 4.1.1 and Arnold Robbins' strftime
263 * version 3.0. That is, "%k" and "%l" have been swapped.
264 * (ado, 1993-05-24)
265 */
266 pt = _conv(t->tm_hour, "%2d", pt, ptlim);
267 continue;
268#ifdef KITCHEN_SINK
269 case 'K':
270
271 /*
272 * After all this time, still unclaimed!
273 */
274 pt = _add("kitchen sink", pt, ptlim);
275 continue;
276#endif /* defined KITCHEN_SINK */
277 case 'l':
278
279 /*
280 * This used to be... _conv(t->tm_hour, 2, ' '); ...and
281 * has been changed to the below to match SunOS 4.1.1 and
282 * Arnold Robbin's strftime version 3.0. That is, "%k" and
283 * "%l" have been swapped. (ado, 1993-05-24)
284 */
285 pt = _conv((t->tm_hour % 12) ?
286 (t->tm_hour % 12) : 12,
287 "%2d", pt, ptlim);
288 continue;
289 case 'M':
290 pt = _conv(t->tm_min, "%02d", pt, ptlim);
291 continue;
292 case 'm':
293 pt = _conv(t->tm_mon + 1, "%02d", pt, ptlim);
294 continue;
295 case 'n':
296 pt = _add("\n", pt, ptlim);
297 continue;
298 case 'p':
299 pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ?
300 Locale->pm :
301 Locale->am,
302 pt, ptlim);
303 continue;
304 case 'R':
305 pt = _fmt("%H:%M", t, pt, ptlim, warnp);
306 continue;
307 case 'r':
308 pt = _fmt("%I:%M:%S %p", t, pt, ptlim, warnp);
309 continue;
310 case 'S':
311 pt = _conv(t->tm_sec, "%02d", pt, ptlim);
312 continue;
313 case 'T':
314 pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp);
315 continue;
316 case 't':
317 pt = _add("\t", pt, ptlim);
318 continue;
319 case 'U':
320 pt = _conv((t->tm_yday + DAYSPERWEEK -
321 t->tm_wday) / DAYSPERWEEK,
322 "%02d", pt, ptlim);
323 continue;
324 case 'u':
325
326 /*
327 * From Arnold Robbins' strftime version 3.0: "ISO 8601:
328 * Weekday as a decimal number [1 (Monday) - 7]" (ado,
329 * 1993-05-24)
330 */
331 pt = _conv((t->tm_wday == 0) ?
332 DAYSPERWEEK : t->tm_wday,
333 "%d", pt, ptlim);
334 continue;
335 case 'V': /* ISO 8601 week number */
336 case 'G': /* ISO 8601 year (four digits) */
337 case 'g': /* ISO 8601 year (two digits) */
338/*
339 * From Arnold Robbins' strftime version 3.0: "the week number of the
340 * year (the first Monday as the first day of week 1) as a decimal number
341 * (01-53)."
342 * (ado, 1993-05-24)
343 *
344 * From <https://www.cl.cam.ac.uk/~mgk25/iso-time.html> by Markus Kuhn:
345 * "Week 01 of a year is per definition the first week which has the
346 * Thursday in this year, which is equivalent to the week which contains
347 * the fourth day of January. In other words, the first week of a new year
348 * is the week which has the majority of its days in the new year. Week 01
349 * might also contain days from the previous year and the week before week
350 * 01 of a year is the last week (52 or 53) of the previous year even if
351 * it contains days from the new year. A week starts with Monday (day 1)
352 * and ends with Sunday (day 7). For example, the first week of the year
353 * 1997 lasts from 1996-12-30 to 1997-01-05..."
354 * (ado, 1996-01-02)
355 */
356 {
357 int year;
358 int base;
359 int yday;
360 int wday;
361 int w;
362
363 year = t->tm_year;
364 base = TM_YEAR_BASE;
365 yday = t->tm_yday;
366 wday = t->tm_wday;
367 for (;;)
368 {
369 int len;
370 int bot;
371 int top;
372
373 len = isleap_sum(year, base) ?
376
377 /*
378 * What yday (-3 ... 3) does the ISO year begin
379 * on?
380 */
381 bot = ((yday + 11 - wday) %
382 DAYSPERWEEK) - 3;
383
384 /*
385 * What yday does the NEXT ISO year begin on?
386 */
387 top = bot -
388 (len % DAYSPERWEEK);
389 if (top < -3)
390 top += DAYSPERWEEK;
391 top += len;
392 if (yday >= top)
393 {
394 ++base;
395 w = 1;
396 break;
397 }
398 if (yday >= bot)
399 {
400 w = 1 + ((yday - bot) /
402 break;
403 }
404 --base;
405 yday += isleap_sum(year, base) ?
408 }
409 if (*format == 'V')
410 pt = _conv(w, "%02d",
411 pt, ptlim);
412 else if (*format == 'g')
413 {
414 *warnp = IN_ALL;
415 pt = _yconv(year, base,
416 false, true,
417 pt, ptlim);
418 }
419 else
420 pt = _yconv(year, base,
421 true, true,
422 pt, ptlim);
423 }
424 continue;
425 case 'v':
426
427 /*
428 * From Arnold Robbins' strftime version 3.0: "date as
429 * dd-bbb-YYYY" (ado, 1993-05-24)
430 */
431 pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp);
432 continue;
433 case 'W':
434 pt = _conv((t->tm_yday + DAYSPERWEEK -
435 (t->tm_wday ?
436 (t->tm_wday - 1) :
437 (DAYSPERWEEK - 1))) / DAYSPERWEEK,
438 "%02d", pt, ptlim);
439 continue;
440 case 'w':
441 pt = _conv(t->tm_wday, "%d", pt, ptlim);
442 continue;
443 case 'X':
444 pt = _fmt(Locale->X_fmt, t, pt, ptlim, warnp);
445 continue;
446 case 'x':
447 {
448 enum warn warn2 = IN_SOME;
449
450 pt = _fmt(Locale->x_fmt, t, pt, ptlim, &warn2);
451 if (warn2 == IN_ALL)
452 warn2 = IN_THIS;
453 if (warn2 > *warnp)
454 *warnp = warn2;
455 }
456 continue;
457 case 'y':
458 *warnp = IN_ALL;
460 false, true,
461 pt, ptlim);
462 continue;
463 case 'Y':
465 true, true,
466 pt, ptlim);
467 continue;
468 case 'Z':
469 if (t->tm_zone != NULL)
470 pt = _add(t->tm_zone, pt, ptlim);
471
472 /*
473 * C99 and later say that %Z must be replaced by the empty
474 * string if the time zone abbreviation is not
475 * determinable.
476 */
477 continue;
478 case 'z':
479 {
480 long diff;
481 char const *sign;
482 bool negative;
483
484 diff = t->TM_GMTOFF;
485 negative = diff < 0;
486 if (diff == 0)
487 {
488 if (t->tm_zone != NULL)
489 negative = t->tm_zone[0] == '-';
490 }
491 if (negative)
492 {
493 sign = "-";
494 diff = -diff;
495 }
496 else
497 sign = "+";
498 pt = _add(sign, pt, ptlim);
499 diff /= SECSPERMIN;
500 diff = (diff / MINSPERHOUR) * 100 +
501 (diff % MINSPERHOUR);
502 pt = _conv(diff, "%04d", pt, ptlim);
503 }
504 continue;
505 case '+':
506 pt = _fmt(Locale->date_fmt, t, pt, ptlim,
507 warnp);
508 continue;
509 case '%':
510 break;
511 }
512 }
513 if (pt == ptlim)
514 break;
515 *pt++ = *format;
516 }
517 return pt;
518}
char sign
Definition informix.c:693
static char * label
const void size_t len
@ TM_YEAR_BASE
Definition private.h:272
@ DAYSPERNYEAR
Definition private.h:214
@ DAYSPERLYEAR
Definition private.h:215
@ DAYSPERWEEK
Definition private.h:213
@ SECSPERMIN
Definition private.h:209
@ MONSPERYEAR
Definition private.h:216
@ MINSPERHOUR
Definition private.h:210
@ HOURSPERDAY
Definition private.h:212
#define isleap_sum(a, b)
Definition private.h:292
warn
Definition strftime.c:104
static char * _fmt(const char *format, const struct pg_tm *t, char *pt, const char *ptlim, enum warn *warnp)
Definition strftime.c:156
static char * _yconv(int a, int b, bool convert_top, bool convert_yy, char *pt, char const *ptlim)
Definition strftime.c:546
static char * _conv(int n, const char *format, char *pt, const char *ptlim)
Definition strftime.c:521
static const struct lc_time_T C_time_locale
Definition strftime.c:62
const char * am
Definition strftime.c:57
const char * mon[MONSPERYEAR]
Definition strftime.c:50
const char * weekday[DAYSPERWEEK]
Definition strftime.c:53
const char * wday[DAYSPERWEEK]
Definition strftime.c:52
const char * month[MONSPERYEAR]
Definition strftime.c:51
int tm_hour
Definition pgtime.h:38
int tm_mday
Definition pgtime.h:39
int tm_mon
Definition pgtime.h:40
int tm_min
Definition pgtime.h:37
const char * tm_zone
Definition pgtime.h:46
int tm_yday
Definition pgtime.h:43
int tm_wday
Definition pgtime.h:42
int tm_sec
Definition pgtime.h:36
int tm_year
Definition pgtime.h:41

References _add(), _conv(), _fmt(), _yconv(), C_time_locale, DAYSPERLYEAR, DAYSPERNYEAR, DAYSPERWEEK, fb(), format, HOURSPERDAY, IN_ALL, IN_SOME, IN_THIS, isleap_sum, label, len, MINSPERHOUR, MONSPERYEAR, SECSPERMIN, sign, pg_tm::tm_hour, pg_tm::tm_mday, pg_tm::tm_min, pg_tm::tm_mon, pg_tm::tm_sec, pg_tm::tm_wday, pg_tm::tm_yday, pg_tm::tm_year, TM_YEAR_BASE, pg_tm::tm_zone, and lc_time_T::wday.

Referenced by _fmt(), and pg_strftime().

◆ _yconv()

static char * _yconv ( int  a,
int  b,
bool  convert_top,
bool  convert_yy,
char pt,
char const ptlim 
)
static

Definition at line 546 of file strftime.c.

548{
549 int lead;
550 int trail;
551
552 int DIVISOR = 100;
553
554 trail = a % DIVISOR + b % DIVISOR;
555 lead = a / DIVISOR + b / DIVISOR + trail / DIVISOR;
556 trail %= DIVISOR;
558 {
559 trail += DIVISOR;
560 --lead;
561 }
562 else if (lead < 0 && trail > 0)
563 {
564 trail -= DIVISOR;
565 ++lead;
566 }
567 if (convert_top)
568 {
569 if (lead == 0 && trail < 0)
570 pt = _add("-0", pt, ptlim);
571 else
572 pt = _conv(lead, "%02d", pt, ptlim);
573 }
574 if (convert_yy)
575 pt = _conv(((trail < 0) ? -trail : trail), "%02d", pt, ptlim);
576 return pt;
577}
int b
Definition isn.c:74
int a
Definition isn.c:73

References _add(), _conv(), a, b, and fb().

Referenced by _fmt().

◆ pg_strftime()

size_t pg_strftime ( char s,
size_t  maxsize,
const char format,
const struct pg_tm t 
)

Definition at line 129 of file strftime.c.

130{
131 char *p;
132 int saved_errno = errno;
133 enum warn warn = IN_NONE;
134
135 p = _fmt(format, t, s, s + maxsize, &warn);
136 if (!p)
137 {
139 if (maxsize > 0)
140 *s = '\0';
141 return 0;
142 }
143 if (p == s + maxsize)
144 {
145 errno = ERANGE;
146 if (maxsize > 0)
147 *s = '\0';
148 return 0;
149 }
150 *p = '\0';
151 errno = saved_errno;
152 return p - s;
153}
#define EOVERFLOW
Definition private.h:88

References _fmt(), EOVERFLOW, fb(), format, and IN_NONE.

Referenced by AddFileToBackupManifest(), build_backup_content(), get_formatted_log_time(), get_formatted_start_time(), log_status_format(), logfile_getname(), str_time(), and timeofday().

Variable Documentation

◆ C_time_locale

const struct lc_time_T C_time_locale
static

Definition at line 62 of file strftime.c.

62 {
63 {
64 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
65 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
66 }, {
67 "January", "February", "March", "April", "May", "June",
68 "July", "August", "September", "October", "November", "December"
69 }, {
70 "Sun", "Mon", "Tue", "Wed",
71 "Thu", "Fri", "Sat"
72 }, {
73 "Sunday", "Monday", "Tuesday", "Wednesday",
74 "Thursday", "Friday", "Saturday"
75 },
76
77 /* X_fmt */
78 "%H:%M:%S",
79
80 /*
81 * x_fmt C99 and later require this format. Using just numbers (as here)
82 * makes Quakers happier; it's also compatible with SVR4.
83 */
84 "%m/%d/%y",
85
86 /*
87 * c_fmt C99 and later require this format. Previously this code used "%D
88 * %X", but we now conform to C99. Note that "%a %b %d %H:%M:%S %Y" is
89 * used by Solaris 2.3.
90 */
91 "%a %b %e %T %Y",
92
93 /* am */
94 "AM",
95
96 /* pm */
97 "PM",
98
99 /* date_fmt */
100 "%a %b %e %H:%M:%S %Z %Y"
101};

Referenced by _fmt().