devxlogo

Minimize Date and Time Display Drudgery

Minimize Date and Time Display Drudgery

any moons ago, I presented C++’s basic time and date facilities. At that time, however, I didn’t demonstrate how to format and customize the date and time. Such customizations may be needed when you localize an application, for example. Although internationalization and localization are notoriously complex, with some help from ‘s function strftime(), you can eliminate much of this drudgery?at least as far as the time and date are concerned.


How do you format the date and time in an easy and portable manner?


Use the strftime() library function.

Time for a Change
It’s hard to imagine a large-scale application that doesn’t rely on date and time calculations. In most cases, a crude representation of the system’s time (e.g., time_t) is used. However, when the date and time are presented in a human readable format, customization and formatting are necessary. In the United States, the accepted date format is MMDDYYYY. However, in many other countries the day precedes the month, as in 31/12/2007. Similarly, the common time format in the UK is based on a 12 hour clock, e.g., 6:30 PM, whereas in other countries a 24-hour clock is used instead i.e., 18:30. These locale-specific differences, along with text formatting, are all handled by the strftime() function declared in . strftime() takes a format string to compose a date and time string:

size_t strftime(char *s,                 size_t maxsz,                 const char *fmt,                 const struct tm *ptm);

The first parameter is the address of a memory buffer into which the resulting date and time string is written. The maxsz parameter specifies the maximum number of characters that can be written to s, excluding the terminating ‘’. The final argument is a pointer to a valid tm struct, which is obtained by calling localtime() and gmtime(). On success, strftime() returns the number of characters (excluding the terminating ‘’) written to s. If the number of characters required is greater than maxsz, strftime() returns 0.

The interesting bit for you is the third parameter fmt, the format string. It contains a sequence of escape characters and optional text. An escape sequence represents a certain date and time category (day, month, seconds). It consists of a % sign followed by a case-sensitive letter. For example, %a represents the abbreviated name of the day (Sun), %A stands for the full name of the day (Sunday). A complete list of all the POSIX escape sequences is available here. The ISO C89 and C99 lists of escape sequences are slightly different, so you should check your compiler’s documentation before using non-portable escapes.

It’s About Time
Let’s see strftime() in action. Suppose you want to display the current date and time in the following format:

Monday, February 05, 2007. The local time is: 16:01:26

Break this string down to its date and time components and pair them with their matching escapes (I’ll discuss the last three components later):

  • Full name of the weekday (%A)
  • Full name of the month (%B)
  • The numeric day of the month (%d)
  • A four digit year (%Y)
  • The hour of the day in a 24-hour clock
  • The minute of the hour (0-59)
  • The second of the minute (0-60, 60 used in a leap minute)

Here’s a complete program that uses the format string fmt to compose a date and time string according to the template above:

#include #include using namespace std;const int BUFSIZE=200;int main(){ time_t t = time(0); //obtain the current time_t value tm now=*localtime(&t); //convert it to tm char tmdescr[BUFSIZE]={0}; const char fmt[]="%A, %B %d %Y. The time is %X";  if (strftime(tmdescr, sizeof(tmdescr)-1, fmt, &now)>0);  cout<

The output is:

Monday, February 05 2007. The time is 07:09:55

At the heart of this program lies the following string format:

"%A, %B %d %Y. The time is %X";

The last escape sequence, %X, is tricky. I could have broken the timestamp into hours, minutes, and seconds?plus the intervening ':' characters between them. However, the %X escape sequence is convenient shorthand for hh:mm:ss so I used that instead. If you want to display only some of these components, for instance, only the hour and the minutes, use the individual escape sequences of each of these components.

Notice that the translation of escape sequences is locale-specific. The default locale "C" (or "POSIX") will use American English weekday and month names. However, after loading a French locale (either by calling setlocale() or setting the appropriate environment variables), the output of the same strftime() call changes to:

lundi, février 05 2007. The time is 07:09:55

That is, the value of each escape sequence depends on the current locale's representation of that category. Any hard-coded text embedded in the format string remains unmodified. This is why you should use dynamically loaded string tables (or message catalogs in POSIX parlance) instead of hard-coded text.

Now, suppose you want to display the abbreviated month name (%b), the numeric day of the month (%d), the day of the year (%j), and a two-digit year (%y). The new format string will change accordingly to:

"%b %d, day %j in %y"

The output is:

Feb 05, day 036 in 07

Notes on Code Safety
Visual Studio 2005 issues a spurious warning message when you use strftime(). You can safely ignore this warning (or better yet, disable it altogether). Remember, the key to code safety is awareness and through examination of strftime()'s behavior. My advice is to always test a function or class before using it in production code for the first time. In addition, consider the following issues:

  • Return Code: While most functions return zero to indicate success, strftime() returns a positive value on success, zero otherwise. This behavior is consistent with the rest of the printf() family of functions. If a strftime() call returns 0, you should also check the errno value to get more information about the cause of the failure:
    if (strftime(tmdescr, sizeof (tmdescr)-1, fmt, &now)==0){  cerr<<"strftime failed. Errno code: "<
  • Parameter Validation: If the format string contains an unrecognized escape sequence, the results are undefined. However, some implementations (Visual Studio 2005 for instance) validate every strftime() argument, including the escapes. Opt for an implementation that validates strftime() arguments carefully, paying attention to the format string in particular.
  • Thread-safety: In multithreaded apps, always copy the tm structure returned from localtime() and gmtime() to a private tm struct.
  • Buffer Overflows: The second parameter must be at least one byte smaller than the size of s because strftime() appends a terminating '' to s.
  • 64-bit Readiness: To ensure a smooth migration to 64-bits, stick to the time_t typedef. Implementations map time_t automatically to a 32-bit or a 64-bit representation (i.e., long long), depending on your compiler's settings and the target operating system. The code used in this 10-Minute Solution should run smoothly on both 32 and 64 systems, whereas __time64_t will only run on 64-bit Windows systems.

Efficient and Powerful
In spite of its old-fashioned look, strftime() enjoys immense popularity among developers. So much so that it has been ported to other programming languages such as PHP, Python, and Ruby. Believe it or not, even Java 1.5 has a Strftime class that uses a similar set of escape sequences. So don't frown at strftime(). When used with the proper security measures described above, strftime() can be an efficient and very powerful tool, particularly in internationalized projects. Furthermore, familiarity with strftime()'s interface will enable you to port C code to any of the aforementioned languages and environments.

devxblackblue

About Our Editorial Process

At DevX, we’re dedicated to tech entrepreneurship. Our team closely follows industry shifts, new products, AI breakthroughs, technology trends, and funding announcements. Articles undergo thorough editing to ensure accuracy and clarity, reflecting DevX’s style and supporting entrepreneurs in the tech sphere.

See our full editorial policy.

About Our Journalist