Quickly getting to YYYY-mm-dd HH:MM:SS in Perl

PerlDatetimeFormattingTimestamp

Perl Problem Overview


When writing Perl scripts I frequently find the need to obtain the current time represented as a string formatted as YYYY-mm-dd HH:MM:SS (say 2009-11-29 14:28:29).

In doing this I find myself taking this quite cumbersome path:

  • man perlfunc
  • /localtime to search for localtime - repeat five times (/ + \n) to reach the relevant section of the manpage
  • Copy the string ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); from the manpage to my script.
  • Try with my $now = sprintf("%04d-%02d-%02d %02d:%02d:%02d", $year, $mon, $mday, $hour, $min, $sec);
  • Remember gotcha #1: Must add 1900 to $year to get current year.
  • Try with my $now = sprintf("%04d-%02d-%02d %02d:%02d:%02d", $year+1900, $mon, $mday, $hour, $min, $sec);
  • Remember gotcha #2: Must add 1 to $mon to get current month.
  • Try with my $now = sprintf("%04d-%02d-%02d %02d:%02d:%02d", $year+1900, $mon+1, $mday, $hour, $min, $sec);
  • Seems ok. Done!

While the process outlined above works it is far from optimal. I'm sure there is a smarter way, so my question is simply:

What is the easiest way to obtain a YYYY-mm-dd HH:MM:SS of the current date/time in Perl?

Where "easy" encompasses both "easy-to-write" and "easy-to-remember".

Perl Solutions


Solution 1 - Perl

Use strftime in the standard POSIX module. The arguments to strftime in Perl’s binding were designed to align with the return values from localtime and gmtime. Compare

strftime(fmt, sec, min, hour, mday, mon, year, wday = -1, yday = -1, isdst = -1)

with

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

Example command-line use is

$ perl -MPOSIX -le 'print strftime "%F %T", localtime $^T'

or from a source file as in

use POSIX;

print strftime "%F %T", localtime time;

Some systems do not support the %F and %T shorthands, so you will have to be explicit with

print strftime "%Y-%m-%d %H:%M:%S", localtime time;

or

print strftime "%Y-%m-%d %H:%M:%S", gmtime time;

Note that time returns the current time when called whereas $^T is fixed to the time when your program started. With gmtime, the return value is the current time in GMT. Retrieve time in your local timezone with localtime.

Solution 2 - Perl

Why not use the DateTime module to do the dirty work for you? It's easy to write and remember!

use strict;
use warnings;
use DateTime;

my $dt   = DateTime->now;   # Stores current date and time as datetime object
my $date = $dt->ymd;   # Retrieves date as a string in 'yyyy-mm-dd' format
my $time = $dt->hms;   # Retrieves time as a string in 'hh:mm:ss' format

my $wanted = "$date $time";   # creates 'yyyy-mm-dd hh:mm:ss' string
print $wanted;

Once you know what's going on, you can get rid of the temps and save a few lines of code:

use strict;
use warnings;
use DateTime;

my $dt = DateTime->now;
print join ' ', $dt->ymd, $dt->hms;

Solution 3 - Perl

Try this:

use POSIX qw/strftime/;
print strftime('%Y-%m-%d',localtime);

the strftime method does the job effectively for me. Very simple and efficient.


Solution 4 - Perl

Time::Piece (in core since Perl 5.10) also has a strftime function and by default overloads localtime and gmtime to return Time::Piece objects:

use Time::Piece;
print localtime->strftime('%Y-%m-%d');

or without the overridden localtime:

use Time::Piece (); 
print Time::Piece::localtime->strftime('%F %T');

Solution 5 - Perl

I made a little test (Perl v5.20.1 under FreeBSD in VM) calling the following blocks 1.000.000 times each:

A

my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
my $now = sprintf("%04d-%02d-%02d %02d:%02d:%02d", $year+1900, $mon+1, $mday, $hour, $min, $sec);

B

my $now = strftime('%Y%m%d%H%M%S',localtime);

C

my $now = Time::Piece::localtime->strftime('%Y%m%d%H%M%S');

with the following results:

A: 2 seconds

B: 11 seconds

C: 19 seconds

This is of course not a thorough test or benchmark, but at least it is reproducable for me, so even though it is more complicated, I'd prefer the first method if generating a datetimestamp is required very often.

Calling (eg. under FreeBSD 10.1)

my $now = `date "+%Y%m%d%H%M%S" | tr -d "\n"`;

might not be such a good idea because it is not OS-independent and takes quite some time.

Best regards, Holger

Solution 6 - Perl

if you just want a human readable time string and not that exact format:

$t = localtime;
print "$t\n";

prints

Mon Apr 27 10:16:19 2015

or whatever is configured for your locale.

Solution 7 - Perl

Time::Piece::datetime() can eliminate T.

use Time::Piece;
print localtime->datetime(T => q{ });

Solution 8 - Perl

Short and sweet, no additional modules needed:

my $toDate = `date +%m/%d/%Y" "%l:%M:%S" "%p`;

Output for example would be: 04/25/2017 9:30:33 AM

Solution 9 - Perl

In many cases, the needed 'current time' is rather $^T, which is the time at which the script started running, in whole seconds (assuming only 60 second minutes) since the UNIX epoch.

This to prevent that an early part of a script uses a different date (or daylight-saving status) than a later part of a script, for example in query-conditions and other derived values.

For that variant of 'current time', one can use a constant, also to document that it was frozen at compile time:

use constant YMD_HMS_AT_START => POSIX::strftime( "%F %T", localtime $^T );

Alternative higher resolution startup time:

0+ [ Time::HiRes::stat("/proc/$$") ]->[10]

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionknorvView Question on Stackoverflow
Solution 1 - PerlGreg BaconView Answer on Stackoverflow
Solution 2 - PerlZaidView Answer on Stackoverflow
Solution 3 - PerlVishView Answer on Stackoverflow
Solution 4 - PerlMkVView Answer on Stackoverflow
Solution 5 - PerlHolgerView Answer on Stackoverflow
Solution 6 - PerlrobmView Answer on Stackoverflow
Solution 7 - PerlernixView Answer on Stackoverflow
Solution 8 - PerlOff The GoldView Answer on Stackoverflow
Solution 9 - Perldruid62View Answer on Stackoverflow