Formatting dates with strftime

[ Perl tips index ]
[ Subscribe to Perl tips ]

When formatting dates in Perl, a commonly seen technique is to use Perl's in-built localtime() function to gain information about the current time, and then use that to build our own date structure.

This commonly starts with the cargo-culted line:

 my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);

and usually ends with a tangled, messy web of difficult to maintain, and often buggy code.

The problem is that localtime returns a format that is distinctly user-unfriendly. The years are counted from 1900, months start at zero, and we're responsible for doing all our own formatting and padding. The workarounds to account for this are ghastly, and won't be repeated here.

If we wanted heavy-duty date formatting, we'd use the excellent DateTime framework from the CPAN, but what if we just want to produce our own formatted dates, using Perl's core functionality?

Enter strftime.

strftime is actually a C function from the POSIX 1003.1 standard. Luckily, the POSIX module which comes standard with Perl, and practically all modern operating systems implement the standard.

To use strftime, we supply a list of elements in the same format as the return from Perl's own localtime or gmtime functions.

        use POSIX qw(strftime);
        my $date = strftime("%Y-%m-%d %H:%M:%S\n", localtime(time));
        print $date;    # prints something like 2009-02-26 13:50:55

We can also supply our own text as well as format strings. For example:

        use POSIX qw(strftime);
        print strftime("The date is %Y-%m-%d, and the time is %H:%M:%S\n",
              localtime(time));
        # The date is 2009-02-26, and the time is 13:52:01

Format strings

Your first step in learning more about reading any module in Perl should be to read its documentation, which we can access with perldoc POSIX. Unfortunately, the entry for strftime refers you to your operating system's man page for further details. This isn't very useful if your system doesn't have that documentation installed, and you don't have a copy of POSIX 1003.1 sitting on your desk.

Even if you do have the strftime documentation, it's worth being a little bit careful. Standards are great, because there are so many to choose from, and the interpretation of the POSIX standard certainly varies between operating systems.

In particular, any format that involves words (days of the week, or months, or abbreviations thereof) and some of the ``preferred date format'' strings should depend upon the user's locale, but some systems ignore the locale entirely.

Portable formats

Below we list the format options which are portable, and should be implemented on all modern systems:

%d

The day of the month as a decimal number (range 01 to 31).

%H

The hour as a decimal number using a 24-hour clock (range 00 to 23).

%I

The hour as a decimal number using a 12-hour clock (range 01 to 12).

%j

The day of the year as a decimal number (range 001 to 366).

%m

The month as a decimal number (range 01 to 12).

%M

The minute as a decimal number (range 00 to 59).

%S

The second as a decimal number (range 00 to 60). (The range is up to 60 to allow for occasional leap seconds (and double leap seconds).)

%U

The week number of the current year as a decimal number, range 00 to 53, starting with the first Sunday as the first day of week 01. See also %W.

%w

The day of the week as a decimal, range 0 to 6, Sunday being 0.

%W

The week number of the current year as a decimal number, range 00 to 53, starting with the first Monday as the first day of week 01.

%y

The year as a decimal number without a century (range 00 to 99).

%Y

The year as a decimal number including the century.

%%

A literal `%' character.

Locale-dependent formats

The following formats may depend upon the user's locale. They're generally considered portable, but may return different strings for the same date, depending upon operating system and locale particulars:

%a

The abbreviated weekday name according to the current locale.

%A

The full weekday name according to the current locale.

%b

The abbreviated month name according to the current locale.

%B

The full month name according to the current locale.

%p

Either `AM' or `PM' according to the given time value, or the corresponding strings for the current locale. Noon is treated as `pm' and midnight as `am'.

Not recommended formats.

The following formats are not recommended. Often the ``preferred locale'' is ambiguous, sometimes it's ignored, and often it's both. Presenting a user with a date such as ``02/03/09'' can be a great source of confusion and angst, whereas ``2009-03-02'' is unambiguously clear.

The %c, %x, %X and %Z formats, while part of the standard, are all notorious for producing these sorts of ambiguous results, and while they're part of the standard, they should be avoided.

Other formats not listed in this tip may not be implemented on all systems, and should be used with care.

Examples

        use POSIX qw(strftime);
        # Thu 26 Feb 2009 13:49:54 EST
        print strftime("%a %d %b %Y %H:%M:%S %Z\n", localtime());
        # The below is the same as above due to our locale setting
        # Thu 26 Feb 2009 13:49:54 EST
        print strftime("%c\n", localtime());
        # Thursday 26 February 09, 01:49:54 PM (day 057)
        print strftime("%A %d %B %y, %I:%M:%S %p (day %j)\n", localtime());

Further information

[ Perl tips index ]
[ Subscribe to Perl tips ]


This Perl tip and associated text is copyright Perl Training Australia. You may freely distribute this text so long as it is distributed in full with this Copyright noticed attached.

If you have any questions please don't hesitate to contact us:

Email: contact@perltraining.com.au
Phone: 03 9354 6001 (Australia)
International: +61 3 9354 6001

Valid XHTML 1.0 Valid CSS