Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

Yesterday's date

by jpys (Novice)
on May 28, 2023 at 12:46 UTC ( [id://11152433]=perlquestion: print w/replies, xml ) Need Help??

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

I am seeking help with providing a date as DD/MM/YYYY within a script and having Perl provide yesterday's date in the same format. I am not concerned about daylight savings time, time zone nor do I need HMS. I just need to provide the script with a date and have it give me yesterday's date. I appreciate any help. Thank you in advance.

Replies are listed 'Best First'.
Re: Yesterday's date
by hippo (Bishop) on May 28, 2023 at 13:33 UTC

    I would be using Time::Piece for this since it is in core.

    #!/usr/bin/env perl use strict; use warnings; use Time::Piece; my $t = Time::Piece->strptime ($ARGV[0], '%d/%m/%Y'); printf "Date as supplied: %s\n", $t->dmy ('/'); $t = $t - 86400; printf "Date minus one day: %s\n", $t->dmy ('/');
    $ ./yesterday.pl 01/12/2022 Date as supplied: 01/12/2022 Date minus one day: 30/11/2022 $

    🦛

      Note that this approach will have a problem for those days with less than 24 hours (like when switching between normal and daylight savings time.

      I prefer the approach to iteratively subtract 22 hours until the (stringified) date changes:

      ... my $res = $t - 22*60*60; while( $res->ymd('-') eq $t->ymd('-') ) { $res -= 22*60*60; } return $res
        Note that this approach will have a problem for those days with less than 24 hours

        I would be interested to see a test case showing that, if you could provide one. The tests I tried all worked fine, even on 23-hour days. That's why I posted it as-is rather than trying to work around a problem which didn't appear to be there.

        Here's my trivial test script for comparison:

        use strict; use warnings; use Time::Piece; use Test::More tests => 366 * 2 + 1; my $dstr = '01/01/2023'; for (1 .. 366) { my $t = Time::Piece->strptime ($dstr, '%d/%m/%Y'); my $nt = $t - 86400; isnt $dstr, $nt->dmy ('/'); my $ddiff = $t->mday - $nt->mday; ok ($ddiff < 0 || $ddiff == 1), '1 day different or month wrap'; $dstr = $nt->dmy ('/'); } is $dstr, '31/12/2021';

        🦛

        > Note that this approach will have a problem for those days with less than 24 hours

        If you want Time::Piece to respect time zones, you need to initialize the object from localtime, not from the class itself:

        $ TZ=Europe/London perl -MTime::Piece -wE ' for my $source ("Time::Piece", scalar localtime()) { my $t = $source->strptime("2023/03/27", "%Y/%m/%d"); say $t - 86400; }' Sun Mar 26 00:00:00 2023 Sat Mar 25 23:00:00 2023

        map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]

        Note that this approach will have a problem for those days with less than 24 hours

        That's not true. Or rather, there are no days with less than 24 hours when dealing with UTC, as the parent code does.

      G'day hippo,

      ++ I agree with your approach; particularly in light of the OP's "I am not concerned about daylight savings time, time zone nor do I need HMS.".

      Having said that, I believe use of the ONE_DAY constant from Time::Seconds (also a core module) would add clarity.

      It's the same value:

      $ perl -E 'use Time::Seconds; say ONE_DAY' 86400

      It works as a direct replacement in your code:

      $ perl -e ' use strict; use warnings; use Time::Piece; use Time::Seconds; my $t = Time::Piece->strptime($ARGV[0], "%d/%m/%Y"); printf "Date as supplied: %s\n", $t->dmy("/"); $t = $t - ONE_DAY; printf "Date minus one day: %s\n", $t->dmy("/"); ' 01/12/2022 Date as supplied: 01/12/2022 Date minus one day: 30/11/2022

      — Ken

        If $Time::Seconds::ONE_DAY remains constant regardless of current time, then do not see how that would add "clarity" or see its purpose. If 24 *60 *60 conjures up magic number, then just assign that to a local variable.

Re: Yesterday's date
by 1nickt (Canon) on May 28, 2023 at 14:06 UTC

    With DateTime (DateTime::Format::Strptime):

    use strict; use warnings; use DateTime::Format::Strptime; my $parser = DateTime::Format::Strptime->new(pattern => '%d/%m/%Y', on +_error => 'croak'); my $dt = $parser->parse_datetime('28/05/2023'); print $dt->subtract(days => 1)->strftime('%d/%m/%Y'), "\n";

    Hope this helps!


    The way forward always starts with a minimal test.
Re: Yesterday's date
by tybalt89 (Monsignor) on May 29, 2023 at 05:03 UTC

    Avoid all those problems with short or long days and daylight savings time switches by using the middle of the day :)

    #!/usr/bin/perl use strict; # https://perlmonks.org/?node_id=11152433 use warnings; use Time::Piece; use Time::Seconds; @ARGV = '28/05/2023'; my $t = -ONE_DAY + Time::Piece->strptime("$ARGV[0] 12", "%d/%m/%Y %H") +; print localtime($t) . " should be near middle of the day\n\n"; printf "Date as supplied: %s\nDate minus one day: %s\n", $ARGV[0], $t- +>dmy("/");

    Outputs:

    Sat May 27 12:00:00 2023 should be near middle of the day Date as supplied: 28/05/2023 Date minus one day: 27/05/2023
Re: Yesterday's date
by jpys (Novice) on May 31, 2023 at 06:37 UTC
    I think I'm getting more than I bargained for. To try to clarify: The script I am working will ONLY be used in the Philippines, laptop knows the date/time of course. There is no DST here. What I need is this: The script will provide the date, from here I need to know what the day before that date was. The initial date will be provided by the script and it WON'T always be today. It could be 04/24/2023 or 05/31/2023 for example. From there I need to know what date yesterday was. Only the date, not HMS no other info. Just the date one day before the date the script provides. Thanks! I appreciate everyone's attention and help.

      Confusing: 04/24/2023 and 05/31/2023 are a direct contradiction to the DD/MM/YYYY given at start of post. Which is it?

        Hello, what I meant was it can be any date that the script will provide - I was just giving examples. The script format will display MMDDYYYY. From there I need to know how to figure out what the day before was. As to my examples the day before would be 04/23/2023 and 05/30/2023 respectively.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11152433]
Approved by 1nickt
Front-paged by kcott
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others scrutinizing the Monastery: (5)
As of 2024-04-23 23:49 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found