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

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

2008-08-25, 2008-09-01, 2008-09-08...

I'd like to be able to specify a start date and an end date and get just the Mondays (or whatever weekday I happen to need) within that range.

I can think of ways to go about it but I'm sure there are better solutions out there; and maybe someday someone else will find this node and be happy.
  • Comment on What is the best way to get a list of all Mondays until the end of the year?

Replies are listed 'Best First'.
Re: What is the best way to get a list of all Mondays until the end of the year?
by grinder (Bishop) on Aug 19, 2008 at 11:34 UTC
    What is the best way...

    Perhaps something using Date::Calc. The idea would be to take a date in the year, find the next monday, and if the year is the same, print it out. Then, keep adding 7 days until the year changes.

    #! /usr/bin/perl use strict; use warnings; use Date::Calc 'Add_Delta_Days'; my ($day, $month, $year, $dow) = (localtime)[3, 4, 5, 6]; $year += 1900; $month += 1; my $this_year = $year; ($year, $month, $day) = Add_Delta_Days($year, $month, $day, (8 - $dow) + % 7); while ($this_year == $year) { printf "%04d-%02d-%02d\n", $year, $month, $day; ($year, $month, $day) = Add_Delta_Days($year, $month, $day, 7); }

    update: it occurs to me that it may not be obvious how this calculates Mondays, since it uses a magic number. It would be a little clearer had I written:

    my %day = qw( Sun 0 Mon 1 Tue 2 Wed 3 Thu 4 Fri 5 Sat 6 ); ($year, $month, $day) = Add_Delta_Days($year, $month, $day, (7 + $day{ +Mon} - $dow) % 7);

    • another intruder with the mooring in the heart of the Perl

Re: What is the best way to get a list of all Mondays until the end of the year?
by Krambambuli (Curate) on Aug 19, 2008 at 11:21 UTC
    Date::Manip is quite convenient for such queries:

    perl -e 'use Date::Manip; $dt = ParseDate("now"); while($dt lt "200812 +31") { $dt = Date_GetNext($dt,"Mon", 0); print UnixDate( $dt, "%Y-%m- +%d"), "\n"; }'
    Update: shortened the line a bit.

    Krambambuli
    ---
Re: What is the best way to get a list of all Mondays until the end of the year?
by ForgotPasswordAgain (Priest) on Aug 19, 2008 at 11:06 UTC

    Play with this:

    perl -MDateTime -le'$min=DateTime->now;$max=DateTime->new(year=>2008,m +onth=>12,day=>31);while($min->dow != 1){$min->add(days=>1)};while($mi +n<$max){print $min->ymd; $min->add(weeks=>1)}'
      #!/usr/bin/perl -- use strict; use warnings; use DateTime::Event::Recurrence; { my $dt1 = new DateTime( year => 2008 ); my $dt2 = new DateTime( year => 2009 ); my $der = DateTime::Event::Recurrence->weekly; print $_->ymd, ' ', ,$/ for $der->as_list( start => $dt1, end => $dt2 ); } # http://datetime.perl.org/index.cgi?FAQDurationsSetsSpans __END__
      2008-01-07 2008-01-14 2008-01-21 2008-01-28 2008-02-04 2008-02-11 2008-02-18 2008-02-25 2008-03-03 2008-03-10 2008-03-17 2008-03-24 2008-03-31 2008-04-07 2008-04-14 2008-04-21 2008-04-28 2008-05-05 2008-05-12 2008-05-19 2008-05-26 2008-06-02 2008-06-09 2008-06-16 2008-06-23 2008-06-30 2008-07-07 2008-07-14 2008-07-21 2008-07-28 2008-08-04 2008-08-11 2008-08-18 2008-08-25 2008-09-01 2008-09-08 2008-09-15 2008-09-22 2008-09-29 2008-10-06 2008-10-13 2008-10-20 2008-10-27 2008-11-03 2008-11-10 2008-11-17 2008-11-24 2008-12-01 2008-12-08 2008-12-15 2008-12-22 2008-12-29
        one-liner version
        perl -MDateTime::Event::Recurrence -le " print $_->ymd, chr(32) for +DateTime::Event::Recurrence->weekly->as_list( start => DateTime->new +( year => 2008 ), end => DateTime->new ( year => 2009 ) ); " perl -MDateTime::Event::Recurrence -le ' print $_->ymd, chr(32) for +DateTime::Event::Recurrence->weekly->as_list( start => DateTime->new +( year => 2008 ), end => DateTime->new ( year => 2009 ) ); '
Re: What is the best way to get a list of all Mondays until the end of the year?
by merlyn (Sage) on Aug 19, 2008 at 16:54 UTC
    use Date::Manip; for my $date (ParseRecur("every monday", "", ParseDate("today"), Parse +Date("dec 31"))) { print "$date\n"; # or format it using UnixDate($date, $format) }
Re: What is the best way to get a list of all Mondays until the end of the year?
by johngg (Canon) on Aug 19, 2008 at 10:59 UTC
    You could have a look at Date::Manip to see if it can be applied to your problem.

    Cheers,

    JohnGG

Re: What is the best way to get a list of all Mondays until the end of the year?
by BrowserUk (Patriarch) on Aug 19, 2008 at 17:47 UTC
    [0] Perl> $t = time(); while( $_=localtime( $t ) and m[2008] ) { m[^Mon] and print scalar localtime( $t ); $t+=86400; } Mon Aug 25 18:45:13 2008 Mon Sep 1 18:45:13 2008 Mon Sep 8 18:45:13 2008 Mon Sep 15 18:45:13 2008 Mon Sep 22 18:45:13 2008 Mon Sep 29 18:45:13 2008 Mon Oct 6 18:45:13 2008 Mon Oct 13 18:45:13 2008 Mon Oct 20 18:45:13 2008 Mon Oct 27 17:45:13 2008 Mon Nov 3 17:45:13 2008 Mon Nov 10 17:45:13 2008 Mon Nov 17 17:45:13 2008 Mon Nov 24 17:45:13 2008 Mon Dec 1 17:45:13 2008 Mon Dec 8 17:45:13 2008 Mon Dec 15 17:45:13 2008 Mon Dec 22 17:45:13 2008 Mon Dec 29 17:45:13 2008

    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.
      ++

      I had one that was equivalent in length to my other code post that did the same thing (just looked at every day) - but I thought I'd avoid doing the extra un-needed calculations by going a week at a time. But most use cases probably wouldn't care about the extra 300 (at most) iterations.
      my @a=qw(random brilliant braindead); print $a[rand(@a)];
Re: What is the best way to get a list of all Mondays until the end of the year?
by Rhandom (Curate) on Aug 19, 2008 at 16:14 UTC
    Golfing - with no modules:
    perl -e '@N=gmtime;$t=time+86400*(1-$N[6]);while(1){@n=gmtime($t+=7*86 +400);last if $n[5]!=$N[5]; printf("%d-%02d-%02d\n",$n[5]+1900,$n[4]+1 +,$n[3])}'
    Human readable and explained:
    perl -e ' my @N = gmtime; # today (calculations in gmtime to avoid tz offset +s) my $t = time + 86400 * (1 - $N[6]); # calculate the time of Monday +(1) while(1) { my @n = gmtime($t += 7*86400); # advance a week at a time last if $n[5] != $N[5]; # done if the year doesn't mat +ch today's printf ("%d-%02d-%02d\n", $n[5]+1900, $n[4]+1, $n[3]); # print re +sult }'

    Really you should look at DateTime or Date::Manip or Date::Calc or ... - but sometimes it makes sense not to.
    my @a=qw(random brilliant braindead); print $a[rand(@a)];
      Just a side node; this would work most of the time, but not always. A week is _not_ always 7*86400 seconds, a day is _not_ always 86400 seconds - when daylight saving comes to play, this offset may give you a false Monday (if you're making the calculation at a unwise chosen time ;) )

      Update: daylight saving changes.

      Krambambuli
      ---
        What you say is true for localtime, but not for gmtime (which is what the Rhandom's example uses). As the doc says, there is no DST for GMT.
Re: What is the best way to get a list of all Mondays until the end of the year?
by dragonchild (Archbishop) on Aug 19, 2008 at 15:36 UTC
    In other words, there are three excellent and several dozen mediocre date modules on CPAN. CPAN is your friend. Look there first and you will find pretty much most of what you'd ever need.

    My criteria for good software:
    1. Does it work?
    2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?