Last Friday of each month
Write a program or a script that returns the last Fridays of each month of a given year provided as argument on the command line.
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.
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>
- 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++
called with ./last_fridays 2012
<lang cpp>#include <boost/date_time/gregorian/gregorian.hpp>
- include <iostream>
- 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
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
<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}
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
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>
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.
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>
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
- 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
- Free code, no limit work
- $Id: lastfridays,v 1.1 2011/11/10 00:48:16 gilles Exp gilles $
- usage :
- lastfridays 2012 # prints last fridays of months of year 2012
debug=${debug:-false}
- 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
}
- 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