anilmwr
anilmwr

Reputation: 477

In Perl how to find the date of the previous Monday for a given date?

I am looking for a Perl script which can give me the last Monday for any specified date.

e.g. For date 2011-06-11, the script should return 2011-06-06

Upvotes: 10

Views: 9472

Answers (9)

bessarabov
bessarabov

Reputation: 11871

There are lot of ways to do it in Perl. Here is how it can be done with Perl library Moment.

#!/usr/bin/perl

use strict;
use warnings FATAL => 'all';
use feature 'say';

use Moment;

sub get_monday_date {
    my ($date) = @_;

    my $moment = Moment->new( dt => "$date 00:00:00" );

    my $weekday_number = $moment->get_weekday_number( first_day => 'monday' );

    my $monday = $moment->minus( day => ($weekday_number - 1) );

    return $monday->get_d();
}

say get_monday_date('2011-06-11'); # 2011-06-06

Upvotes: 1

Cristina
Cristina

Reputation: 21

If you are a slave like me and have to use a corporate Perl without libraries and you are not allowed to install them either, old fashioned way:

my $datestring = "";
my $secondsEpoc = time(); #gives the seconds from system epoch
my $secondsWantedDate;
my $seconds2substract;

$datestring = localtime($secondsEpoc);
print "Today's date and time ".$datestring."\n";
my ($second,$minute,$hour,$d,$M,$y,$wd,$yd) = (localtime)[0,1,2,3,4,5,6,7];
#print "hour: ".$hour;
#print "minute: ".$minute;
#print "second: ".$second;
#print "week day: ".$wd; #week day is 1=Monday .. 7=Sunday

$seconds2substract = 24 * 60 * 60;  # seconds in 24 hours
$secondsWantedDate=$secondsEpoc-$seconds2substract;
$datestring = localtime($secondsWantedDate);
print "Yesterday at the same time ".$datestring."\n";


my $days2Substract = $wd-1;
$seconds2substract = ($days2Substract * 24 * 60 * 60);
$secondsWantedDate=$secondsEpoc-$seconds2substract;
$datestring = localtime($secondsWantedDate);
print "Past Monday same time ".$datestring."\n";

$seconds2substract = ($days2Substract * 24 * 60 * 60) + ($hour *60 *60) + ($minute * 60) + $second;
$secondsWantedDate = $secondsEpoc-$seconds2substract;
$datestring = localtime($secondsWantedDate);
print "Past Monday at 00:00:00  ".$datestring."\n";

Hope it helps somebody!

Upvotes: 1

Axeman
Axeman

Reputation: 29854

At the end of this, $tstamp would have the timestamp you want:

use strict;
use warnings;
use POSIX qw<mktime>;

my $time = '2011-06-11';

my ( $year, $month, $day ) = split /-0?/, $time;
my $tstamp = mktime( 0, 0, 0, $day, $month - 1, $year - 1900 );
my $dow  = ( localtime $tstamp )[6];
$tstamp -= (( $dow > 1 ? 0 : 7 ) + $dow - 1 ) * 24 * 60 * 60;

This assumes that by "last Monday" you mean the last occurring Monday prior to the given day." So if the day of the week is Monday (1), then it subtracts and additional 7.

Upvotes: 1

oylenshpeegul
oylenshpeegul

Reputation: 3424

You could use Date::Manip, which has a Date_GetPrev function and understands "Monday"

$ perl -MDate::Manip -le 'print UnixDate(Date_GetPrev(shift, "Monday", 0), "%Y-%m-%d")' 2011-06-11
2011-06-06

Upvotes: 2

cjm
cjm

Reputation: 62109

I'm assuming that if the given date is a Monday, you want the same date (and not the previous Monday). Here's one way to do it with DateTime:

use DateTime;

my $date = DateTime->new(year => 2011, month => 6, day => 11);
my $desired_dow = 1;            # Monday
$date->subtract(days => ($date->day_of_week - $desired_dow) % 7);
print "$date\n";

(Actually, for the special case of Monday, the % 7 isn't necessary, because $date->day_of_week - 1 will always be 0–6, and that mod 7 is a no-op. But with the % 7, it works for any desired day-of-week, not just Monday.)

If you did want the previous Monday, you can change the subtraction:

$date->subtract(days => ($date->day_of_week - $desired_dow) % 7 || 7);

If you need to parse a date entered on the command line, you might want to look at DateTime::Format::Natural.

Upvotes: 26

DavidO
DavidO

Reputation: 13942

In the spirit of Perl, There Is More Than One Way To Do It.

use Modern::Perl;
use Date::Calc qw/Day_of_Week/;
my $date = '2011/6/11';
my @fields = split /\//, $date;
my @new_date = Add_Delta_Days( @fields , 1 - Day_of_Week( @fields ) );
say join "/", @new_date;

Upvotes: 3

Dave Cross
Dave Cross

Reputation: 69274

Pretty simple stuff using the standard Perl library.

#!/usr/bin/perl

use strict;
use warnings;
use 5.010;

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

my $date = shift || die "No date given\n";

my @date = split /-/, $date;
$date[0] -= 1900;
$date[1]--;

die "Invalid date: $date\n" unless @date == 3;

my $now = timelocal(0, 0, 12, reverse @date);

while (strftime('%u', localtime $now) != 1) {
  $now -= 24 * 60 * 60;
}

I'll leave it as an exercise for the reader to look up the various modules and functions used.

It's probably even simpler if you use DateTime.

Upvotes: 4

mirod
mirod

Reputation: 16161

You could also use Time::ParseDate, which understand "last Monday".

A one-liner to maintain Perl's reputation:

perl -MTime::ParseDate -M'POSIX qw(strftime)' -l -e'foreach (@ARGV) { my $now= parsedate( $_); my $e= parsedate( "last Monday", NOW => $now) ; print "$_ : ", strftime "%F", localtime( $e)}' 2011-06-11 2011-06-12 2011-06-13 2011-06-14

And a sane script:

#!/usr/bin/perl

use strict;
use warnings;

use Time::ParseDate;    # to parse dates
use POSIX qw(strftime); # to format dates

foreach my $date (@ARGV) 
  { my $date_epoch= parsedate( $date) || die"'cannot parse date '$date'\n";
    my $monday= parsedate( "last Monday", NOW => $date_epoch);                  # last Monday before NOW
    print "Monday before $date: ", strftime( "%F", localtime( $monday)), "\n";  # %F is YYYY-MM-DD
  }

A couple of notes: if the date is a Monday, then you get the previous Monday, which may or may not be what you want, to change that just set NOW to the next day (add 60*60*24, a day, to $date_epoch). Then Time::ParseDate is pretty liberal, it will happily parse 2011-23-38 for example (as 2012-12-09).

Upvotes: 12

Jerry Coffin
Jerry Coffin

Reputation: 490178

Zeller's congruence will give you the day of the week. From there it should be pretty easy.

Upvotes: 1

Related Questions