http://qs1969.pair.com?node_id=666044

Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks!

How can I get yesterday's date from today's date, but making sure I don't get weekends for yesterday's date.
I can get yesterday's date using this:
#!/usr/bin/perl use strict; use CGI qw/:standard/; use CGI::Carp qw(fatalsToBrowser); use Date::Calc qw(Add_Delta_Days Day_of_Week); use Date::Calc qw(Today Add_Delta_Days); print header(); my @date = Add_Delta_Days( Today(), -1 ); print "@date\n";

But if I run it I am getting "2008-2-3" and it's a weekend date, any help?

Thanks!!!

Replies are listed 'Best First'.
Re: Yesterday Date
by apl (Monsignor) on Feb 04, 2008 at 19:26 UTC
    use Date::Business; my $Target = new Date::Business( OFFSET => -1 );
    The above returns a string of the prior (today -1 ) business date.

    If you do a little initialization, you can also ignore holidays, or determine the day before any specified date.

Re: Yesterday Date
by moritz (Cardinal) on Feb 04, 2008 at 19:29 UTC

    Date::Simple to the help.

    #!/usr/bin/perl use strict; use warnings; use Date::Simple qw(today); my $d = today() - 1; $d-- while ($d->day_of_week == 0 or $d->day_of_week == 6); print $d, $/;
      This gets the right date and no weekend, can you explain what this code is doing, specially the "$d--" ? Is there another way to write the some code?
        $d-- is short for $d = $d -1, that is "subtract one from $d".

        Date::Simple provides a date object, and you can add and subtract number from that, so today() - 1 is yesterday.

        Then it decreases the value by one while the day of week is 0 (Sunday) or 6 (Saturday).

Re: Yesterday Date
by toolic (Bishop) on Feb 04, 2008 at 19:11 UTC
    I do not have Date::Calc installed (so I can not verify this), but, looking at the documentation, it would seem that you could use Day_of_Week to determine if today is Monday or not. If it is Monday, then subtract 3 days, else subtract one day.
Re: Yesterday Date
by ForgotPasswordAgain (Priest) on Feb 04, 2008 at 19:37 UTC

    There's probably an equivalent with DateTime, but it always takes me too long to figure out, so I end up using Date::Manip :

    use Date::Manip; ... $date = Date_PrevWorkDay($date,$off [,$time]);
      How can DateTime be too hard to figure out? Come on!
      use DateTime; my $date = DateTime->new( month => 2, day => 4, year => 2008 ); print "Start Date: " . $date->mdy . "\n"; $date->subtract( days => 1); print "Yesterday's Date: " . $date->mdy . "\n"; while( $date->day_of_week > 5) { $date->subtract( days => 1); } print "Next weekday date is " . $date->mdy() . "\n";

      See! Easy as pie, a cow pie even! :)

      How could one use this?
      Would that be that the $date is today's date, what would $off be, and $time be?
        For an explanation of how to use an installed module, for example, Date::Manip
        perldoc date::manip
        for any of the other modules, substitute the name of your selection.
      I recommend Date::Manip does everything but wash windows! One package to install, one to learn.
Re: Yesterday Date
by impossiblerobot (Deacon) on Feb 04, 2008 at 20:00 UTC

    The Date::Calc documentation answers this question in the "Recipes" section:

    How can I calculate the difference in days between dates, but without counting Saturdays and Sundays?


    Impossible Robot
Re: Yesterday Date
by Anonymous Monk on Feb 04, 2008 at 19:01 UTC
    Run it again tomorrow and see if you have the same problem. ;)
      That would ne nice and easy, but I need to know if I run it today I am not going to get a weekend...
Re: Yesterday Date
by jdporter (Paladin) on Feb 04, 2008 at 21:19 UTC

    A variation on a classic:

    my $yesterday_datetime = time; sleep 86_400;
    A word spoken in Mind will reach its own level, in the objective world, by its own weight

      This code has some serious problems. First of all, what if the current time is 11:30PM right before the Spring daylight-savings switch? After your sleep, it'll be 12:30AM two days later, not just one.

      Second scenario is that it's 12:30AM the morning of the Autumn switch? After your sleep, it'll be 11:30AM the same day.

      These are serious problems that you need to address.

      How about 12:00:00.1AM (midnight) on a day that has a leap *second* attached? After 86_400 seconds, you end up right before midnight on the same day!

      Serious serious problems with this code.

      :-)

      Pay attention to the stated requirements.

      How can I get yesterday's date from today's date, but making sure I don't get weekends for yesterday's date.

      my @is_business_day = (0, 1 x 5, 0); SNOOZE: while (sleep 86_400) { my $wday = ( localtime )[6]; last SNOOZE if $business_day[$wday]; } my $prev_business_day_datetime = time; sleep 86_400;

      This code is untested.

Re: Yesterday Date
by sundialsvc4 (Abbot) on Feb 04, 2008 at 19:36 UTC

    As the Monks have well-advised you, date handling is a penultimate “well-solved problem,” for which copious good and well-tested examples exist on CPAN. Grab the one that solves your problem most-completely and just drop it in.

    Dictum Ne Agas:   “Do Not Do A Thing Already Done.”

Re: Yesterday Date
by mifflin (Curate) on Feb 04, 2008 at 20:18 UTC
    Possible pure Perl solution...
    my $wday = (localtime)[6]; my $offset = $wday == 1 ? 3 : ($wday == 0 ? 2 : 1); my @date = localtime(time - 86400*$offset); printf "%s-%s-%s\n", 1900+$date[5], 1+$date[4], $date[3];
    Doesn't take into account holidays, just weekends.
      Also doesn't take into account Daylight_saving, where a day can be 25 hours long. As others stated, using a well-tested CPAN library is your best bet with date manipulation.
Re: Yesterday Date
by benizi (Hermit) on Feb 06, 2008 at 05:25 UTC

    Here's one without any module required. (Mainly for fun.) Take the current time. Find the day of the week. Then subtract 12 hours at a time while you're still on that day or you're on a weekend (day = 0 or 6 -- so abs(3-day) == 3). I think you avoid any Daylight Saving problems by going 12 hours at a time. (Going 24 hours at a time could skip the 23-hour day.) Someone correct me if that's wrong.

    my $t = time; my $dow = (localtime $t)[6]; my $new_dow; do { $t -= 43200; # half a day, to counter Daylight Saving effects $new_dow = (localtime $t)[6]; } while $dow == $new_dow or 3 == abs(3-$new_dow); my @ymd = (localtime $t)[5,4,3]; $ymd[0]+=1900; $ymd[1]++; my $date = sprintf "%04d-%02d-%02d", @ymd;