http://www.perlmonks.org?node_id=1037686

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

Hi Monks, What the best way to get 30 days or month ago from today’s date?
Here is what I have and they all print different dates:
se strict; use warnings; use Data::Dumper; use POSIX qw(strftime); use Date::Calc qw( Today Add_Delta_Days ); # get todays date::: my $today = sprintf "%04d%02d%02d", Today(); my $month_ago_1 = strftime("%Y%m%d",localtime(time() - 720*60*60)); my $month_ago_2 = sprintf "%04d/%02d/%02d",Add_Delta_Days( Today(), -3 +0 ); print "\n Today = $today\n\n"; print "$month_ago_1 - $month_ago_1\n"; my @date = localtime; $date[3] -= 4 * 7; my $month_ago = sprintf "%04d%02d%02d", @date; print "\n $month_ago\n"; my $month_ago_3 = strftime('%Y-%m-%d', localtime(time - 4 * 7 * 86400 +)); print "\n $month_ago_3\n"; exit;
Thanks for looking!

Replies are listed 'Best First'.
Re: Find 30 days from today's date
by golux (Chaplain) on Jun 07, 2013 at 15:58 UTC
    You're already using Date::Calc, so I'd go with Add_Delta_Days:
    #!/usr/bin/perl -w use strict; use warnings; use Date::Calc qw{ :all }; my ($year, $mon, $day) = Today(); show_date("Today's date", $year, $mon, $day); ($year, $mon, $day) = Add_Delta_Days($year, $mon, $day, -30); show_date("30 days ago", $year, $mon, $day); sub show_date { my ($label, $year, $mon, $day) = @_; my $date = sprintf "%04d-%02d-%02d", $year, $mon, $day; print "$label: $date\n"; } __END__ [Output] Today's date: 2013-06-07 30 days ago: 2013-05-08
    Update:    Oh, now I see why you're getting different answers. It's because in:
    $date[3] -= 4 * 7; ... my $month_ago_3 = strftime('%Y-%m-%d', localtime(time - 4 * 7 * 86400 +));
    You're subtracting 4 * 7 days (ie. 4 weeks), rather than 30 days.

    Does that help?

    say  substr+lc crypt(qw $i3 SI$),4,5
      4 weeks, one month and 30 days are all different. And then we are not even looking at the impact of such strange beasts as leap days, leap seconds, timezones, daylight saving time and more of this kind of "fun".

      CountZero

      A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

      My blog: Imperial Deltronics
Re: Find 30 days from today's date
by frozenwithjoy (Priest) on Jun 07, 2013 at 15:56 UTC
    #!/usr/bin/env perl use strict; use warnings; use feature 'say'; use DateTime; my $thirty_days_ago = DateTime->today->subtract(days => 30); say $thirty_days_ago; __END__ 2013-05-08T00:00:00
      If he wants the date where his computer is located (as opposed to the date somewhere in Europe),
      my $thirty_days_ago = DateTime->today(time_zone => 'local')->subtract( +days => 30);

      Note that the above solution will fail two days a year in time zones with no midnight on a DST change. (There is at least one such time zone.) Workaround:

      my $thirty_days_ago = DateTime->now(time_zone => 'local')->set_hour(12 +)->subtract(days => 30);
Re: Find 30 days from today's date
by aaron_baugher (Curate) on Jun 08, 2013 at 14:47 UTC

    On your three outputs, the first one succeeds in getting the date from 30 days ago, which may or may not be one month ago. The second fails because you subtract 28 from the day-of-month, which will have no effect on the rest of the date fields, and then you print out seconds, minutes, and hours anyway. The third succeeds in subtracting 28 days, which will give you "one month ago" if you happen to be in the first 28 days of March in a non-leap year.

    "One month ago" and "30 days ago" (or 28 days ago) are not the same thing. If you really want 30 days ago, that's easy: use your first example where you subtract 30*24*60*60 seconds from the current time and get the date from that. But if you really want one month ago, that won't work except when you're crossing a 30-day boundary. And you can't just get the month and decrement it (wrapping around the end of the year if necessary), because what if today is July 31? You'll get June 31, a non-existent date. And then there are leap-years... So if you really want one month ago, use Date::Calc and the Add_Delta_YM function and let the module handle that stuff.

    Aaron B.
    Available for small or large Perl jobs; see my home node.

Re: Find 30 days from today's date
by ambrus (Abbot) on Apr 18, 2014 at 11:30 UTC

    Try Date::Manip.

    use warnings; use strict; use Date::Manip::Date 6.30; my $today = Date::Manip::Date->new("today"); print $today->printf("Today is: %Y-%m-%d\n"); my $month_ago = $today->calc($today->new_delta("-1 months")); print $month_ago->printf("A month ago from today is: %Y-%m-%d\n"); my $thirty_ago = $today->calc($today->new_delta("-30 days")); print $thirty_ago->printf("Thirty days ago from today is: %Y-%m-%d\n") +; __END__

    The output today is this:

    Today is: 2014-04-18 A month ago from today is: 2014-03-18 Thirty days ago from today is: 2014-03-19
    There's a difference between the two because March had 31 days.
Re: Find 30 days from today's date
by Discipulus (Canon) on Apr 18, 2014 at 11:35 UTC

    perl -e "print scalar localtime (time - $ARGV[0] * 86400)" 30 #output: Wed Mar 19 12:34:19 2014
    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.

      A couple of tweaks improve it somewhat:

      C:\test>perl -e "$x = scalar localtime (int(time()/43200)*43200 - $ARG +V[0] * 86400); substr($x,11,9,''); print $x" 30 Thu Mar 20 2014

      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.
        eh eh quoting you is like a summoning spell..
        you burned me on time (appropriate analogy) BrowserUk .. i was thinking how to tweak it too.

        And if you are searching files newer than..? my oneliner skips all seconds between midnigth and the current second: this seems to be an headcache for anonymous. So i have tweacked this way:
        perl -MTime::Local -e " print scalar localtime (timelocal(0, 0, 0, @{[ +localtime(time - $ARGV[0] * 86400)]}[3..8]))" 30 #output Thu Mar 20 00:00:00 2014
        very lazy solution.

        HtH
        L*
        There are no rules, there are no thumbs..
        Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.

      No. This gives the time 2592000 non-leap seconds ago.

      Sure, this code will be right most of the time, and it might even meet the OP's specs. However, it's lazy code like this that ignores the existing date/time modules which cause the subtle bugs that give people everywhere headaches. It's coding like this that causes people to ask questions like the original post in the first place.

        there are many ways to get the job done in Perl. I like this freedom as in 'free beer'
        It's up to the wisdom of the coder when choice a solution or another.
        In a critical application i would use some standard module about Date:: while in a oneliner maybe i would choice the simplest solution.

        I never propose me as 'The teacher' as you can guess looking at my nickname, maybe i need to add a standard disclaimer in the signature? ;=)

        can i cite BrowserUk as found here?
            On the basis of what I know, or at least what I think I know, I think this will help you, so here it is. It almost certainly isn't perfect, it may not even be relevant, though I believe it to be, and I am happy to offer it in case it helps, and to learn from the enevitable corrections that will come if what I believe is wrong.
        
        I think that this attitude is most succinctly and most prevelantly summed up by the oft-used sign-off HTH. -- Hope That Helps. 
        My best form of enjoy here at perlmonks is when i post something and many experienced or less monks, point me to some issue or better way to do it.

        Please let all solution to have the right to exist, the wisdom is in the coder not in the code.
        Cya

        L*
        There are no rules, there are no thumbs..
        Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.