strftime.c revision 72445
172087Sbp/* 272087Sbp * Copyright (c) 1999 - 2000 Kungliga Tekniska H�gskolan 372087Sbp * (Royal Institute of Technology, Stockholm, Sweden). 472087Sbp * All rights reserved. 572087Sbp * 672087Sbp * Redistribution and use in source and binary forms, with or without 772087Sbp * modification, are permitted provided that the following conditions 872087Sbp * are met: 972087Sbp * 1072087Sbp * 1. Redistributions of source code must retain the above copyright 1172087Sbp * notice, this list of conditions and the following disclaimer. 1272087Sbp * 1372087Sbp * 2. Redistributions in binary form must reproduce the above copyright 1472087Sbp * notice, this list of conditions and the following disclaimer in the 1572087Sbp * documentation and/or other materials provided with the distribution. 1672087Sbp * 1772087Sbp * 3. Neither the name of KTH nor the names of its contributors may be 1872087Sbp * used to endorse or promote products derived from this software without 1972087Sbp * specific prior written permission. 2072087Sbp * 2172087Sbp * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY 2272087Sbp * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2372087Sbp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 2472087Sbp * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE 2572087Sbp * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2672087Sbp * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2772100Sru * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 28206622Suqs * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 2972087Sbp * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 3072087Sbp * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 3172087Sbp * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ 3272087Sbp 3372087Sbp#ifdef HAVE_CONFIG_H 3472087Sbp#include <config.h> 3572087Sbp#endif 3684306Sru#include "roken.h" 3784306Sru 3872087SbpRCSID("$Id: strftime.c,v 1.11 2000/07/08 14:22:12 assar Exp $"); 3986691Sarr 4072087Sbpstatic const char *abb_weekdays[] = { 4172087Sbp "Sun", 4272087Sbp "Mon", 4372087Sbp "Tue", 4472087Sbp "Wed", 4572087Sbp "Thu", 4672087Sbp "Fri", 4772087Sbp "Sat", 4872087Sbp}; 4972087Sbp 5072100Srustatic const char *full_weekdays[] = { 51140931Sru "Sunday", 5272100Sru "Monday", 53140931Sru "Tuesday", 5472087Sbp "Wednesday", 5572087Sbp "Thursday", 56236235Sgjb "Friday", 5772087Sbp "Saturday", 5872087Sbp}; 5972087Sbp 6072087Sbpstatic const char *abb_month[] = { 6172087Sbp "Jan", 6272087Sbp "Feb", 6372087Sbp "Mar", 64107788Sru "Apr", 6572087Sbp "May", 66107788Sru "Jun", 6772087Sbp "Jul", 6872087Sbp "Aug", 6972087Sbp "Sep", 7072087Sbp "Oct", 7172087Sbp "Nov", 7272087Sbp "Dec" 7372087Sbp}; 7472087Sbp 7572087Sbpstatic const char *full_month[] = { 7672087Sbp "January", 77107788Sru "February", 7872087Sbp "Mars", 7972087Sbp "April", 8072087Sbp "May", 8172087Sbp "June", 8272087Sbp "July", 8372087Sbp "August", 8472087Sbp "September", 8572087Sbp "October", 8672087Sbp "November", 8772087Sbp "December" 8872087Sbp}; 8972100Sru 9072087Sbpstatic const char *ampm[] = { 9172087Sbp "AM", 9272087Sbp "PM" 9372087Sbp}; 9472087Sbp 9572087Sbp/* 9672087Sbp * Convert hour in [0, 24] to [12 1 - 11 12 1 - 11 12] 9772087Sbp */ 9872087Sbp 9972087Sbpstatic int 10072087Sbphour_24to12 (int hour) 10172087Sbp{ 10272087Sbp int ret = hour % 12; 10372087Sbp 104107788Sru if (ret == 0) 10572100Sru ret = 12; 10672100Sru return ret; 10772087Sbp} 10879366Sru 10972087Sbp/* 11079366Sru * Return AM or PM for `hour' 11172087Sbp */ 112147647Shmp 11372087Sbpstatic const char * 114hour_to_ampm (int hour) 115{ 116 return ampm[hour / 12]; 117} 118 119/* 120 * Return the week number of `tm' (Sunday being the first day of the week) 121 * as [0, 53] 122 */ 123 124static int 125week_number_sun (const struct tm *tm) 126{ 127 return (tm->tm_yday + 7 - (tm->tm_yday % 7 - tm->tm_wday + 7) % 7) / 7; 128} 129 130/* 131 * Return the week number of `tm' (Monday being the first day of the week) 132 * as [0, 53] 133 */ 134 135static int 136week_number_mon (const struct tm *tm) 137{ 138 int wday = (tm->tm_wday + 6) % 7; 139 140 return (tm->tm_yday + 7 - (tm->tm_yday % 7 - wday + 7) % 7) / 7; 141} 142 143/* 144 * Return the week number of `tm' (Monday being the first day of the 145 * week) as [01, 53]. Week number one is the one that has four or more 146 * days in that year. 147 */ 148 149static int 150week_number_mon4 (const struct tm *tm) 151{ 152 int wday = (tm->tm_wday + 6) % 7; 153 int w1day = (wday - tm->tm_yday % 7 + 7) % 7; 154 int ret; 155 156 ret = (tm->tm_yday + w1day) / 7; 157 if (w1day >= 4) 158 --ret; 159 if (ret == -1) 160 ret = 53; 161 else 162 ++ret; 163 return ret; 164} 165 166/* 167 * 168 */ 169 170size_t 171strftime (char *buf, size_t maxsize, const char *format, 172 const struct tm *tm) 173{ 174 size_t n = 0; 175 size_t ret; 176 177 while (*format != '\0' && n < maxsize) { 178 if (*format == '%') { 179 ++format; 180 if(*format == 'E' || *format == 'O') 181 ++format; 182 switch (*format) { 183 case 'a' : 184 ret = snprintf (buf, maxsize - n, 185 "%s", abb_weekdays[tm->tm_wday]); 186 break; 187 case 'A' : 188 ret = snprintf (buf, maxsize - n, 189 "%s", full_weekdays[tm->tm_wday]); 190 break; 191 case 'h' : 192 case 'b' : 193 ret = snprintf (buf, maxsize - n, 194 "%s", abb_month[tm->tm_mon]); 195 break; 196 case 'B' : 197 ret = snprintf (buf, maxsize - n, 198 "%s", full_month[tm->tm_mon]); 199 break; 200 case 'c' : 201 ret = snprintf (buf, maxsize - n, 202 "%d:%02d:%02d %02d:%02d:%02d", 203 tm->tm_year, 204 tm->tm_mon + 1, 205 tm->tm_mday, 206 tm->tm_hour, 207 tm->tm_min, 208 tm->tm_sec); 209 break; 210 case 'C' : 211 ret = snprintf (buf, maxsize - n, 212 "%02d", (tm->tm_year + 1900) / 100); 213 break; 214 case 'd' : 215 ret = snprintf (buf, maxsize - n, 216 "%02d", tm->tm_mday); 217 break; 218 case 'D' : 219 ret = snprintf (buf, maxsize - n, 220 "%02d/%02d/%02d", 221 tm->tm_mon + 1, 222 tm->tm_mday, 223 (tm->tm_year + 1900) % 100); 224 break; 225 case 'e' : 226 ret = snprintf (buf, maxsize - n, 227 "%2d", tm->tm_mday); 228 break; 229 case 'F': 230 ret = snprintf (buf, maxsize - n, 231 "%04d-%02d-%02d", tm->tm_year + 1900, 232 tm->tm_mon + 1, tm->tm_mday); 233 break; 234 case 'g': 235 /* last two digits of week-based year */ 236 abort(); 237 case 'G': 238 /* week-based year */ 239 abort(); 240 case 'H' : 241 ret = snprintf (buf, maxsize - n, 242 "%02d", tm->tm_hour); 243 break; 244 case 'I' : 245 ret = snprintf (buf, maxsize - n, 246 "%02d", 247 hour_24to12 (tm->tm_hour)); 248 break; 249 case 'j' : 250 ret = snprintf (buf, maxsize - n, 251 "%03d", tm->tm_yday + 1); 252 break; 253 case 'k' : 254 ret = snprintf (buf, maxsize - n, 255 "%2d", tm->tm_hour); 256 break; 257 case 'l' : 258 ret = snprintf (buf, maxsize - n, 259 "%2d", 260 hour_24to12 (tm->tm_hour)); 261 break; 262 case 'm' : 263 ret = snprintf (buf, maxsize - n, 264 "%02d", tm->tm_mon + 1); 265 break; 266 case 'M' : 267 ret = snprintf (buf, maxsize - n, 268 "%02d", tm->tm_min); 269 break; 270 case 'n' : 271 ret = snprintf (buf, maxsize - n, "\n"); 272 break; 273 case 'p' : 274 ret = snprintf (buf, maxsize - n, "%s", 275 hour_to_ampm (tm->tm_hour)); 276 break; 277 case 'r' : 278 ret = snprintf (buf, maxsize - n, 279 "%02d:%02d:%02d %s", 280 hour_24to12 (tm->tm_hour), 281 tm->tm_min, 282 tm->tm_sec, 283 hour_to_ampm (tm->tm_hour)); 284 break; 285 case 'R' : 286 ret = snprintf (buf, maxsize - n, 287 "%02d:%02d", 288 tm->tm_hour, 289 tm->tm_min); 290 291 case 's' : 292 ret = snprintf (buf, maxsize - n, 293 "%d", (int)mktime((struct tm *)tm)); 294 break; 295 case 'S' : 296 ret = snprintf (buf, maxsize - n, 297 "%02d", tm->tm_sec); 298 break; 299 case 't' : 300 ret = snprintf (buf, maxsize - n, "\t"); 301 break; 302 case 'T' : 303 case 'X' : 304 ret = snprintf (buf, maxsize - n, 305 "%02d:%02d:%02d", 306 tm->tm_hour, 307 tm->tm_min, 308 tm->tm_sec); 309 break; 310 case 'u' : 311 ret = snprintf (buf, maxsize - n, 312 "%d", (tm->tm_wday == 0) ? 7 : tm->tm_wday); 313 break; 314 case 'U' : 315 ret = snprintf (buf, maxsize - n, 316 "%02d", week_number_sun (tm)); 317 break; 318 case 'V' : 319 ret = snprintf (buf, maxsize - n, 320 "%02d", week_number_mon4 (tm)); 321 break; 322 case 'w' : 323 ret = snprintf (buf, maxsize - n, 324 "%d", tm->tm_wday); 325 break; 326 case 'W' : 327 ret = snprintf (buf, maxsize - n, 328 "%02d", week_number_mon (tm)); 329 break; 330 case 'x' : 331 ret = snprintf (buf, maxsize - n, 332 "%d:%02d:%02d", 333 tm->tm_year, 334 tm->tm_mon + 1, 335 tm->tm_mday); 336 break; 337 case 'y' : 338 ret = snprintf (buf, maxsize - n, 339 "%02d", (tm->tm_year + 1900) % 100); 340 break; 341 case 'Y' : 342 ret = snprintf (buf, maxsize - n, 343 "%d", tm->tm_year + 1900); 344 break; 345 case 'z': 346 ret = snprintf (buf, maxsize - n, 347 "%ld", 348#if defined(HAVE_STRUCT_TM_TM_GMTOFF) 349 (long)tm->tm_gmtoff 350#elif defined(HAVE_TIMEZONE) 351 tm->tm_isdst ? 352 (long)altzone : 353 (long)timezone 354#else 355#error Where in timezone chaos are you? 356#endif 357 ); 358 break; 359 case 'Z' : 360 ret = snprintf (buf, maxsize - n, 361 "%s", 362 363#if defined(HAVE_STRUCT_TM_TM_ZONE) 364 tm->tm_zone 365#elif defined(HAVE_TIMEZONE) 366 tzname[tm->tm_isdst] 367#else 368#error what? 369#endif 370 ); 371 break; 372 case '\0' : 373 --format; 374 /* FALLTHROUGH */ 375 case '%' : 376 ret = snprintf (buf, maxsize - n, 377 "%%"); 378 break; 379 default : 380 ret = snprintf (buf, maxsize - n, 381 "%%%c", *format); 382 break; 383 } 384 if (ret >= maxsize - n) 385 return 0; 386 n += ret; 387 buf += ret; 388 ++format; 389 } else { 390 *buf++ = *format++; 391 ++n; 392 } 393 } 394 *buf++ = '\0'; 395 return n; 396} 397