Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

Re^2: Yesterday's date

by Corion (Patriarch)
on May 28, 2023 at 13:47 UTC ( [id://11152435]=note: print w/replies, xml ) Need Help??


in reply to Re: Yesterday's date
in thread Yesterday's date

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

Replies are listed 'Best First'.
Re^3: Yesterday's date
by hippo (Bishop) on May 28, 2023 at 14:20 UTC
    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';

    🦛

      This is because Time::Piece doesn't care as much about timezones and DST. When using DateTime (because I know it is exact with timezones, bordering on the unusable), in the following program, I can make things skip from 03/27/2023 to 03/25/2023:

      use 5.020; use Test2::V0; use DateTime; use DateTime::Format::Strptime; my $dstr = '2023-03-27 00:30'; my $strp = DateTime::Format::Strptime->new( pattern => '%Y-%m-%d %H:%M', locale => 'de_DE', time_zone => 'Europe/Paris', ); my $t = $strp->parse_datetime($dstr); diag $t->strftime('%Y-%m-%d %H:%M %z'); my $nt = $t->clone->subtract( seconds => 24*60*60 ); isnt $t->ymd('-'), $nt->ymd('-'); diag $nt->strftime('%Y-%m-%d %H:%M %z'); my $ddiff = $t->mday - $nt->mday; ok( ($ddiff < 0 || $ddiff == 1), '1 day different or month wrap'); $dstr = $nt->ymd ('-'); is $dstr, '2023-03-26';

      Update: I just realized that your code doesn't care about the time, and it (implicitly) always is at 00:00. Adjusting my example from 00:30 to 00:00 shows the problem there:

      use 5.020; use Test2::V0; use DateTime; use DateTime::Format::Strptime; my $dstr = '2023-03-27'; my $strp = DateTime::Format::Strptime->new( pattern => '%Y-%m-%d', locale => 'de_DE', time_zone => 'Europe/Paris', ); my $t = $strp->parse_datetime($dstr); diag $t->strftime('%Y-%m-%d %H:%M %z'); my $nt = $t->clone->subtract( seconds => 24*60*60 ); isnt $t->ymd('-'), $nt->ymd('-'); diag $nt->strftime('%Y-%m-%d %H:%M %z'); my $ddiff = $t->mday - $nt->mday; ok( ($ddiff < 0 || $ddiff == 1), '1 day different or month wrap'); $dstr = $nt->ymd ('-'); is $dstr, '2023-03-26';
        This is because Time::Piece doesn't care as much about timezones and DST.

        Precisely so. That's another good reason to use it in this sort of scenario where DST is a hindrance at best. I don't see why, given a problem where DST and timezones would only complicate things, the user would choose a non-core module where these are important over a core module which for the most part ignores them.

        For the general audience reading this, if you are used to DateTime or Date::Calc or any of the myriad other modules, I do recommend that you become at least passingly familiar with Time::Piece. It is pretty simple, fairly lightweight and core. It won't solve all problems but it handles a good subset of them, including the one in this thread, very well indeed.


        🦛

Re^3: Yesterday's date
by choroba (Cardinal) on May 28, 2023 at 20:02 UTC
    > 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]
Re^3: Yesterday's date
by ikegami (Patriarch) on May 31, 2023 at 14:50 UTC

    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.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://11152435]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others taking refuge in the Monastery: (2)
As of 2024-04-26 01:38 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found