3

I would like a simple way to get yesterday's date (local time) as a string in a Perl script. Preferably, I would like to do this with no module dependencies, since we have a bare bones Perl 5.12 installation.

So, something like:

my $yesterdays_date=...; # Puts for example '301011' into $yesterdays_date, 
                         # if today is October 31st, 2011
Michael Goldshteyn
  • 71,784
  • 24
  • 131
  • 181
  • 3
    Yesterday isn't always 86_400 seconds ago, thanks to daylight savings and leap seconds. Do you need to know the date 86_400 seconds ago (as the current answers instruct), or do you need to know yesterday's calendar date? – pilcrow Oct 31 '11 at 19:19
  • I am after yesterday's calendar date, but given our local 2AM -> 1AM and vice versa DST conversion, can you come up with a case where subtracting 86,400 seconds will not give you yesterday's date? – Michael Goldshteyn Oct 31 '11 at 19:21
  • 3
    In my time zone, 13 Mar 2011 had only 23 hours. What day, then, is 86_400 seconds before 00:30 on the following day, 14 Mar 2011? In my time zone, 06 Nov 2011 will have 25 hours. What day is 86_400 seconds before 23:30 on 06 Nov 2011? – pilcrow Oct 31 '11 at 20:27
  • see also: http://stackoverflow.com/questions/3506475/how-do-i-get-yesterdays-date-using-localtime/3508717#3508717 – bigiain Nov 03 '11 at 01:06

4 Answers4

12

Time::Piece is core:

use Time::Piece;
use Time::Seconds qw(ONE_DAY);

my $yesterday = localtime() - ONE_DAY();
print $yesterday->strftime('%d%m%y'), "\n";

If you're concerned about daylight savings, you can normalize the current time to near noon:

use Time::Piece;
use Time::Seconds qw(ONE_DAY ONE_HOUR);

my $today = localtime;
my $yesterday = $today + ONE_HOUR * ( 12 - $today->hour ) - ONE_DAY;
print $yesterday->strftime("%d%m%y"), "\n";

If you can live with dependencies, then use DateTime:

use DateTime;

print DateTime->now->subtract(days => 1)->strftime('%d%m%y'), "\n";
Miller
  • 34,962
  • 4
  • 39
  • 60
runrig
  • 6,486
  • 2
  • 27
  • 44
  • 1
    You of course meant $yesterday->strftime('%d%m%y'), but this does the job, thanks! – Michael Goldshteyn Oct 31 '11 at 19:06
  • Since you seem to have answered and run off, I FTFY :) – Michael Goldshteyn Oct 31 '11 at 20:10
  • 1
    FWIW, the second technique, of regressing from today at 00:00 hours, can be done entirely with POSIX.pm: `strftime q|%d%m%y|, localtime(mktime(0, 0, 0, (localtime)[3,4,5], 0 ,0) - 2*60)`. It's not guaranteed to avoid DST/civil-time-adjustment bugs, but is less likely to encounter them than the naive approach. – pilcrow Nov 01 '11 at 12:09
  • If you feel you really must do date math by adding and subtracting a days worth of seconds the safest method is to adjust the date to noon (saving the time portion if it's needed) and then doing any math (then restore the saved time portion if it's needed). – Ven'Tatsu Nov 02 '11 at 16:02
  • @Ven'Tatsu: updated. And sometimes, you must use what's available and don't have time to get infrastructure to install things in production. I use DateTime when available. – runrig Nov 02 '11 at 21:56
  • ...and the OP asked for no dependencies. – runrig Nov 02 '11 at 23:10
12

If you're willing to go with dependencies, DateTime will generally do anything you need.

use strict;
use warnings;
use 5.012;

use DateTime;

say DateTime->now->subtract(days => 1)->strftime('%d%m%y');
Oesor
  • 6,632
  • 2
  • 29
  • 56
  • 5
    I mean, I understand not wanting dependencies, but my headaches with 'how do I do $x right with dates and times' really all disappeared after I started using DateTime for everything. – Oesor Oct 31 '11 at 20:21
  • @Ven'Tatsu, hear, hear. +1 to the answer and +1 to the comment. – pilcrow Oct 31 '11 at 20:30
  • @runrig: needs 5.10 minimum for say. – Oesor Nov 03 '11 at 15:55
0

Just subtract 24 hours (24 hours * 60 minutes * 60 seconds) from current time and get localtime:

say scalar localtime(time - 60*60*24);
# Sun Oct 30 21:04:30 2011

Note, that localtime returns time in string format only in scalar context. If you need to generate 'DDMMYY' you can just use data structure returned by list context:

my @tm = localtime(time - 60*60*24);
my $date = sprintf("%02d%02d%2d", $tm[3], $tm[4]+1, $tm[5] + 1900);
# 30102011
yko
  • 2,710
  • 13
  • 15
0

You can use the POSIX module thusly:

perl -MPOSIX=strftime -le 'print strftime "%m%d%y",localtime(time-(60*60*24))'
JRFerguson
  • 7,426
  • 2
  • 32
  • 36
  • 3
    Be careful about subtracting exactly 24 hours in `localtime`. Once a year for many locals there are only 23 hours in a day, and once a year there are 25 hours in a day. In either case if your code is run at just the right time the result will be two days ago, or today. – Ven'Tatsu Oct 31 '11 at 19:54
  • If our DST conversion is 1 AM -> 2 AM and vice versa, at what time of the day will subtracting 24 hours from localtime present a problem? I can see how this can be a problem for other time zones, but living under CST makes life easier. – Michael Goldshteyn Oct 31 '11 at 20:14
  • @MichaelGoldshteyn : The actual transition in the USA is at 01:59:59 either forward to 03:00:00 or backward to 01:00:00. – JRFerguson Oct 31 '11 at 20:27
  • If you subtract 24 hours in seconds from the time '2011-11-06 23:30' the resulting time is '2011-11-06 00:30', this is because the date 2011-11-06 has 25 hours in it's day in the US. – Ven'Tatsu Oct 31 '11 at 20:35