Find the last Sunday of each month

From Rosetta Code
Revision as of 12:56, 25 April 2013 by rosettacode>Axtens (FBSL)
Task
Find the last Sunday of each month
You are encouraged to solve this task according to the task description, using any language you may know.

Write a program or a script that returns the last Sundays of each month of a given year. The year may be given through any simple input method in your language (command line, std in, etc.).

Example of an expected output:


./last_sundays 2013
2013-01-27
2013-02-24
2013-03-31
2013-04-28
2013-05-26
2013-06-30
2013-07-28
2013-08-25
2013-09-29
2013-10-27
2013-11-24
2013-12-29
Cf.

Ada

The program from [[1]] solves this task, as well.

Output:
>./last_weekday_in_month sunday 2013
2013-01-27
2013-02-24
2013-03-31
2013-04-28
2013-05-26
2013-06-30
2013-07-28
2013-08-25
2013-09-29
2013-10-27
2013-11-24
2013-12-29

BBC BASIC

<lang bbcbasic> INSTALL @lib$+"DATELIB"

INPUT "What year to calculate (YYYY)? " Year%

PRINT '"Last Sundays in ";Year%;" are on:" FOR Month%=1 TO 12

 PRINT Year% "-" RIGHT$("0"+STR$Month%,2) "-";FN_dim(Month%,Year%)-FN_dow(FN_mjd(FN_dim(Month%,Year%),Month%,Year%))

NEXT END </lang> Output:

What year to calculate (YYYY)? 2013

Last Sundays in 2013 are on:
      2013-01-27
      2013-02-24
      2013-03-31
      2013-04-28
      2013-05-26
      2013-06-30
      2013-07-28
      2013-08-25
      2013-09-29
      2013-10-27
      2013-11-24
      2013-12-29

C++

<lang cpp>

  1. include <windows.h>
  2. include <iostream>
  3. include <string>

//-------------------------------------------------------------------------------------------------- using namespace std;

//-------------------------------------------------------------------------------------------------- class lastSunday { public:

   lastSunday()
   {

m[0] = "JANUARY: "; m[1] = "FEBRUARY: "; m[2] = "MARCH: "; m[3] = "APRIL: "; m[4] = "MAY: "; m[5] = "JUNE: "; m[6] = "JULY: "; m[7] = "AUGUST: "; m[8] = "SEPTEMBER: "; m[9] = "OCTOBER: "; m[10] = "NOVEMBER: "; m[11] = "DECEMBER: ";

   }
   void findLastSunday( int y )
   {

year = y; isleapyear();

int days[] = { 31, isleap ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, d; for( int i = 0; i < 12; i++ ) { d = days[i]; while( true ) { if( !getWeekDay( i, d ) ) break; d--; } lastDay[i] = d; }

display();

   }

private:

   void isleapyear()
   {

isleap = false; if( !( year % 4 ) ) { if( year % 100 ) isleap = true; else if( !( year % 400 ) ) isleap = true; }

   }
   void display()
   {

system( "cls" ); cout << " YEAR " << year << endl << "=============" << endl; for( int x = 0; x < 12; x++ ) cout << m[x] << lastDay[x] << endl;

cout << endl << endl;

   }
   int getWeekDay( int m, int d )
   {

int y = year;

int f = y + d + 3 * m - 1; m++; if( m < 3 ) y--; else f -= int( .4 * m + 2.3 );

f += int( y / 4 ) - int( ( y / 100 + 1 ) * 0.75 ); f %= 7;

return f;

   }
   int lastDay[12], year;
   string m[12];
   bool isleap;

}; //-------------------------------------------------------------------------------------------------- int main( int argc, char* argv[] ) {

   int y;
   lastSunday ls;
   while( true )
   {

system( "cls" ); cout << "Enter the year( yyyy ) --- ( 0 to quit ): "; cin >> y; if( !y ) return 0;

ls.findLastSunday( y );

system( "pause" );

   }
   return 0;

} //-------------------------------------------------------------------------------------------------- </lang> Output:

  YEAR 2013
=============
JANUARY:   27
FEBRUARY:  24
MARCH:     31
APRIL:     28
MAY:       26
JUNE:      30
JULY:      28
AUGUST:    25
SEPTEMBER: 29
OCTOBER:   27
NOVEMBER:  24
DECEMBER:  29

FBSL

<lang qbasic>#APPTYPE CONSOLE

  1. OPTION STRICT

DIM date AS INTEGER, dayname AS STRING FOR DIM i = 1 TO 12

   FOR DIM j = 31 DOWNTO 1
       date = 20130000 + (i * 100) + j
       IF CHECKDATE(i, j, 2013) THEN
           dayname = DATECONV(date, "dddd")
           IF dayname = "Sunday" THEN
               PRINT 2013, " ", i, " ", j
               EXIT FOR
           END IF
       END IF
   NEXT

NEXT

PAUSE </lang> Output <lang text>2013-1-27 2013-2-24 2013-3-31 2013-4-28 2013-5-26 2013-6-30 2013-7-28 2013-8-25 2013-9-29 2013-10-27 2013-11-24 2013-12-29

Press any key to continue... </lang>

Perl

<lang Perl>#!/usr/bin/perl use strict ; use warnings ; use DateTime ;

for my $i( 1..12 ) {

  my $date = DateTime->last_day_of_month( year => $ARGV[ 0 ] , 

month => $i ) ;

  while ( $date->dow != 7 ) {
     $date = $date->subtract( days => 1 ) ;
  }
  my $ymd = $date->ymd ;
  print "$ymd\n" ;

}</lang> Output:

2013-01-27
2013-02-24
2013-03-31
2013-04-28
2013-05-26
2013-06-30
2013-07-28
2013-08-25
2013-09-29
2013-10-27
2013-11-24
2013-12-29

Perl 6

<lang Perl6>for (1..12) -> $i {

  my $lastDay = Date.days-in-month( @*ARGS[ 0 ].Int , $i ) ;
  my $lastDate = Date.new( @*ARGS[ 0 ].Int , $i , $lastDay ) ;
  while $lastDate.day-of-week != 7 {
     $lastDate -= 1 ;
  }
  $lastDate.say ;

}</lang> Output:

2013-01-27
2013-02-24
2013-03-31
2013-04-28
2013-05-26
2013-06-30
2013-07-28
2013-08-25
2013-09-29
2013-10-27
2013-11-24
2013-12-29

REXX

This REXX example is an exact replication of the Rosetta Code

  • find last Fridays of each month for any year

except for the innards of the first DO loop.

The   lastDOW   subroutine can be used for any day-of-the-week for any month for any year. <lang rexx>/*REXX program displays dates of last Sundays of each month for any year*/ parse arg yyyy

                  do j=1 for  12
                  _ = lastDOW('Sunday', j, yyyy)
                  say right(_,4)'-'right(j,2,0)"-"left(word(_,2),2)
                  end  /*j*/

exit /*stick a fork in it, we're done.*/ /*┌────────────────────────────────────────────────────────────────────┐

 │ lastDOW:  procedure to return the date of the  last day-of-week of │
 │           any particular month  of any particular year.            │
 │                                                                    │
 │ The  day-of-week  must be specified (it can be in any case,        │
 │ (lower-/mixed-/upper-case)  as an English name of the spelled day  │
 │ of the week,   with a minimum length that causes no ambiguity.     │
 │ I.E.:   W  for Wednesday,   Sa  for Saturday,   Su  for Sunday ... │
 │                                                                    │
 │ The month can be specified as an integer   1 ──► 12                │
 │    1=January     2=February     3=March     ...     12=December    │
 │ or the English  name  of the month,  with a minimum length that    │
 │ causes no ambiguity.    I.E.:  Jun  for June,   D  for December.   │
 │ If omitted  [or an asterisk(*)],  the current month is used.       │
 │                                                                    │
 │ The year is specified as an integer or just the last two digits    │
 │ (two digit years are assumed to be in the current century,  and    │
 │ there is no windowing for a two-digit year).                       │
 │ If omitted  [or an asterisk(*)],  the current year is used.        │
 │ Years < 100   must be specified with  (at least 2)  leading zeroes.│
 │                                                                    │
 │ Method used: find the "day number" of the 1st of the next month,   │
 │ then subtract one  (this gives the "day number" of the last day of │
 │ the month,  bypassing the leapday mess).   The last day-of-week is │
 │ then obtained straightforwardly,   or  via subtraction.            │
 └────────────────────────────────────────────────────────────────────┘*/

lastdow: procedure; arg dow .,mm .,yy . /*DOW = day of week*/ parse arg a.1,a.2,a.3 /*orig args, errmsg*/ if mm== | mm=='*' then mm=left(date('U'),2) /*use default month*/ if yy== | yy=='*' then yy=left(date('S'),4) /*use default year */ if length(yy)==2 then yy=left(date('S'),2)yy /*append century. */

                  /*Note mandatory leading blank in strings below.*/

$=" Monday TUesday Wednesday THursday Friday SAturday SUnday" !=" JAnuary February MARch APril MAY JUNe JULy AUgust September",

 " October November December"

upper $ ! /*uppercase strings*/ if dow== then call .er "wasn't specified",1 if arg()>3 then call .er 'arguments specified',4

 do j=1 for 3                                       /*any plural args ?*/
 if words(arg(j))>1       then call .er 'is illegal:',j
 end

dw=pos(' 'dow,$) /*find day-of-week*/ if dw==0 then call .er 'is invalid:',1 if dw\==lastpos(' 'dow,$) then call .er 'is ambigious:',1

if datatype(mm,'month') then /*if MM is alpha...*/

 do
 m=pos(' 'mm,!)                                     /*maybe its good...*/
 if m==0                  then call .er 'is invalid:',1
 if m\==lastpos(' 'mm,!)  then call .er 'is ambigious:',2
 mm=wordpos(word(substr(!,m),1),!)-1                /*now, use true Mon*/
 end

if \datatype(mm,'W') then call .er "isn't an integer:",2 if \datatype(yy,'W') then call .er "isn't an integer:",3 if mm<1 | mm>12 then call .er "isn't in range 1──►12:",2 if yy=0 then call .er "can't be 0 (zero):",3 if yy<0 then call .er "can't be negative:",3 if yy>9999 then call .er "can't be > 9999:",3

tdow=wordpos(word(substr($,dw),1),$)-1 /*target DOW, 0──►6*/

                                                    /*day# of last dom.*/

_=date('B',right(yy+(mm=12),4)right(mm//12+1,2,0)"01",'S')-1 ?=_//7 /*calc. DOW, 0──►6*/ if ?\==tdow then _=_-?-7+tdow+7*(?>tdow) /*not DOW? Adjust.*/ return date('weekday',_,"B") date(,_,'B') /*return the answer*/

.er: arg ,_;say; say '***error!*** (in LASTDOW)';say /*tell error, and */

 say word('day-of-week month year excess',arg(2)) arg(1) a._
 say; exit 13                                       /*... then exit.   */</lang>

output when using the default input (the current year, 2013):

2013-01-27
2013-02-24
2013-03-31
2013-04-28
2013-05-26
2013-06-30
2013-07-28
2013-08-25
2013-09-29
2013-10-27
2013-11-24
2013-12-29

Seed7

Uses the libraries time.s7i and duration.s7i. Applicable to any day of the week, cf. [[2]].

<lang seed7>$ include "seed7_05.s7i";

 include "time.s7i";
 include "duration.s7i";

const proc: main is func

 local
   var integer: weekday is 1; # 1 for monday, 2 for tuesday, and so on up to 7 for sunday.
   var integer: year is 0;
   var integer: month is 1;
   var time: aDate is time.value;
   var time: selected is time.value;
 begin
   if length(argv(PROGRAM)) <> 2 then
     writeln("usage: lastWeekdayInMonth weekday year");
     writeln("  weekday: 1 for monday, 2 for tuesday, and so on up to 7 for sunday.");
   else
     weekday := integer parse (argv(PROGRAM)[1]);
     year := integer parse (argv(PROGRAM)[2]);
     for month range 1 to 12 do
       aDate := date(year, month, 1);
       while aDate.month = month do
         if dayOfWeek(aDate) = weekday then
           selected := aDate;
         end if;
         aDate +:= 1 . DAYS;
       end while;
       writeln(strDate(selected));
     end for;
   end if;
 end func;</lang>

Output when called with s7 rosetta/lastWeekdayInMonth 7 2013:

2013-01-27
2013-02-24
2013-03-31
2013-04-28
2013-05-26
2013-06-30
2013-07-28
2013-08-25
2013-09-29
2013-10-27
2013-11-24
2013-12-29