Debugger
Debugger

Reputation: 532

How do I get yesterday's date in perl?

Currently i take today date using below.I need to get yesterday date using this.. how can i get that ?

my $today = `date "+%Y-%m-%d"`;

Upvotes: 11

Views: 7473

Answers (6)

ikegami
ikegami

Reputation: 385897

If you want yesterday's date:

use DateTime qw( );

my $yday_date =
   DateTime
      ->now( time_zone => 'local' )
      ->set_time_zone('floating')
      ->truncate( to => 'day' )
      ->subtract( days => 1 )
      ->strftime('%Y-%m-%d');

For example, in New York on 2019-05-14 at 01:00:00, it would have returned 2019-05-13.

For example, in New York on 2019-11-04 at 00:00:00, it would have returned 2019-11-03.

Note that ->now( time_zone => 'local' )->set_time_zone('floating')->truncate( to => 'day' ) is used instead of ->today( time_zone => 'local' ) to avoid this problem.


If you want the time a day earlier:

use DateTime qw( );

my $yday_datetime =
   DateTime
      ->now( time_zone => 'local' )
      ->subtract( days => 1 )
      ->strftime('%Y-%m-%d %H:%M:%S');

For example, in New York on 2019-05-14 at 01:00:00, it would have returned 2019-05-13 01:00:00.

For example, in New York on 2019-03-10 at 12:00:00, it would have returned 2019-03-09 12:00:00.

For example, in New York on 2019-03-11 at 02:30:00, it would have resulted in an error. 2019-03-10 02:30:00 didn't exist because of the switch to Daylight Saving Time.


If you want the time 24 hours earlier:

use DateTime qw( );

my $yday_datetime =
   DateTime
      ->now( time_zone => 'local' )
      ->subtract( hours => 24 )
      ->strftime('%Y-%m-%d %H:%M:%S');

For example, in New York on 2019-05-14 at 01:00:00, it would have returned 2019-05-13 01:00:00.

For example, in New York on 2019-03-10 at 12:00:00, it would have returned 2019-03-09 11:00:00.

For example, in New York on 2019-03-11 at 02:30:00, it would have returned 2019-03-10 01:30:00.

Upvotes: 15

zdim
zdim

Reputation: 66881

Using DateTime module

use strict;
use warnings;
use feature 'say';

use DateTime;

my $today = DateTime->today(time_zone => 'local');

my $yesterday = $today->clone->add(days => -1);

say $yesterday->ymd;  #--> 2019-05-13

or directly

my $yesterday = DateTime->today(time_zone => 'local')->add(days => -1);

Now these are objects with which you can do practically anything date-time related.

To extract a string in the question's format use $yesterday->ymd since ymd's default format is %Y-%m-%d. Practically arbitrary formats can be obtained using strftime method.


There is no reason to reach for system facilities for a job like this. More to the point, the module is incomparably more sophisticated and rounded, for all kinds of curious cases and needs.

An example: At some date-times, as Daylight Saving Time kicks in, certain time periods just don't exist. The docs offer an example of 2003-04-06, when 01:59:59 "jumps" to 03:00:00 and that hour is gone. The module handles attempts to use such (non-existing times) correctly, by throwing errors.

And if you need to do any work with dates then using system's date isn't even an option since you get back merely a string, which you'd have to parse by hand for any further use.


It has been added that in fact the time is wanted as well, not only the date. Then, for example

my $today = DateTime->now(time_zone => 'local');

say $today->strftime("%Y%m%d_%H.%M.%S");         #--> 20190522_22.44.23

my $yesterday = $today->clone->add(days => -1);

say $yesterday->strftime("%Y%m%d_%H.%M.%S");     #--> 20190521_22.44.23

where method now "keeps" the (local) time, along with the date (today is truncate-ed now).

Upvotes: 10

Grinnz
Grinnz

Reputation: 9231

With Time::Moment, for just yesterday's date:

use strict;
use warnings;
use Time::Moment;
my $yesterday = Time::Moment->now->minus_days(1)->strftime('%Y-%m-%d');

Time::Moment works in instants and offsets, not time zones, so if you want the exact date and time of "one day ago" in your local time zone as in the DateTime examples, you can use Time::Moment::Role::TimeZone.

use strict;
use warnings;
use Time::Moment;
use Role::Tiny ();
my $class = Role::Tiny->create_class_with_roles('Time::Moment', 'Time::Moment::Role::TimeZone');
my $yesterday = $class->now->minus_days(1)->with_system_offset_same_local; # 1 day ago
my $yesterday = $class->now->minus_days(1)->with_system_offset_same_instant; # 24 hours ago

And the same caveats apply if the current time does not exist in the previous day in the local time zone.

Upvotes: 4

Dave Cross
Dave Cross

Reputation: 69274

I recommend using DateTime (as described in ikegami's answer). But if you don't want to install a CPAN module, this method uses only features available in the standard Perl installation.

#!/usr/bin/perl

use strict;
use warnings;
use feature 'say';

use Time::Local;
use POSIX 'strftime';

# Get the current date/time
my ($sec, $min, $hr, $day, $mon, $yr) = localtime;

# Get the epoch seconds for midday today
# (we use midday to eliminate potential problems
# when entering or leaving daylight savings time)
my $midday = timelocal(0, 0, 12, $day, $mon, $yr);

# Subtract a day's worth of seconds from the epoch
my $midday_yesterday = $midday - (24 * 60 * 60);

# Convert that epoch value to a string date using
# localtime() and POSIX::strftime().
my $yesterday = strftime('%Y%m%d', localtime($midday_yesterday));

say $yesterday;

Upvotes: 5

gugod
gugod

Reputation: 830

Using the backtick string has some quirks.... I generally disklike that operator.

Let me recommand the use of localtime() function provided by Time::Piece module (there is a bulitin localtime() function, but the one from Time::Piece is awesomer :)


use Time::Piece;

my ($t, $today, $yesterday);

$t = localtime();
$today = sprintf('%04d/%02d/%02d', $t->year, $t->mon, $t->mday);

$t = localtime(time() - 86400);
$yesterday = sprintf('%04d/%02d/%02d', $t->year, $t->mon, $t->mday);

Upvotes: 1

Heyddo
Heyddo

Reputation: 102

my $yesterday = `date -d yesterday +%Y%m%d-%H%M%S`;

Upvotes: 1

Related Questions