Re: Formating datetime values
Posted in 1997
On Sun, 9 Nov 1997 nation@priapic.demon.co.uk wrote: > I need to format a datetime value to read as follows: > > 6:52PM > > At the mo I'm using %I:%M%p which gives 06:52PM. Close, but no banana.... > > Any suggestions? Well, you could try converting the datetime into a Unix time and then format it with strftime(3), but that's not guaranteed to give what you want. On Solaris 2.5.1, I get the result "09:18AM", for example. This is because the ANSI C standard defines the format from %I as producing a value 01-12. Since that will not work, you could alternatively obtain a public-domain strftime() workalike and fix it to do what you want. I have such source. You could add a %i (which is otherwise unused) which returns 1-12. That, of course, then makes your code dependent on a non-standard extension to the C standard (a good reason for renaming the modified strftime()). My code has no locale-support (it assumes English), and adds a %o (for ordinal) format, which prints the day of month value as 1st, 2nd, 3rd, etc. I reserve the right to have errors in the week number calculation. Yours, Jonathan Leffler (johnl@informix.com) #include <witticism.h> : "@(#): shar.sh,v 1.10 1997/06/02 21:45:00 johnl Exp $" #! /bin/sh # # This is a shell archive. # Remove everything above this line and run sh on the resulting file. # If this archive is complete, you will see this message at the end: # "All files extracted" # # Created: Mon Nov 10 09:27:26 PST 1997 by johnl at Informix Software Ltd. # Files archived in this archive: # strftime.c # #-------------------- if [ -f strftime.c -a "$1" != "-c" ] then echo shar: strftime.c already exists else echo 'x - strftime.c (8791 characters)' sed -e 's/^X//' >strftime.c <<'SHAR-EOF' X/* X@(#)File: $RCSfile: strftime.c,v $ X@(#)Version: $Revision: 1.12 $ X@(#)Last changed: $Date: 1997/08/08 00:47:20 $ X@(#)Purpose: Simulate STRFTIME(3) X@(#)Author: J Leffler X@(#)Copyright: (C) JLSS 1990-91,1997 X@(#)Product: :PRODUCT: X*/ X X/*TABSTOP=4*/ X/*LINTLIBRARY*/ X X/* -- Include Files */ X X#define _POSIX_SOURCE 1 X#include <stdio.h> X#include <ctype.h> X#include <string.h> X#include <time.h> X X/* -- Constant Definitions */ X X#define LONG_STRING 1024 X X#define LOCAL_TIME "%H:%M:%S" X#ifdef STRICT_STRFTIME X#define LOCAL_DATE "%d %B %Y" X#define LOCAL_DATETIME "%H:%M:%S %d %B %Y" X#else X#define LOCAL_DATE "%o %B %Y" X#define LOCAL_DATETIME "%H:%M:%S %o %B %Y" X#endif /* STRICT_STRFTIME */ X X#define NIL(x) ((x)0) X X#ifdef _POSIX_SOURCE X#define TZNAME X#undef TM_NAME X#undef TM_ZONE X#endif X X#ifdef TM_NAME X#define timezonename(x) ((x)->tm_name) X#endif /* TM_NAME */ X#ifdef TM_ZONE X#define timezonename(x) ((x)->tm_zone) X#endif /* TM_ZONE */ X#ifdef TZNAME X#define timezonename(x) (tzname[(x)->tm_isdst]) X#endif /* TZNAME */ X#ifndef timezonename Xerror "timezonename is not defined" X#endif X X/* -- Declarations */ X Xstatic const char *day_of_week[] = X{ X "Sunday", X "Monday", X "Tuesday", X "Wednesday", X "Thursday", X "Friday", X "Saturday" X}; X Xstatic const char *month_of_year[] = X{ X "January", X "February", X "March", X "April", X "May", X "June", X "July", X "August", X "September", X "October", X "November", X "December" X}; X X#ifndef lint Xstatic const char rcs[] = "@(#)$Id: strftime.c,v 1.12 1997/08/08 00:47:20 johnl Exp $"; X#endif X Xstatic char *ordinal(int n) X{ X int x; X static char *suffix[4] = {"th", "st", "nd", "rd"}; X static char string[15]; X X x = n % 100; X if (x == 11 || x == 12 || x == 13) X x = 0; X else if ((x = x % 10) > 3) X x = 0; X sprintf(string, "%d%s", n, suffix[x]); X return (string); X} X X/* X** Calculating week numbers: X** To give the correct answers, the LHS of any modulus operator must be a X** non-negative number. X** Given the day of the year (yd: 1..366) and the weekday it corresponds to X** (wd: 0..6), the day of the week of 1st January is readily derivable using X** j1 = (8 + wd - (yd % 7)) % 7 (equivalent to j1 = (372 + wd - yd) % 7). X** The other requisite input for the week number calculation is the reference X** day of the week (rd: 0..6), which is the day deemed to be the first day of X** the week (normally either 0 Sunday or 1 Monday). Week numbers have the X** range 00..53, where week 0 occurs before the first instance of rd in the X** year, week 1 starts on the first instance of rd in the year, and week 53 X** occurs when day 365 or 366 is the same day of the week as rd (or the day X** after for yd = 366). Given j1 and rd, the value ff = (j1 + 6 - rd) % 7 X** needs to be added to yd and the result divided by 7 to produce the week X** number. Combining these results and using the associative property of the X** modulus operator yields a function: X** wn(yd, wd, rd) = (yd + (378 + wd - rd - yd) % 7) / 7 X** X** To further complicate things, the value yd' supplied to the function below X** is the value yd' = yd - 1. The revised formula becomes: X** wn(yd', wd, rd) = (yd' + 1 + (379 + wd - rd - yd') % 7) / 7 X*/ X Xstatic int weekno(int yd, int wd, int rd) X/* yd -- Days since Jan 1st (0..365) */ X/* wd -- Day of week (0 Sunday) */ X/* rd -- First day of week (0 Sunday) */ X{ X return (yd + 1 + (379 + wd - rd - yd) % 7) / 7; X} X Xsize_t strftime(char *s, size_t sz, const char *f, const struct tm *lt) X{ X register char *dst; X register char *end; X register int slen; X int xxxx; X char c; X char *t; X X dst = s; X end = s + sz; X X while ((c = *f++) && dst < end) X { X#ifdef TEST X fprintf(stderr, "FC = %c\\n", c); X#endif /* TEST */ X if (c != '%') X *dst++ = c; X else X { X#ifdef TEST X fprintf(stderr, "FC = %c\\n", *f); X#endif /* TEST */ X switch (*f++) X { X case 'a': /* abbreviated weekday name */ X slen = 3; X if (dst < end - slen) X strncpy(dst, day_of_week[lt->tm_wday], slen); X else X dst = end; X break; X X case 'A': /* full weekday name */ X slen = strlen(day_of_week[lt->tm_wday]); X if (dst < end - slen) X strcpy(dst, day_of_week[lt->tm_wday]); X else X dst = end; X break; X X case 'b': /* abbreviated month name */ X slen = 3; X if (dst < end - slen) X strncpy(dst, month_of_year[lt->tm_mon], slen); X else X dst = end; X