Last Friday of each month: Difference between revisions

From Rosetta Code
Content added Content deleted
m (→‎{{header|D}}: less confusing)
m (→‎{{header|REXX}}: removed ''height'' from ''style'', added whitespace, changed comments. -- ~~~~)
Line 715: Line 715:
=={{header|REXX}}==
=={{header|REXX}}==
This REXX program will find the last day-of-week (for any day) of all the months for any year.
This REXX program will find the last day-of-week (for any day) of all the months for any year.
<lang rexx>/*REXX program displays dates of last Fridays of each month for any year*/
<lang rexx>
/*REXX program displays dates of last Fridays of each month for any year*/


parse arg yyyy
parse arg yyyy
do j=1 for 12
do j=1 for 12
say lastDOW('Friday',j,yyyy)
say lastDOW('Friday',j,yyyy)
end
end /*j*/
exit /*stick a fork in it, we're done.*/
exit


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


lastdow: procedure; arg dow .,mm .,yy . /*dow = day of week*/
lastdow: procedure; arg dow .,mm .,yy . /*DOW = day of week*/
parse arg a.1,a.2,a.3 /*orig args, errmsg*/
parse arg a.1,a.2,a.3 /*orig args, errmsg*/
if mm=='' | mm=='*' then mm=left(date('U'),2) /*use default month*/
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 yy=='' | yy=='*' then yy=left(date('S'),4) /*use default year */
if length(yy)==2 then yy=left(date('S'),2)yy /*append century. */
if length(yy)==2 then yy=left(date('S'),2)yy /*append century. */
/*Note mandatory leading blank in strings below.*/
/*Note mandatory leading blank in strings below.*/
$=" Monday TUesday Wednesday THursday Friday SAturday SUnday"
$=" Monday TUesday Wednesday THursday Friday SAturday SUnday"
!=" JAnuary February MARch APril MAY JUNe JULy AUgust September",
!=" JAnuary February MARch APril MAY JUNe JULy AUgust September",
" October November December"
" October November December"
upper $ ! /*uppercase strings*/
upper $ ! /*uppercase strings*/
if dow=='' then call .er "wasn't specified",1
if dow=='' then call .er "wasn't specified",1
if arg()>3 then call .er 'arguments specified',4
if arg()>3 then call .er 'arguments specified',4


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


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

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

if \datatype(mm,'W') then call .er "isn't an integer:",2
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 \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 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 0 (zero):",3
if yy<0 then call .er "can't be negative:",3
if yy<0 then call .er "can't be negative:",3
if yy>9999 then call .er "can't be > 9999:",3
if yy>9999 then call .er "can't be > 9999:",3


tdow=wordpos(word(substr($,dw),1),$)-1 /*target DOW, 0──►6*/
/*─────────────────────────────────────────────────────────────────*/
tdow=wordpos(word(substr($,dw),1),$)-1 /*target dow, 0-->6*/
/*day# of last dom.*/
/*day# of last dom.*/
_=date('B',right(yy+(mm=12),4)right(mm//12+1,2,0)"01",'S')-1
_=date('B',right(yy+(mm=12),4)right(mm//12+1,2,0)"01",'S')-1
?=_//7 /*calc. dow, 0-->6*/
?=_//7 /*calc. DOW, 0──►6*/
if ?\==tdow then _=_-?-7+tdow+7*(?>tdow) /*not dow? Adjust.*/
if ?\==tdow then _=_-?-7+tdow+7*(?>tdow) /*not DOW? Adjust.*/
return date('weekday',_,"B") date(,_,'B') /*return the answer*/
return date('weekday',_,"B") date(,_,'B') /*return the answer*/
/*─────────────────────────────────────────────────────────────────*/


.er: arg ,_;say; say '***error!*** (in LASTDOW)';say /*tell error,*/
.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 word('day-of-week month year excess',arg(2)) arg(1) a._
say; exit 13 /*... and then exit.*/
say; exit 13 /*... then exit. */</lang>
'''output''' when using the following input: <tt> 2012 </tt> or <tt> 12 </tt>
</lang>
<pre style="overflow:scroll">
Output when an input of <tt> 2012 </tt> or <tt> 12 </tt> is used:
<pre style="height:20ex;overflow:scroll">
Friday 27 Jan 2012
Friday 27 Jan 2012
Friday 24 Feb 2012
Friday 24 Feb 2012

Revision as of 17:21, 10 August 2012

Last Friday of each month is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

Write a program or a script that returns the last Fridays 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_fridays 2012
2012-01-27
2012-02-24
2012-03-30
2012-04-27
2012-05-25
2012-06-29
2012-07-27
2012-08-31
2012-09-28
2012-10-26
2012-11-30
2012-12-28
Cf.

Ada

<lang Ada>with Ada.Text_IO; use Ada.Text_IO; with Ada.Calendar; use Ada.Calendar; with Ada.Command_Line; use Ada.Command_Line; with Ada.Calendar.Formatting; use Ada.Calendar.Formatting; procedure Fridays is

  T : Ada.Calendar.Time;
  Year : Year_Number := Integer'Value (Argument (1));
  MLength : constant array (1 .. 12) of Positive :=
     (4 | 6 | 9 | 11 => 30, 2 => 28, others => 31);

begin

  for month in 1 .. 12 loop
     for day in reverse 1 .. MLength (month) loop
        T := Ada.Calendar.Time_Of (Year, month, day);
        if Day_Of_Week (T) = Friday then
           Put_Line (Image (Date => T)(1 .. 10)); exit;
        end if;
     end loop;
  end loop;

end Fridays;</lang>

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

AutoHotkey

<lang AHK>if 1 = ; no parameter passed { InputBox, 1, Last Fridays of year, Enter a year:, , , , , , , , %A_YYYY% If ErrorLevel ExitApp }

YYYY = %1% ; retrieve command line parameter Stmp = %YYYY%0101000000 count= 0

While count < 12 { FormatTime, ddd, %stmp%, ddd FormatTime, M, %stmp%, M If (ddd = "Fri"){ if (M-1 = count){ t := stmp stmp += 7, days } else res .= SubStr(t, 1, 4) "-" SubStr(t, 5, 2) "-" SubStr(t, 7, 2) "`n" ,count++ ,stmp := YYYY . SubStr("0" M, -1) . "01" } else stmp += 1, days } MsgBox % res</lang> Output for 2012:

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

C

Doesn't work with Julian calendar (then again, you probably don't need to plan your weekends for middle ages).

<lang c>#include <stdio.h>

  1. include <stdlib.h>

int main(int c, char *v[]) { int days[] = {31,29,31,30,31,30,31,31,30,31,30,31}; int m, y, w;

if (c < 2 || (y = atoi(v[1])) <= 1700) return 1;

	days[1] -= (y % 4) || (!(y % 100) && (y % 400));

w = y * 365 + (y - 1) / 4 - (y - 1) / 100 + (y - 1) / 400 + 6;

for(m = 0; m < 12; m++) { w = (w + days[m]) % 7; printf("%d-%02d-%d\n", y, m + 1, days[m] + (w < 5 ? -2 : 5) - w); }

return 0; }</lang>

C++

Library: Boost

called with ./last_fridays 2012 <lang cpp>#include <boost/date_time/gregorian/gregorian.hpp>

  1. include <iostream>
  2. include <cstdlib>

int main( int argc , char* argv[ ] ) {

  using namespace boost::gregorian ;
  greg_month months[ ] = { Jan , Feb , Mar , Apr , May , Jun , Jul ,
     Aug , Sep , Oct , Nov , Dec } ;
  greg_year gy = atoi( argv[ 1 ] ) ;
  for ( int i = 0 ; i < 12 ; i++ ) {
     last_day_of_the_week_in_month lwdm ( Friday , months[ i ] ) ;
     date d = lwdm.get_date( gy ) ;
     std::cout << d << std::endl ;
  }
  return 0 ;

}</lang> Output:

2012-Jan-27
2012-Feb-24
2012-Mar-30
2012-Apr-27
2012-May-25
2012-Jun-29
2012-Jul-27
2012-Aug-31
2012-Sep-28
2012-Oct-26
2012-Nov-30
2012-Dec-28

CoffeeScript

<lang coffeescript> last_friday_of_month = (year, month) ->

 # month is 1-based, JS API is 0-based, then we use
 # non-positive indexes to work backward relative to the
 # first day of the next month
 i = 0
 while true
   last_day = new Date(year, month, i) 
   if last_day.getDay() == 5
     return last_day.toDateString()
   i -= 1

print_last_fridays_of_month = (year) ->

 for month in [1..12]
   console.log last_friday_of_month year, month

do ->

 year = parseInt process.argv[2]
 print_last_fridays_of_month year

</lang> output <lang> > coffee last_friday.coffee 2012 Fri Jan 27 2012 Fri Feb 24 2012 Fri Mar 30 2012 Fri Apr 27 2012 Fri May 25 2012 Fri Jun 29 2012 Fri Jul 27 2012 Fri Aug 31 2012 Fri Sep 28 2012 Fri Oct 26 2012 Fri Nov 30 2012 Fri Dec 28 2012 </lang>

D

<lang d>import std.stdio, std.datetime, std.traits;

void main() {

   lastFridays(2012);

}

void lastFridays(in uint year) {

   Date date = Date(year, 1, 1);
   foreach (mon; EnumMembers!Month) {
       date.day(1);
       date.month(mon);
       auto mday = date.daysInMonth;
       do {
           date.day(mday);
           mday--;
       } while (date.dayOfWeek != DayOfWeek.fri);
       writeln(date);
   }

}</lang>

2012-Jan-27
2012-Feb-24
2012-Mar-30
2012-Apr-27
2012-May-25
2012-Jun-29
2012-Jul-27
2012-Aug-31
2012-Sep-28
2012-Oct-26
2012-Nov-30
2012-Dec-28

Go

<lang go>package main

import (

   "fmt"
   "os"
   "strconv"
   "time"

)

func main() {

   y := time.Now().Year()
   if len(os.Args) == 2 {
       if i, err := strconv.Atoi(os.Args[1]); err == nil {
           y = i
       }
   }
   for m := time.January; m <= time.December; m++ {
       d := time.Date(y, m+1, 1, 0, 0, 0, 0, time.UTC).Add(-24 * time.Hour)
       d = d.Add(time.Duration((11-d.Weekday())%7-6) * 24 * time.Hour)
       fmt.Println(d.Format("2006-01-02"))
   }

}</lang> Output:

> ./fridays 2012
2012-01-27
2012-02-24
2012-03-30
2012-04-27
2012-05-25
2012-06-29
2012-07-27
2012-08-31
2012-09-28
2012-10-26
2012-11-30
2012-12-28

Icon and Unicon

This will write the last fridays for every year given as an argument. There is no error checking on the year.

<lang Icon>procedure main(A) every write(lastfridays(!A)) end

procedure lastfridays(year) every m := 1 to 12 do {

  d := case m of {
     2        : if IsLeapYear(year) then 29 else 28
     4|6|9|11 : 30
     default  : 31
     }                          # last day of month
      
  z := 0  
  j := julian(m,d,year) + 1     # first day of next month
  until (j-:=1)%7 = 4 do z -:=1 # backup to last friday=4
  suspend sprintf("%d-%d-%d",year,m,d+z)
  }

end

link datetime, printf</lang>

printf.icn provides formatting datetime.icn provides julian and IsLeapYear

Output:

last_fridays.exe 2012
2012-1-27
2012-2-24
2012-3-30
2012-4-27
2012-5-25
2012-6-29
2012-7-27
2012-8-31
2012-9-28
2012-10-26
2012-11-30
2012-12-28

J

<lang j>require'dates' last_fridays=: 12 {. [:({:/.~ }:"1)@(#~ 5 = weekday)@todate (i.366) + todayno@,&1 1</lang>

In other words, start from January 1 of the given year, and count forward for 366 days, keeping the fridays. Then pick the last friday within each represented month. Then pick the first 12 (since on a non-leap year which ends on a thursday we would get an extra friday).

Example use:

<lang j> last_fridays 2012 2012 1 27 2012 2 24 2012 3 30 2012 4 27 2012 5 25 2012 6 29 2012 7 27 2012 8 31 2012 9 28 2012 10 26 2012 11 30 2012 12 28</lang>

Java

Works with: Java version 1.5+

<lang java5>import java.text.DateFormatSymbols; import java.util.Calendar; import java.util.GregorianCalendar;

public class LastFriday { private static int[] months = {Calendar.JANUARY, Calendar.FEBRUARY, Calendar.MARCH, Calendar.APRIL, Calendar.MAY, Calendar.JUNE, Calendar.JULY, Calendar.AUGUST, Calendar.SEPTEMBER, Calendar.OCTOBER, Calendar.NOVEMBER, Calendar.DECEMBER}; public static void main(String[] args){ int year = Integer.parseInt(args[0]); boolean leapYear = new GregorianCalendar().isLeapYear(year); for(int month:months){ int days = 31; switch(month){ case Calendar.SEPTEMBER: case Calendar.APRIL: case Calendar.JUNE: case Calendar.NOVEMBER: days = 30; break; case Calendar.FEBRUARY: days = leapYear ? 29 : 28; default: } GregorianCalendar date = new GregorianCalendar(year, month, days); while(date.get(Calendar.DAY_OF_WEEK) != Calendar.FRIDAY){ date.add(Calendar.DAY_OF_MONTH, -1); } String monthStr = new DateFormatSymbols().getShortMonths()[month]; System.out.println(monthStr +" "+ date.get(Calendar.DAY_OF_MONTH)); } } }</lang> Output (for java LastFriday 2012):

Jan 27
Feb 24
Mar 30
Apr 27
May 25
Jun 29
Jul 27
Aug 31
Sep 28
Oct 26
Nov 30
Dec 28

Mathematica

<lang Mathematica>Needs["Calendar`"] FridaysOfTheYear[Y_] := Cases[Map[{#,DayOfWeek[#]}&,DaysPlus[{Y,1,2}, #]&/@Range[365],{1}],List[x_,Friday]->x]; Last[SortBy[Cases[FridaysOfTheYear[2011], {_,#,_}], #3 &]]& /@ Range[12] // Column</lang> Output:

{2012,1,27}
{2012,2,24}
{2012,3,30}
{2012,4,27}
{2012,5,25}
{2012,6,29}
{2012,7,27}
{2012,8,31}
{2012,9,28}
{2012,10,26}
{2012,11,30}
{2012,12,28}

MATLAB / Octave

<lang Matlab> function t = last_fridays_of_year(y)

 t1 = datenum([y,1,1,0,0,0]);
 t2 = datenum([y,12,31,0,0,0]);
 t  = datevec(t1:t2);
 t  = t(strmatch('Friday', datestr(t,'dddd')), :);     % find all Fridays
 t  = t([find(diff(t(:,2)) > 0); end], :);     % find Fridays before change of month
 end; 
 datestr(last_fridays_of_year(2012),'yyyy-mm-dd')		

</lang>


Output:

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

OCaml

Using the module Unix from the standard OCaml library:

<lang ocaml>#load "unix.cma" open Unix

let usage() =

 Printf.eprintf "%s <year>\n" Sys.argv.(0);
 exit 1

let print_date t =

 Printf.printf "%d-%02d-%02d\n" (t.tm_year + 1900) (t.tm_mon + 1) t.tm_mday

let is_date_ok tm t =

 (tm.tm_year = t.tm_year &&
  tm.tm_mon  = t.tm_mon  &&
  tm.tm_mday = t.tm_mday)

let () =

 let _year =
   try int_of_string Sys.argv.(1)
   with _ -> usage()
 in
 let year = _year - 1900 in
 let fridays = Array.make 12 (Unix.gmtime 0.0) in
 for month = 0 to 11 do
   for day_of_month = 1 to 31 do
     let tm = { (Unix.gmtime 0.0) with 
       tm_year = year;
       tm_mon = month;
       tm_mday = day_of_month;
     } in
     let _, t = Unix.mktime tm in
     if is_date_ok tm t  (* check for months that have less than 31 days *)
     && t.tm_wday = 5  (* is a friday *)
     then fridays.(month) <- t
   done;
 done;
 Array.iter print_date fridays</lang>

Output:

$ ocaml last_fridays.ml 2012
2012-01-27
2012-02-24
2012-03-30
2012-04-27
2012-05-25
2012-06-29
2012-07-27
2012-08-31
2012-09-28
2012-10-26
2012-11-30
2012-12-28

With a dedicated library

<lang ocaml>open CalendarLib

let usage() =

 Printf.eprintf "%s <year>\n" Sys.argv.(0);
 exit 1

let print_date (year, month, day) =

 Printf.printf "%d-%02d-%02d\n" year month day

let () =

 let year =
   try int_of_string Sys.argv.(1)
   with _ -> usage()
 in
 let fridays = ref [] in
 for month = 1 to 12 do
   let num_days = Date.days_in_month (Date.make_year_month year month) in
   let rec aux day =
     if Date.day_of_week (Date.make year month day) = Date.Fri
     then fridays := (year, month, day) :: !fridays
     else aux (pred day)
   in
   aux num_days
 done;
 List.iter print_date (List.rev !fridays)</lang>

Run this script with the command:

ocaml unix.cma str.cma -I +calendar calendarLib.cma last_fridays.ml 2012

Perl

<lang Perl>#!/usr/bin/perl -w use strict ; use DateTime ; use feature qw( say ) ;

foreach my $month ( 1..12 ) {

  my $dt = DateTime->last_day_of_month( year => $ARGV[ 0 ] , month => $month ) ;
  while ( $dt->day_of_week != 5 ) {
     $dt->subtract( days => 1 ) ;
  }
  say $dt->ymd ;

}</lang> Output:

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

Perl 6

<lang perl6>sub MAIN (Int $year = Date.today.year) {

   my @fri;
   for Date.new("$year-01-01") .. Date.new("$year-12-31") {
       @fri[.month] = .Str if .day-of-week == 5;
   }
   .say for @fri[1..12];

}</lang>

Example:

$ ./lastfri 2038
2038-01-29
2038-02-26
2038-03-26
2038-04-30
2038-05-28
2038-06-25
2038-07-30
2038-08-27
2038-09-24
2038-10-29
2038-11-26
2038-12-31

A solution without a result array to store things in:

<lang perl6>sub MAIN (Int $year = Date.today.year) {

   say ~.value.reverse.first: *.day-of-week == 5
       for classify *.month, Date.new("$year-01-01") .. Date.new("$year-12-31");

}</lang>

Here, classify sorts the dates into one bin per month (but preserves the order in each bin). We then take the list inside each bin (.value) and find the last (.reverse.first) date which is a Friday.

PHP

PHP is generally used for web apps, so I am not implementing the command-line component of this task.

<lang PHP><?php function last_friday_of_month($year, $month) {

 $day = 0;
 while(True) {
   $last_day = mktime(0, 0, 0, $month+1, $day, $year); 
   if (date("w", $last_day) == 5) {
     return date("Y-m-d", $last_day);
   }
   $day -= 1;
 }

}

function print_last_fridays_of_month($year) {

 foreach(range(1, 12) as $month) {
   echo last_friday_of_month($year, $month), "
"; }

}

date_default_timezone_set("GMT"); $year = 2012; print_last_fridays_of_month($year); ?></lang>

Output in browser:

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

PicoLisp

<lang PicoLisp>(de lastFridays (Y)

  (for M `(range 1 12)
     (prinl
        (dat$
           (find '((D) (= "Friday" (day D)))
              (mapcar '((D) (date Y M D)) `(range 31 22)) )
           "-" ) ) ) )</lang>

Test: <lang PicoLisp>: (lastFridays 2012) 2012-01-27 2012-02-24 2012-03-30 2012-04-27 2012-05-25 2012-06-29 2012-07-27 2012-08-31 2012-09-28 2012-10-26 2012-11-30 2012-12-28</lang>

Pike

<lang Pike>int(0..1) last_friday(object day) {

  return day->week_day() == 5 && 
         day->month_day() > day->month()->number_of_days()-7; 

}

int main(int argc, array argv) {

   array days = filter(Calendar.Year((int)argv[1])->months()->days()[*], last_friday);
   write("%{%s\n%}", days->format_ymd());
   return 0;

}</lang>

Python

<lang python>import calendar c=calendar.Calendar() fridays={} year=raw_input("year") for item in c.yeardatescalendar(int(year)):

   for i1 in item:
       for i2 in i1:
           for i3 in i2:
               if "Fri" in i3.ctime() and year in i3.ctime():
                   month,day=str(i3).rsplit("-",1)
                   fridays[month]=day

for item in sorted((month+"-"+day for month,day in fridays.items()),

                  key=lambda x:int(x.split("-")[1])):
   print item</lang>

Using reduce

<lang python>import calendar c=calendar.Calendar() fridays={} year=raw_input("year") add=list.__add__ for day in reduce(add,reduce(add,reduce(add,c.yeardatescalendar(int(year))))):

   if "Fri" in day.ctime() and year in day.ctime():
       month,day=str(day).rsplit("-",1)
       fridays[month]=day

for item in sorted((month+"-"+day for month,day in fridays.items()),

                  key=lambda x:int(x.split("-")[1])):
   print item</lang>

using itertools

<lang python>import calendar from itertools import chain f=chain.from_iterable c=calendar.Calendar() fridays={} year=raw_input("year") add=list.__add__

for day in f(f(f(c.yeardatescalendar(int(year))))):

   if "Fri" in day.ctime() and year in day.ctime():
       month,day=str(day).rsplit("-",1)
       fridays[month]=day

for item in sorted((month+"-"+day for month,day in fridays.items()),

                  key=lambda x:int(x.split("-")[1])):
   print item</lang>

REXX

This REXX program will find the last day-of-week (for any day) of all the months for any year. <lang rexx>/*REXX program displays dates of last Fridays of each month for any year*/

parse arg yyyy

                  do j=1 for 12
                  say lastDOW('Friday',j,yyyy)
                  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 following input: 2012 or 12

Friday 27 Jan 2012
Friday 24 Feb 2012
Friday 30 Mar 2012
Friday 27 Apr 2012
Friday 25 May 2012
Friday 29 Jun 2012
Friday 27 Jul 2012
Friday 31 Aug 2012
Friday 28 Sep 2012
Friday 26 Oct 2012
Friday 30 Nov 2012
Friday 28 Dec 2012

Ruby

<lang ruby>require 'date'

def last_friday(year, month)

 # Find end of month = beginning of month + 1 month - 1 day.
 d = Date.new(year, month, 1).>>(1) - 1
 d -= (d.wday - 5) % 7  # Subtract days after Friday.

end

year = Integer(ARGV.shift) (1..12).each {|month| puts last_friday(year, month)}</lang>

Friday is d.wday == 5; the expression (d.wday - 5) % 7 counts days after Friday.

Library: ActiveSupport

Using the ActiveSupport library for some convenience methods

<lang ruby>require 'rubygems' require 'activesupport'

def last_friday(year, month)

 d = Date.new(year, month, 1).end_of_month
 until d.wday == 5
   d = d.yesterday
 end
 d

end</lang>

Scala

<lang scala>import java.util.Calendar import java.text.SimpleDateFormat

object Fridays {

 def lastFridayOfMonth(year:Int, month:Int)={
   val cal=Calendar.getInstance
   cal.set(Calendar.YEAR, year)
   cal.set(Calendar.MONTH, month)
   cal.set(Calendar.DAY_OF_WEEK, Calendar.FRIDAY)
   cal.set(Calendar.DAY_OF_WEEK_IN_MONTH, -1)
   cal.getTime
 }
 def fridaysOfYear(year:Int)=for(month <- 0 to 11) yield lastFridayOfMonth(year, month)
 def main(args:Array[String]){
   val year=args(0).toInt
   val formatter=new SimpleDateFormat("yyyy-MMM-dd")
   fridaysOfYear(year).foreach{date=>
     println(formatter.format(date))
   }
 }

}</lang> Output:

2012-Jan-27
2012-Feb-24
2012-Mrz-30
2012-Apr-27
2012-Mai-25
2012-Jun-29
2012-Jul-27
2012-Aug-31
2012-Sep-28
2012-Okt-26
2012-Nov-30
2012-Dez-28

Tcl

<lang tcl>package require Tcl 8.5 set year [lindex $argv 0] foreach dm {02/1 03/1 04/1 05/1 06/1 07/1 08/1 09/1 10/1 11/1 12/1 12/32} {

   # The [clock scan] code is unhealthily clever; use it for our own evil purposes
   set t [clock scan "last friday" -base [clock scan $dm/$year -gmt 1] -gmt 1]
   # Print the interesting part
   puts [clock format $t -format "%Y-%m-%d" -gmt 1]

}</lang> Sample execution:

$ tclsh8.5 lastfri.tcl 2012
2012-01-27
2012-02-24
2012-03-30
2012-04-27
2012-05-25
2012-06-29
2012-07-27
2012-08-31
2012-09-28
2012-10-26
2012-11-30
2012-12-28

TUSCRIPT

<lang tuscript> $$ MODE TUSCRIPT year=2012 LOOP month=1,12

LOOP day=31,22,-1
 dayofweek=DATE (number,day,month,year,nummer)
 IF (dayofweek==5) THEN
 PRINT year,"-",month,"-",day
 EXIT
 ENDIF
ENDLOOP

ENDLOOP </lang> Output:

2012-1-27
2012-2-24
2012-3-30
2012-4-27
2012-5-25
2012-6-29
2012-7-27
2012-8-31
2012-9-28
2012-10-26
2012-11-30
2012-12-28

UNIX Shell

Using ncal. Will switch to Julian calender as ncal sees fit, and will not calculate past year 9999 (chances are you'll be too dead by then to worry about weekends anyway). <lang bash>#!/bin/sh

if [ -z $1 ]; then exit 1; fi

  1. weed out multiple erros due to bad year

ncal 1 $1 > /dev/null && \ for m in 01 02 03 04 05 06 07 08 09 10 11 12; do echo $1-$m-`ncal $m $1 | grep Fr | sed 's/.* \([0-9]\)/\1/'` done</lang>

Using date --date from GNU date??? This code is not portable.

<lang bash>#!/bin/sh

  1. Free code, no limit work
  2. $Id: lastfridays,v 1.1 2011/11/10 00:48:16 gilles Exp gilles $
  1. usage :
  2. lastfridays 2012 # prints last fridays of months of year 2012

debug=${debug:-false}

  1. debug=true

epoch_year_day() { #set -x x_epoch=`expr ${2:-0} '*' 86400 + 43200` date --date="${1:-1970}-01-01 UTC $x_epoch seconds" +%s }

year_of_epoch() { date --date="1970-01-01 UTC ${1:-0} seconds" +%Y } day_of_epoch() { LC_ALL=C date --date="1970-01-01 UTC ${1:-0} seconds" +%A } date_of_epoch() { date --date="1970-01-01 UTC ${1:-0} seconds" "+%Y-%m-%d" } month_of_epoch() { date --date="1970-01-01 UTC ${1:-0} seconds" "+%m" }

last_fridays() { year=${1:-2012}

       next_year=`expr $year + 1`
       $debug && echo "next_year $next_year"
       current_year=$year
       day=0
       previous_month=01
       while test $current_year != $next_year; do
       	$debug && echo "day $day"
       	current_epoch=`epoch_year_day $year $day`
       	$debug && echo "current_epoch $current_epoch"
       	current_year=`year_of_epoch $current_epoch`
       	current_day=`day_of_epoch $current_epoch`
       	$debug && echo "current_day $current_day"
       	test $current_day = 'Friday' && current_friday=`date_of_epoch $current_epoch`
       	$debug && echo "current_friday $current_friday"
       	current_month=`month_of_epoch $current_epoch`
       	$debug && echo "current_month $current_month"
       	# Change of month => previous friday is the last of month
       	test "$previous_month" != "$current_month" \
       		&& echo $previous_friday
       	
       	previous_month=$current_month
       	previous_friday=$current_friday
       	day=`expr $day + 1`
       done

}

  1. main

last_fridays ${1:-2012}</lang>

Sample execution:

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