1#include <limits.h> 2#include <stdlib.h> 3#include <string.h> 4#include <time.h> 5#include "test.h" 6 7static char buffer[100]; 8 9static void checkStrftime(const char* format, const struct tm* tm, 10 const char* expected) { 11 size_t resultLength = strftime(buffer, sizeof(buffer), format, tm); 12 13 if (resultLength != 0 && strcmp(buffer, expected) != 0) { 14 t_error("\"%s\": expected \"%s\", got \"%s\"\n", format, expected, buffer); 15 } else if (resultLength == 0 && strlen(expected) != 0) { 16 t_error("\"%s\": expected \"%s\", got nothing\n", format, expected); 17 } 18} 19 20static struct tm tm1 = { 21 .tm_sec = 45, 22 .tm_min = 23, 23 .tm_hour = 13, 24 .tm_mday = 3, 25 .tm_mon = 0, 26 .tm_year = 2016 - 1900, 27 .tm_wday = 0, 28 .tm_yday = 2, 29 .tm_isdst = 0 30}; 31 32static struct tm tm2 = { 33 .tm_sec = 53, 34 .tm_min = 17, 35 .tm_hour = 5, 36 .tm_mday = 5, 37 .tm_mon = 0, 38 .tm_year = 10009 - 1900, 39 .tm_wday = 1, 40 .tm_yday = 4, 41 .tm_isdst = 0 42}; 43 44static struct tm tm3 = { 45 .tm_sec = 0, 46 .tm_min = 0, 47 .tm_hour = 12, 48 .tm_mday = 23, 49 .tm_mon = 1, 50 .tm_year = 0 - 1900, 51 .tm_wday = 3, 52 .tm_yday = 53, 53 .tm_isdst = 0 54}; 55 56static struct tm tm4 = { 57 .tm_sec = 0, 58 .tm_min = 0, 59 .tm_hour = 0, 60 .tm_mday = 1, 61 .tm_mon = 0, 62 .tm_year = -123 - 1900, 63 .tm_wday = 1, 64 .tm_yday = 0, 65 .tm_isdst = 0 66}; 67 68static struct tm tm5 = { 69 .tm_sec = 0, 70 .tm_min = 0, 71 .tm_hour = 0, 72 .tm_mday = 1, 73 .tm_mon = 0, 74 .tm_year = INT_MAX, 75 .tm_wday = 3, 76 .tm_yday = 0, 77 .tm_isdst = 0 78}; 79 80int main() { 81 setenv("TZ", "UTC0", 1); 82 83 checkStrftime("%c", &tm1, "Sun Jan 3 13:23:45 2016"); 84 checkStrftime("%c", &tm2, "Mon Jan 5 05:17:53 +10009"); 85 checkStrftime("%c", &tm3, "Wed Feb 23 12:00:00 0000"); 86 87 // The POSIX.1-2008 standard does not specify the padding character for 88 // "%C". The C standard requires that the number is padded by '0'. 89 // See also http://austingroupbugs.net/view.php?id=1184 90 checkStrftime("%C", &tm1, "20"); 91 checkStrftime("%03C", &tm1, "020"); 92 checkStrftime("%+3C", &tm1, "+20"); 93 checkStrftime("%C", &tm2, "100"); 94 checkStrftime("%C", &tm3, "00"); 95 checkStrftime("%01C", &tm3, "0"); 96 97 checkStrftime("%F", &tm1, "2016-01-03"); 98 checkStrftime("%012F", &tm1, "002016-01-03"); 99 checkStrftime("%+10F", &tm1, "2016-01-03"); 100 checkStrftime("%+11F", &tm1, "+2016-01-03"); 101 checkStrftime("%F", &tm2, "+10009-01-05"); 102 checkStrftime("%011F", &tm2, "10009-01-05"); 103 checkStrftime("%F", &tm3, "0000-02-23"); 104 checkStrftime("%01F", &tm3, "0-02-23"); 105 checkStrftime("%06F", &tm3, "0-02-23"); 106 checkStrftime("%010F", &tm3, "0000-02-23"); 107 checkStrftime("%F", &tm4, "-123-01-01"); 108 checkStrftime("%011F", &tm4, "-0123-01-01"); 109 110 checkStrftime("%g", &tm1, "15"); 111 checkStrftime("%g", &tm2, "09"); 112 113 checkStrftime("%G", &tm1, "2015"); 114 checkStrftime("%+5G", &tm1, "+2015"); 115 checkStrftime("%04G", &tm2, "10009"); 116 117 checkStrftime("%r", &tm1, "01:23:45 PM"); 118 checkStrftime("%r", &tm2, "05:17:53 AM"); 119 checkStrftime("%r", &tm3, "12:00:00 PM"); 120 checkStrftime("%r", &tm4, "12:00:00 AM"); 121 122 // The "%s" specifier was accepted by the Austin Group for the next POSIX.1 123 // revision. See http://austingroupbugs.net/view.php?id=169 124 checkStrftime("%s", &tm1, "1451827425"); 125 if (sizeof(time_t) * CHAR_BIT >= 64) { 126 checkStrftime("%s", &tm2, "253686748673"); 127 } 128 129 checkStrftime("%T", &tm1, "13:23:45"); 130 checkStrftime("%T", &tm2, "05:17:53"); 131 checkStrftime("%T", &tm3, "12:00:00"); 132 checkStrftime("%T", &tm4, "00:00:00"); 133 134 checkStrftime("%U", &tm1, "01"); 135 checkStrftime("%U", &tm2, "01"); 136 checkStrftime("%U", &tm3, "08"); 137 138 checkStrftime("%V", &tm1, "53"); 139 checkStrftime("%V", &tm2, "02"); 140 checkStrftime("%V", &tm3, "08"); 141 142 checkStrftime("%W", &tm1, "00"); 143 checkStrftime("%W", &tm2, "01"); 144 checkStrftime("%W", &tm3, "08"); 145 146 checkStrftime("%x", &tm1, "01/03/16"); 147 checkStrftime("%X", &tm1, "13:23:45"); 148 checkStrftime("%y", &tm1, "16"); 149 150 // There is no standard that explicitly specifies the exact format of "%Y". 151 // The C standard says that "%F" is equivalent to "%Y-%m-%d". The 152 // POSIX.1-2008 standard says that "%F" is equivalent to "%+4Y-%m-%d". 153 // This implies that to conform to both standards "%Y" needs to be 154 // equivalent to "%+4Y". 155 // See also http://austingroupbugs.net/view.php?id=739 156 checkStrftime("%Y", &tm1, "2016"); 157 checkStrftime("%05Y", &tm1, "02016"); 158 checkStrftime("%+4Y", &tm1, "2016"); 159 checkStrftime("%+5Y", &tm1, "+2016"); 160 checkStrftime("%Y", &tm2, "+10009"); 161 checkStrftime("%05Y", &tm2, "10009"); 162 checkStrftime("%Y", &tm3, "0000"); 163 checkStrftime("%02Y", &tm3, "00"); 164 checkStrftime("%+5Y", &tm3, "+0000"); 165 checkStrftime("%Y", &tm4, "-123"); 166 checkStrftime("%+4Y", &tm4, "-123"); 167 checkStrftime("%+5Y", &tm4, "-0123"); 168 169 if (INT_MAX == 0x7FFFFFFF) { 170 // The standard does not specify any range for tm_year, so INT_MAX 171 // should be valid. 172 checkStrftime("%y", &tm5, "47"); 173 checkStrftime("%Y", &tm5, "+2147485547"); 174 checkStrftime("%011Y", &tm5, "02147485547"); 175 if (sizeof(time_t) * CHAR_BIT >= 64) { 176 checkStrftime("%s", &tm5, "67768036160140800"); 177 } 178 } 179 180 return t_status; 181} 182