Last Friday of each month

You are encouraged to solve this task according to the task description, using any language you may know.
- Task
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
- Related tasks
Ada
Uses GNAT. Applicable to any day of the week, cf. [[1]].
<lang Ada>with Ada.Text_IO, GNAT.Calendar.Time_IO, Ada.Command_Line,
Ada.Calendar.Formatting, Ada.Calendar.Arithmetic;
procedure Last_Weekday_In_Month is
procedure Put_Line(T: Ada.Calendar.Time) is use GNAT.Calendar.Time_IO; begin Ada.Text_IO.Put_Line(Image(Date => T, Picture => ISO_Date)); end Put_Line; use Ada.Calendar, Ada.Calendar.Arithmetic; subtype Day_Name is Formatting.Day_Name; use type Formatting.Day_Name; T, Selected : Time; Weekday: Day_Name := Day_Name'Value(Ada.Command_Line.Argument (1)); Year : Year_Number := Integer'Value (Ada.Command_Line.Argument (2));
begin
for Month in 1 .. 12 loop T := Time_Of (Year => Year, Month => Month, Day => 01); while Ada.Calendar.Month(T) = Month loop
if Formatting.Day_Of_Week (T) = Weekday then Selected := T; end if; T := T + Day_Count(1);
end loop; Put_Line(Selected); end loop;
end Last_Weekday_In_Month;</lang>
- Output:
>./last_weekday_in_month friday 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
AutoIt
<lang AutoIt>
- include <Date.au3>
$iYear = InputBox('Last Friday in each month', 'Please input the year:')
_GetLastFridays($iYear)
Func _GetLastFridays($_iYear) Local $sResult = 'last fridays in ' & $_iYear & @LF, $iDay Local $aDaysInMonth[12] = [31,28,31,30,31,30,31,31,30,31,30,31] If _DateIsLeapYear($_iYear) Then $aDaysInMonth[1] = 29 For $i = 1 To 12 $iDay = $aDaysInMonth[$i-1] While 1 If _DateToDayOfWeekISO($_iYear, $i, $iDay) = 5 Then $sResult &= StringFormat('%4d-%02d-%02d', $_iYear, $i, $iDay) & @LF ExitLoop EndIf $iDay -= 1 WEnd Next ConsoleWrite($sResult) EndFunc ;==>_GetFridays </lang>
- Output:
last fridays in 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
--BugFix (talk) 13:27, 15 November 2013 (UTC)
AWK
<lang AWK>
- syntax: GAWK -f LAST_FRIDAY_OF_EACH_MONTH.AWK year
- converted from Fortran
BEGIN {
split("31,28,31,30,31,30,31,31,30,31,30,31",daynum_array,",") # days per month in non leap year year = ARGV[1] if (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0)) { daynum_array[2] = 29 } y = year - 1 k = 44 + y + int(y/4) + int(6*(y/100)) + int(y/400) for (m=1; m<=12; m++) { k += daynum_array[m] d = daynum_array[m] - (k%7) printf("%04d-%02d-%02d\n",year,m,d) } exit(0)
} </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
Befunge
The algorithm has been slightly simplified to avoid the additional day adjustment inside the loop, and the year is obtained from stdin rather than via the command line.
<lang befunge>":raeY",,,,,&>55+,:::45*:*%\"d"%!*\4%+!3v v2++1**"I"5\+/*:*54\-/"d"\/4::-1::p53+g5< >:00p5g4-+7%\:0\v>,"-",5g+:55+/68*+,55+%v ^<<_$$vv*86%+55:<^+*86%+55,+*86/+55:-1:<6 >$$^@$<>+\55+/:#^_$>:#,_$"-",\:04-\-00g^8 ^<# #"#"##"#"##!` +76:+1g00,+55,+*<</lang>
- Output:
Year: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#
<lang csharp>using System; using System.Collections.Generic; using System.Globalization; using System.Linq;
namespace RosettaCode.LastFridaysOfYear {
internal static class Program { private static IEnumerable<DateTime> LastFridaysOfYear(int year) { for (var month = 1; month <= 12; month++) { var date = new DateTime(year, month, 1).AddMonths(1).AddDays(-1); while (date.DayOfWeek != DayOfWeek.Friday) { date = date.AddDays(-1); } yield return date; } }
private static void Main(string[] arguments) { int year; var argument = arguments.FirstOrDefault(); if (string.IsNullOrEmpty(argument) || !int.TryParse(argument, out year)) { year = DateTime.Today.Year; }
foreach (var date in LastFridaysOfYear(year)) { Console.WriteLine(date.ToString("d", CultureInfo.InvariantCulture)); } } }
}</lang>
- Output:
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/2012
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
Clojure
<lang clojure>(use '[clj-time.core :only [last-day-of-the-month day-of-week minus days]]
'[clj-time.format :only [unparse formatters]])
(defn last-fridays [year]
(let [last-days (map #(last-day-of-the-month year %) (range 1 13 1)) dow (map day-of-week last-days) relation (zipmap last-days dow)] (map #(minus (key %) (days (mod (+ (val %) 2) 7))) relation)))
(defn last-fridays-formatted [year]
(sort (map #(unparse (formatters :year-month-day) %) (last-fridays year))))</lang>
- Output:
user=> (pprint (last-fridays-formatted 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")
COBOL
<lang COBOL>
program-id. last-fri. data division. working-storage section. 1 wk-date. 2 yr pic 9999. 2 mo pic 99 value 1. 2 da pic 99 value 1. 1 rd-date redefines wk-date pic 9(8). 1 binary. 2 int-date pic 9(8). 2 dow pic 9(4). 2 friday pic 9(4) value 5. procedure division. display "Enter a calendar year (1601 thru 9999): " with no advancing accept yr if yr >= 1601 and <= 9999 continue else display "Invalid year" stop run end-if perform 12 times move 1 to da add 1 to mo if mo > 12 *> to avoid y10k in 9999 move 12 to mo move 31 to da end-if compute int-date = function integer-of-date (rd-date) if mo =12 and da = 31 *> to avoid y10k in 9999 continue else subtract 1 from int-date end-if compute rd-date = function date-of-integer (int-date) compute dow = function mod ((int-date - 1) 7) + 1 compute dow = function mod ((dow - friday) 7) subtract dow from da display yr "-" mo "-" da add 1 to mo end-perform stop run . end program last-fri.
</lang>
- Output:
2016-01-29 2016-02-26 2016-03-25 2016-04-29 2016-05-27 2016-06-24 2016-07-29 2016-08-26 2016-09-30 2016-10-28 2016-11-25 2016-12-30
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>
Common Lisp
The command-line argument processing is the only CLISP-specific code.
<lang lisp>(defun friday-before (year month day)
(let* ((timestamp (encode-universal-time 0 0 12 day month year)) (weekday (nth 6 (multiple-value-list (decode-universal-time timestamp)))) (fri (- timestamp (* (+ (mod (+ weekday 2) 7) 1) 86400)))) (multiple-value-bind (_ _ _ d m y) (decode-universal-time fri) (list y m d))))
(defun last-fridays (year)
(append (loop for month from 2 to 12 collecting (friday-before year month 1)) (list (friday-before (1+ year) 1 1))))
(let* ((year (read-from-string (car *args*))))
(format t "~{~{~a-~2,'0d-~2,'0d~}~%~}" (last-fridays year)))</lang>
Sample run for the year 2015:
- Output:
2015-01-30 2015-02-27 2015-03-27 2015-04-24 2015-05-29 2015-06-26 2015-07-31 2015-08-28 2015-09-25 2015-10-30 2015-11-27 2015-12-25
D
<lang d>import std.stdio, std.datetime, std.traits;
void lastFridays(in uint year) {
auto date = Date(year, 1, 1); foreach (_; [EnumMembers!Month]) { date.day(date.daysInMonth); date.roll!"days"(-(date.dayOfWeek + 2) % 7); writeln(date); date.add!"months"(1, AllowDayOverflow.no); }
}
void main() {
lastFridays(2012);
}</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
Elixir
<lang elixir>defmodule RC do
def lastFriday(year) do Enum.map(1..12, fn month -> lastday = :calendar.last_day_of_the_month(year, month) daynum = :calendar.day_of_the_week(year, month, lastday) friday = lastday - rem(daynum + 2, 7) {year, month, friday} end) end
end
y = String.to_integer(hd(System.argv)) Enum.each(RC.lastFriday(y), fn {year, month, day} ->
:io.format "~4b-~2..0w-~2..0w~n", [year, month, day]
end)</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
Elm
<lang elm>import Html exposing (Html, Attribute, text, div, input) import Html.App exposing (beginnerProgram) import Html.Attributes exposing (placeholder, value, style) import Html.Events exposing (onInput) import String exposing (toInt) import Maybe exposing (withDefault) import List exposing (map, map2) import List.Extra exposing (scanl1)
type Msg = SetYear String
lastFridays : Int -> List Int lastFridays year =
let isLeap = (year % 400) == 0 || ( (year % 4) == 0 && (year % 100) /= 0 ) daysInMonth = [31, if isLeap then 29 else 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] y = year-1 in scanl1 (+) daysInMonth |> map2 (\len day -> len - (day + 2 + y + y//4 - y//100 + y//400) % 7) daysInMonth
lastFridayStrings : String -> List String lastFridayStrings yearString =
let months= ["January ", "February ", "March ", "April ", "May ", "June ", "July ", "August ", "September ", "October ", "November ", "December "] errString = "Only years after 1752 are valid." in case toInt yearString of Ok year -> if (year < 1753) then [errString] else lastFridays year |> map2 (\m d -> m ++ toString d ++ ", " ++ toString year) months Err _ -> [errString]
view : String -> Html Msg view yearString =
div [] ([ input [ placeholder "Enter a year." , value yearString , onInput SetYear , myStyle ] [] ] ++ (lastFridayStrings yearString |> map (\date -> div [ myStyle ] [ text date ]) ))
myStyle : Attribute Msg myStyle =
style [ ("width", "100%") , ("height", "20px") , ("padding", "5px 0 0 5px") , ("font-size", "1em") , ("text-align", "left") ]
update : Msg -> String -> String update msg _ =
case msg of SetYear yearString -> yearString
main =
beginnerProgram { model = "" , view = view , update = update }</lang>
Link to live demo: http://dc25.github.io/lastFridayOfMonthElm/
Sample run for the year 2003; copied and pasted from web-page:
- Output:
January 31, 2003 February 28, 2003 March 28, 2003 April 25, 2003 May 30, 2003 June 27, 2003 July 25, 2003 August 29, 2003 September 26, 2003 October 31, 2003 November 28, 2003 December 26, 2003
Erlang
<lang Erlang> -module( last_date_each_month ).
-export( [monday/1, tuesday/1, wednesday/1, thursday/1, friday/1, saturday/1, sunday/1] ).
monday( Year ) -> last( Year, 1 ). tuesday( Year ) -> last( Year, 2 ). wednesday( Year ) -> last( Year, 3 ). thursday( Year ) -> last( Year, 4 ). friday( Year ) -> last( Year, 5 ). saturday( Year ) -> last( Year, 6 ). sunday( Year ) -> last( Year, 7 ).
last( Year, Week_day ) ->
Months = lists:seq( 1, 12 ), Months_days = [{X, Y} || X <- Months, Y <- lists:seq(calendar:last_day_of_the_month(Year, X), calendar:last_day_of_the_month(Year, X) - 7, -1), calendar:valid_date(Year, X, Y), calendar:day_of_the_week(Year, X, Y) =:= Week_day], [{Year, X, proplists:get_value(X, Months_days)} || X <- Months].
</lang>
- Output:
32> [io:fwrite("~B-~2.10.0B-~B~n", [Y,M,D]) || {Y,M,D} <- last_date_each_month:friday(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
Fortran
Algorithm: compute day of week for last day of month, then subtract just enough to get to the preceding friday. Do this for each month. To simplify computations further, we only need to compute day of week of january 1st (the others are found by adding month lengths). Since day of week need only be known modulo 7, we do not compute modulo at all except once when subtracting. <lang fortran>program fridays
implicit none integer :: days(1:12) = (/31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31/) integer :: year, k, y, m read *, year if (mod(year, 400) == 0 .or. (mod(year, 4) == 0 .and. mod(year, 100) /= 0)) days(2) = 29 y = year - 1 k = 44 + y + y/4 + 6*(y/100) + y/400 do m = 1, 12 k = k + days(m) print "(I4,A1,I2.2,A1,I2)", year, '-', m, '-', days(m) - mod(k, 7) end do
end program </lang>
FreeBASIC
<lang FreeBasic>' version 23-06-2015 ' compile with: fbc -s console
- Ifndef TRUE ' define true and false for older freebasic versions
#Define FALSE 0 #Define TRUE Not FALSE
- EndIf
Function leapyear(Year_ As Integer) As Integer
' from the leapyeat entry If (Year_ Mod 4) <> 0 Then Return FALSE If (Year_ Mod 100) = 0 AndAlso (Year_ Mod 400) <> 0 Then Return FALSE Return TRUE
End Function
Function wd(m As Integer, d As Integer, y As Integer) As Integer
' Zellerish ' 0 = Sunday, 1 = Monday, 2 = Tuesday, 3 = Wednesday ' 4 = Thursday, 5 = Friday, 6 = Saturday
If m < 3 Then ' If m = 1 Or m = 2 Then m += 12 y -= 1 End If Return (y + (y \ 4) - (y \ 100) + (y \ 400) + d + ((153 * m + 8) \ 5)) Mod 7
End Function
' ------=< MAIN >=------
Type month_days
m_name As String days As UByte
End Type
Dim As month_days arr(1 To 12) Data "January", 31, "February", 28, "March", 31, "April", 30 Data "May", 31, "June", 30, "July", 31, "August", 31 Data "September", 30, "October", 31, "November", 30, "December", 31
Dim As Integer yr, d, i, x Dim As String keypress
For i = 1 To 12
With arr(i) Read .m_name Read .days End With
Next
Do
Do Print "For what year do you want to find the last Friday of the month" Input "any number below 1800 stops program, year in YYYY format";yr ' empty input also stops If yr < 1800 Then End Else Exit Do End If Loop
Print : Print Print "Last Friday of the month for"; yr
For i = 1 To 12 d = arr(i).days If i = 2 AndAlso leapyear(yr) = TRUE Then d = d + 1 x = wd(i, d, yr) If x <> 5 Then d = d - IIf(x > 5, x - 5, x + 2) Print d; " "; arr(i).m_name Next
' empty key buffer While InKey <> "" : keypress = InKey : Wend Print : Print Print "Find last Friday for a other year [Y|y], anything else stops" keypress ="" While keypress = "" : keypress = InKey : Wend If LCase(keypress) <> "y" Then Exit Do Print : Print
Loop End</lang>
- Output:
For what year do you want to find the last Friday of the month any number below 1800 stops program, year in YYYY format? 2015 Last Friday of the month for 2015 30 January 27 February 27 March 24 April 29 May 26 June 31 July 28 August 25 September 30 October 27 November 25 December
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((d.Weekday()+7-time.Friday)%7) * 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
Groovy
Solution: Same as Find last Sunday of each month
Test: <lang groovy>def ymd = { it.format('yyyy-MM-dd') } def lastFridays = lastWeekDays.curry(Day.Fri) lastFridays(args[0] as int).each { println (ymd(it)) }</lang>
Execution (Cygwin on Windows 7):
[2273] groovy lastFridays.groovy 2012
- 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
Haskell
<lang Haskell>import Data.Time.Calendar import Data.Time.Calendar.WeekDate
findFriday date = head $ filter isFriday $ map toDate [-6 .. 0]
where toDate ago = addDays ago date isFriday theDate = let (_ , _ , day) = toWeekDate theDate in day == 5
fridayDates year = map (showGregorian . findFriday) lastDaysInMonth
where lastDaysInMonth = map findLastDay [1 .. 12] findLastDay month = fromGregorian year month (gregorianMonthLength year month)
main = do
putStrLn "Please enter a year!" year <- getLine mapM_ putStrLn $ fridayDates (read year)</lang>
- Output:
Please enter a year! 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 remaining day within each represented month (which will be a Friday because we only kept the Fridays). 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.*; import java.util.*;
public class LastFridays {
public static void main(String[] args) throws Exception { int year = Integer.parseInt(args[0]); GregorianCalendar c = new GregorianCalendar(year, 0, 1);
for (String mon : new DateFormatSymbols(Locale.US).getShortMonths()) { if (!mon.isEmpty()) { int totalDaysOfMonth = c.getActualMaximum(Calendar.DAY_OF_MONTH); c.set(Calendar.DAY_OF_MONTH, totalDaysOfMonth);
int daysToRollBack = (c.get(Calendar.DAY_OF_WEEK) + 1) % 7;
int day = totalDaysOfMonth - daysToRollBack; c.set(Calendar.DAY_OF_MONTH, day);
System.out.printf("%d %s %d\n", year, mon, day);
c.set(year, c.get(Calendar.MONTH) + 1, 1); } } }
}</lang>
- Output:
(for java LastFridays 2012
)
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
JavaScript
Imperative
<lang javascript> var last_friday_of_month, print_last_fridays_of_month;
last_friday_of_month = function(year, month) {
var i, last_day; 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 = function(year) {
var month, results; results = []; for (month = 1; month <= 12; ++month) { results.push(console.log(last_friday_of_month(year, month))); } return results;
};
(function() {
var year; year = parseInt(process.argv[2]); return print_last_fridays_of_month(year);
})();
</lang>
- Output:
<lang> >node lastfriday.js 2015 Fri Jan 30 2015 Fri Feb 27 2015 Fri Mar 27 2015 Fri Apr 24 2015 Fri May 29 2015 Fri Jun 26 2015 Fri Jul 31 2015 Fri Aug 28 2015 Fri Sep 25 2015 Fri Oct 30 2015 Fri Nov 27 2015 Fri Dec 25 2015 </lang>
Functional (ES 5)
<lang JavaScript>(function () {
'use strict';
// lastFridaysOfYear :: Int -> [Date] function lastFridaysOfYear(y) { return lastWeekDaysOfYear(y, days.friday); }
// lastWeekDaysOfYear :: Int -> [Date] function lastWeekDaysOfYear(y, iWeekDay) { return [ 31, 0 === y % 4 && 0 !== y % 100 || 0 === y % 400 ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ] .map(function (d, m) { var dte = new Date(Date.UTC(y, m, d));
return new Date(Date.UTC( y, m, dte.getDate() - ((dte.getDay() + (7 - iWeekDay)) % 7) )); }); }
var days = { sunday: 0, monday: 1, tuesday: 2, wednesday: 3, thursday: 4, friday: 5, saturday: 6 }
// TEST // ( columns of results for 2013 to 2017 )
function zipListsWith(f, xxs) { return (xxs.length ? xxs[0] : []) .map(function (_, i) { return f.apply(null, xxs.map(function (lst) { return lst[i]; })); }) }
// Int -> Int -> [Int] function range(m, n) { return Array.apply(null, Array(n - m + 1)) .map(function (x, i) { return m + i; }); }
return zipListsWith( function () { return (Array.apply(null, arguments)) .map(function (dte) { return dte.toISOString() .substr(0, 10); }) .join('\t'); }, range(2012, 2016) .map(lastFridaysOfYear) ) .join('\n');
})();</lang>
- Output:
2012-01-27 2013-01-25 2014-01-31 2015-01-30 2016-01-29 2012-02-24 2013-02-22 2014-02-28 2015-02-27 2016-02-26 2012-03-30 2013-03-29 2014-03-28 2015-03-27 2016-03-25 2012-04-27 2013-04-26 2014-04-25 2015-04-24 2016-04-29 2012-05-25 2013-05-31 2014-05-30 2015-05-29 2016-05-27 2012-06-29 2013-06-28 2014-06-27 2015-06-26 2016-06-24 2012-07-27 2013-07-26 2014-07-25 2015-07-31 2016-07-29 2012-08-31 2013-08-30 2014-08-29 2015-08-28 2016-08-26 2012-09-28 2013-09-27 2014-09-26 2015-09-25 2016-09-30 2012-10-26 2013-10-25 2014-10-31 2015-10-30 2016-10-28 2012-11-30 2013-11-29 2014-11-28 2015-11-27 2016-11-25 2012-12-28 2013-12-27 2014-12-26 2015-12-25 2016-12-30
jq
Foundations <lang jq># In case your jq does not have "until" defined:
def until(cond; next):
def _until: if cond then . else (next|_until) end; _until;
- Zeller's Congruence is from Day_of_the_week#jq
- Use Zeller's Congruence to determine the day of the week, given
- year, month and day as integers in the conventional way.
- If iso == "iso" or "ISO", then emit an integer in 1 -- 7 where
- 1 represents Monday, 2 Tuesday, etc;
- otherwise emit 0 for Saturday, 1 for Sunday, etc.
def day_of_week(year; month; day; iso):
if month == 1 or month == 2 then [year - 1, month + 12, day] else [year, month, day] end | .[2] + (13*(.[1] + 1)/5|floor) + (.[0]%100) + ((.[0]%100)/4|floor) + (.[0]/400|floor) - 2*(.[0]/100|floor) | if iso == "iso" or iso == "ISO" then 1 + ((. + 5) % 7) else . % 7 end ;</lang>
findLastFridays <lang jq># year and month are numbered conventionally def findLastFriday(year; month):
def isLeapYear: year%4 == 0 and ( year%100!=0 or year%400==0 ) ; def days: if month == 2 then (if isLeapYear then 29 else 28 end) else [31, 28, 31,30,31,30,31,31,30,31,30,31][month-1] end; year as $year | month as $month | days | until( day_of_week($year; $month; .; null) == 6 ; .-1);
- input: year
def findLastFridays:
def months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; . as $year | "YEAR: \(.)", (range(0;12) | "\(months[.]) \(findLastFriday($year; .+1))") ;
$year|tonumber|findLastFridays</lang>
- Output:
<lang sh>$ jq --arg year 2012 -n -r -f findLastFridays.jq YEAR: 2012 January 27 February 24 March 30 April 27 May 25 June 29 July 27 August 31 September 28 October 26 November 30 December 28</lang>
Julia
<lang Julia> isdefined(:Date) || using Dates
const wday = Dates.Fri const lo = 1 const hi = 12
print("\nThis script will print the last ", Dates.dayname(wday)) println("s of each month of the year given.") println("(Leave input empty to quit.)")
while true
print("\nYear> ") y = chomp(readline()) 0 < length(y) || break y = try parseint(y) catch println("Sorry, but \"", y, "\" does not compute as a year.") continue end println() for m in Date(y, lo):Month(1):Date(y, hi) println(" ", tolast(m, wday)) end
end </lang>
This code uses the Dates
module, which is being incorporated into Julian's standard library with the current development version (0.4). I've used isdefined
to make this code good for the current stable version (0.3) as well as for future releases. If Dates
is not installed on your instance of Julian try Pkg.add("Dates")
from the REPL.
- Output:
This script will print the last Fridays of each month of the year given. (Leave input empty to quit.) Year> 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 Year> this year Sorry, but "this year" does not compute as a year. Year>
Lasso
<lang Lasso>define isLeapYear(y::integer) => { #y % 400 == 0 ? return true #y % 100 == 0 ? return false #y % 4 == 0 ? return true return false } define fridays(y::integer) => { local(out = array) loop(12) => { local(last = 28) loop_count == 2 && isLeapYear(#y) ? #last = 29 array(4,6,9,11) >> loop_count ? #last == 30 #last == 28 && loop_count != 2 ? #last = 31 local(start = date(-year=#y,-month=loop_count,-day=#last)) while(#start->dayofweek != 6) => { #start->subtract(-day=1) } #out->insert(#start) } return #out } with f in fridays(2012) do => {^ #f->format('%Q') + '\r' ^}</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
LiveCode
<lang LiveCode>function lastFriday yyyy
-- year,month num,day of month,hour in 24-hour time,minute,second,numeric day of week. convert the long date to dateitems put 1 into item 2 of it put 1 into item 3 of it put yyyy into item 1 of it put it into startDate convert startDate to dateItems repeat with m = 1 to 12 put m into item 2 of startDate repeat with d = 20 to 31 put d into item 3 of startDate convert startDate to dateItems -- 6 is friday if item 7 of startDate is 6 and item 1 of startDate is yyyy and item 2 of startDate is m then put item 3 of startDate into fridays[item 2 of startDate] end if end repeat end repeat combine fridays using cr and space sort fridays ascending numeric return fridays
end lastFriday</lang> Example<lang LiveCode>put lastFriday("2012")</lang>Output<lang LiveCode>1 27 2 24 3 30 4 27 5 25 6 29 7 27 8 31 9 28 10 26 11 30 12 28</lang>
Logo
<lang logo>; Determine if a Gregorian calendar year is leap to leap? :year
output (and equal? 0 modulo :year 4 not member? modulo :year 400 [100 200 300] )
end
- Convert Gregorian calendar date to a simple day count from
- RD 1 = January 1, 1 CE
to day_number :year :month :day
local "elapsed make "elapsed difference :year 1 output (sum product 365 :elapsed int quotient :elapsed 4 minus int quotient :elapsed 100 int quotient :elapsed 400 int quotient difference product 367 :month 362 12 ifelse lessequal? :month 2 0 ifelse leap? :year -1 -2 :day)
end
- Find the day of the week from a day number, 0 = Sunday through 6 = Saturday
to day_of_week :day_number
output modulo :day_number 7
end
- Find the date of the last Friday of a given month
to last_friday :year :month
local "zero make "zero day_number :year :month 0 local "last make "last day_number :year sum 1 :month 0 local "wday make "wday day_of_week :last local "friday make "friday sum :last remainder difference -2 :wday 7 output difference :friday :zero
end
local "year make "year ifelse empty? :command.line 2012 :command.line
repeat 12 [
local "month make "month # local "day make "day last_friday :year :month if (less? :month 10) [make "month word "0 :month] print reduce [(word ?1 "- ?2)] (list :year :month :day)
] bye</lang>
- Output:
$ logo last_fridays.lg - 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
Lua
<lang lua>function isLeapYear (y)
return (y % 4 == 0 and y % 100 ~=0) or y % 400 == 0
end
function dayOfWeek (y, m, d)
local t = os.time({year = y, month = m, day = d}) return os.date("%A", t)
end
function lastWeekdays (wday, year)
local monthLength, day = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} if isLeapYear(year) then monthLength[2] = 29 end for month = 1, 12 do day = monthLength[month] while dayOfWeek(year, month, day) ~= wday do day = day - 1 end print(year .. "-" .. month .. "-" .. day) end
end
lastWeekdays("Friday", tonumber(arg[1]))</lang> Command line session:
>lua lastFridays.lua 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 >
Mathematica
<lang Mathematica>FridaysOfYear[Y_] :=
NestWhile[(DaysPlus[#, - 1]) &, #, (DateString[#, "DayName"] != "Friday") &] & /@ Most@Reverse@NestList [DaysPlus[# /. {x_, y_, X_} -> {x, y, 1}, - 1] &, {Y + 1, 1, 1}, 12]
Column@FridaysOfYear[2012]</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
Maxima
<lang maxima>weekday(year, month, day) := block([m: month, y: year, k],
if m < 3 then (m: m + 12, y: y - 1), k: 1 + remainder(day + quotient((m + 1)*26, 10) + y + quotient(y, 4) + 6*quotient(y, 100) + quotient(y, 400) + 5, 7), ['monday, 'tuesday, 'wednesday, 'thurdsday, 'friday, 'saturday, 'sunday][k]
)$
leapyearp(year) := is(mod(year, 4) = 0 and (mod(year, 100) # 0 or mod(year, 400) = 0))$
lastfridays(year) := block(
[m: [31, if leapyearp(year) then 29 else 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], v: [ ]], for month thru 12 do v: endcons(sconcat(year, "-", month, "-", lmax(sublist(makelist(i, i, 1, m[month]), lambda([day], weekday(year, month, day) = 'friday)))), v), v
)$
lastfridays(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>
NetRexx
Implements the algorithms from both the Java and C implementations. <lang NetRexx>/* NetRexx */ options replace format comments java crossref symbols nobinary
import java.text.
runSample(arg) return
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ method lastFridayByLib(year) public static
cal = GregorianCalendar(year, 0, 1)
loop mon over DateFormatSymbols().getShortMonths() if \mon.isEmpty() then do totalDaysOfMonth = cal.getActualMaximum(Calendar.DAY_OF_MONTH) cal.set(Calendar.DAY_OF_MONTH, totalDaysOfMonth)
daysToRollBack = (cal.get(Calendar.DAY_OF_WEEK) + 1) // 7
day = totalDaysOfMonth - daysToRollBack cal.set(Calendar.DAY_OF_MONTH, day)
say year.right(4, 0) mon day.right(2, 0)
cal.set(year, cal.get(Calendar.MONTH) + 1, 1) end end mon return
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ method lastFridayCalc(year) public static binary signals BadArgumentException
if year <= 1700 then do signal BadArgumentException(year 'is out of range') end
wk = int mth = int yr = int year days = [int 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] -- days in month days[1] = days[1] - ((yr // 4) | \(yr // 100) & (yr // 400)) -- adjust for leap year
wk = yr * 365 + (yr - 1) % 4 - (yr - 1) % 100 + (yr - 1) % 400 + 6 -- week number
loop mth = 0 to 11 wk = (wk + days[mth]) // 7 wx = int if wk < 5 then wx = -2 else wx = 5 yy = Rexx(yr) mm = Rexx(mth + 1) dd = Rexx(days[mth] + wx - wk) say yy.right(4, 0)'-'mm.right(2, 0)'-'dd.right(2, 0) end mth return
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ method runSample(arg) private static
do parse arg year . if year = | year = '.' then year = 2012 dlm = '-' dlm = dlm.left(60, dlm) say say 'Using Java calendar libraries' say dlm lastFridayByLib(year) say say 'Calculated' say dlm lastFridayCalc(year) catch ex = Exception ex.printStackTrace end return
</lang>
- Output:
Using Java calendar libraries ------------------------------------------------------------ 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 Calculated ------------------------------------------------------------ 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
Nim
<lang nim>import times, os, strutils
var timeinfo = getLocalTime getTime() timeinfo.year = paramStr(1).parseInt for month in mJan .. mDec:
timeinfo.month = month for day in countdown(31, 1): timeinfo.monthday = day let t = getLocalTime(timeInfoToTime timeinfo) if t.month == month and t.weekday == dFri: echo t.format "yyyy-MM-dd" break</lang>
Sample usage:
./lastfriday 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
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
Oforth
<lang Oforth>import: date
- lastFridays(y)
| m |
Date.JANUARY Date.DECEMBER for: m [ Date newDate(y, m, Date.DaysInMonth(y, m)) while(dup dayOfWeek Date.FRIDAY <>) [ addDays(-1) ] println ] ;</lang>
- Output:
2012-01-27 00:00:00,000 2012-02-24 00:00:00,000 2012-03-30 00:00:00,000 2012-04-27 00:00:00,000 2012-05-25 00:00:00,000 2012-06-29 00:00:00,000 2012-07-27 00:00:00,000 2012-08-31 00:00:00,000 2012-09-28 00:00:00,000 2012-10-26 00:00:00,000 2012-11-30 00:00:00,000 2012-12-28 00:00:00,000
PARI/GP
<lang parigp>\\ Normalized Julian Day Number from date njd(D) = {
my (m = D[2], y = D[1]);
if (D[2] > 2, m++, y--; m += 13);
(1461 * y) \ 4 + (306001 * m) \ 10000 + D[3] - 694024 + 2 - y \ 100 + y \ 400
}
\\ Date from Normalized Julian Day Number njdate(J) = {
my (a = J + 2415019, b = (4 * a - 7468865) \ 146097, c, d, m, y);
a += 1 + b - b \ 4 + 1524; b = (20 * a - 2442) \ 7305; c = (1461 * b) \ 4; d = ((a - c) * 10000) \ 306001; m = d - 1 - 12 * (d > 13); y = b - 4715 - (m > 2); d = a - c - (306001 * d) \ 10000;
[y, m, d]
}
for (m=1, 12, a=njd([2012,m+1,0]); print(njdate(a-(a+1)%7)))</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]
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.
Another variation where the data flow can be read left to right using feed operators:
<lang perl6>sub MAIN (Int $year = Date.today.year) {
.say for Date.new("$year-01-01") .. Date.new("$year-12-31") ==> classify *.month ==> map *.value.reverse.first: *.day-of-week == 5
}</lang>
Phix
<lang Phix>include timedate.e
constant FRIDAY=6
procedure showlast(integer dow, integer doy, timedate td)
td = adjust_timedate(td,timedelta(days:=doy-1)) integer {year,month,day} = td while day_of_week(year,month,day)!=dow do day-=1 end while printf(1,"%4d-%02d-%02d\n",{year,month,day})
end procedure
procedure last_day_of_month(integer year, integer dow) integer doy timedate first = {year,1,1,0,0,0,0,0}
-- start by finding the 1st of the next month, less 1 for i=1 to 11 do doy = day_of_year(year,i+1,1)-1 showlast(dow,doy,first) end for -- do December separately, as 1st would be next year doy = day_of_year(year,12,31) showlast(dow,doy,first)
end procedure last_day_of_month(2012,FRIDAY)</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
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:
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 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>
PL/I
<lang PL/I> Fridays: procedure (year) options (main); /* 8 January 2013 */
declare year character (4) varying; declare start fixed binary (31); declare months fixed decimal (2) initial (0); declare (current_month, month_one_week_hence) character (2);
put list ('Last Fridays in each month for the year ' || year || ':' ); start = days('0101' || year, 'DDMMYYYY'); /* Find first Friday */ do while (weekday(start) ^= 6); start = start + 1; end;
do until (months=12); current_month = substr (daystodate(start, 'MMDDYYYY'), 1, 2 ); month_one_week_hence = substr (daystodate(start+7, 'MMDDYYYY'), 1, 2 ); if current_month ^= month_one_week_hence then do; months = months + 1; put skip list (daystodate(start, 'DDMmmYYYY')); end; start = start + 7; end;
end Fridays; </lang> The command: FRIDAYS /2008 produces:
Last Fridays in each month for the year 2008: 25Jan2008 29Feb2008 28Mar2008 25Apr2008 30May2008 27Jun2008 25Jul2008 29Aug2008 26Sep2008 31Oct2008 28Nov2008 26Dec2008
- Output:
for 2013
Last Fridays in each month for the year 2013: 25Jan2013 22Feb2013 29Mar2013 26Apr2013 31May2013 28Jun2013 26Jul2013 30Aug2013 27Sep2013 25Oct2013 29Nov2013 27Dec2013
PowerShell
<lang PowerShell> function last-dayofweek {
param( [Int][ValidatePattern("[1-9][0-9][0-9][0-9]")]$year, [String][validateset('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday')]$dayofweek ) $date = (Get-Date -Year $year -Month 1 -Day 1) while($date.DayOfWeek -ne $dayofweek) {$date = $date.AddDays(1)} while($date.year -eq $year) { if($date.Month -ne $date.AddDays(7).Month) {$date.ToString("yyyy-dd-MM")} $date = $date.AddDays(7) }
} last-dayofweek 2012 "Friday" </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
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>
R
<lang rsplus>year = commandArgs(T) d = as.Date(paste0(year, "-01-01")) fridays = d + seq(by = 7,
(5 - as.POSIXlt(d)$wday) %% 7, 364 + (months(d + 30 + 29) == "February"))
message(paste(collapse = "\n", fridays[tapply(
seq_along(fridays), as.POSIXlt(fridays)$mon, max)]))</lang>
Racket
<lang racket>
- lang racket
(require srfi/19 math)
(define (days-in-month m y)
(define lengths #(0 31 #f 31 30 31 30 31 31 30 31 30 31)) (define d (vector-ref lengths m)) (or d (days-in-feb y)))
(define (leap-year? y)
(and (divides? 4 y) (or (not (divides? 100 y)) (divides? 400 y))))
(define (days-in-feb y)
(if (leap-year? y) 29 28))
(define (last-day-in-month m y)
(make-date 0 0 0 0 (days-in-month m y) m y 0))
(define (week-day date)
(define days #(sun mon tue wed thu fri sat)) (vector-ref days (date-week-day date)))
(define (last-fridays y)
(for/list ([m (in-range 1 13)]) (prev-friday (last-day-in-month m y))))
(define 24hours (make-time time-duration 0 (* 24 60 60)))
(define (prev-day d)
(time-utc->date (subtract-duration (date->time-utc d) 24hours)))
(define (prev-friday d)
(if (eq? (week-day d) 'fri) d (prev-friday (prev-day d))))
(for ([d (last-fridays 2012)])
(displayln (~a (date->string d "~a ~d ~b ~Y"))))
</lang>
- Output:
Fri 27 Jan 2012 Fri 24 Feb 2012 Fri 30 Mar 2012 Fri 27 Apr 2012 Fri 25 May 2012 Fri 29 Jun 2012 Fri 27 Jul 2012 Fri 31 Aug 2012 Fri 28 Sep 2012 Fri 26 Oct 2012 Fri 30 Nov 2012 Fri 28 Dec 2012
REBOL
The longer version: <lang REBOL>leap-year?: function [year] [to-logic attempt [to-date reduce [29 2 year]]]
days-in-feb: function [year] [either leap-year? year [29] [28]]
days-in-month: function [month year] [
do pick [31 (days-in-feb year) 31 30 31 30 31 31 30 31 30 31] month
]
last-day-of-month: function [month year] [
to-date reduce [year month days-in-month month year]
]
last-weekday-of-month: function [weekday month year] [
d: last-day-of-month month year while [d/weekday != weekday] [d/day: d/day - 1] d
]
last-friday-of-month: function [month year] [last-weekday-of-month 5 month year]
year: to-integer input repeat month 12 [print last-friday-of-month month year] </lang>
- Output:
rebol last-fridays.reb <<< 2012 27-Jan-2012 24-Feb-2012 30-Mar-2012 27-Apr-2012 25-May-2012 29-Jun-2012 27-Jul-2012 31-Aug-2012 28-Sep-2012 26-Oct-2012 30-Nov-2012 28-Dec-2012
A shorter version: <lang REBOL>last-fridays-of-year: function [year] [
collect [ repeat month 12 [ d: to-date reduce [1 month year] d/month: d/month + 1 ; start of next month until [d/day: d/day - 1 d/weekday = 5] ; go backwards until find a Friday keep d ] ]
]
foreach friday last-fridays-of-year to-integer input [print friday] </lang> NB. See "Find the last Sunday of each month" Rosetta for alternative (even more succinct) solution
REXX
This REXX program will find the last day-of-week (for any day) of all the months for any year.
It wasn't optimized just to find a particular day-of-week.
The documentation for the lastDOW function (used in the REXX program below):
╔════════════════════════════════════════════════════════════════════╗ ║ 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. ║ ╚════════════════════════════════════════════════════════════════════╝
<lang rexx>/*REXX program displays the dates of the last Fridays of each month for any given year.*/ parse arg yyyy
do j=1 for 12 say lastDOW('Friday', j, yyyy) /*find last Friday for the Jth month.*/ end /*j*/
exit /*stick a fork in it, we're all done. */ /*──────────────────────────────────────────────────────────────────────────────────────*/ lastDOW: procedure; arg dow .,mm .,yy .; parse arg a.1,a.2,a.3 /*DOW = day of week*/ 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,'M') then /*is MM alphabetic?*/
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
Ring
<lang ring> see "What year to calculate (yyyy) : " give year see "Last Friday in " + year + " are on :" + nl month = list(12) mo = [4,0,0,3,5,1,3,6,2,4,0,2] mon = [31,28,31,30,31,30,31,31,30,31,30,31] if year < 2100 leap = year - 1900 else leap = year - 1904 ok m = ((year-1900)%7) + floor(leap/4) % 7 for n = 1 to 12
month[n] = (mo[n] + m) % 7
next for n = 1 to 12
for i = (mon[n] - 6) to mon[n] if year%4 = 0 and n<3 x = (month[n] + i) % 7 - 1 else x = (month[n] + i) % 7 ok if n < 10 strn = "0" + string(n) else strn = string(n) ok if x = 2 see year + "-" + strn + "-" + string(i) + nl ok next
next
</lang> Output:
What year to calculate (yyyy) : 2012 Last Fridays in 2012 are on : 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
Ruby
<lang ruby>require 'date'
def last_friday(year, month)
# Last day of month: Date.new interprets a negative number as a relative month/day from the end of year/month. d = Date.new(year, month, -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.
- 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
Or get the last day of the month and go to the previous day until it's a Friday. <lang ruby>require 'date'
def last_friday(year, month)
d = Date.new(year, month, -1) d = d.prev_day until d.friday? d
end </lang>
Run BASIC
<lang runbasic>input "Year:";yr dayOne$ = "01-01-";yr n1 = date$(dayOne$) for i = 1 to 12
n1 = n1 + 26 m1$ = left$(date$(n1),2) while m1$ = left$(date$(n1),2) ' find end of month n1 = n1 + 1 wend n1 = n1 -1 while (n1 Mod 7) <> 3 ' find Friday n1 = n1 - 1 wend print date$(n1) ' print last Friday's date
next i</lang>
Year:?2013 01/25/2013 02/22/2013 03/29/2013 04/26/2013 05/31/2013 06/28/2013 07/26/2013 08/30/2013 09/27/2013 10/25/2013 11/29/2013 12/27/2013
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
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 5 2013
2013-01-25 2013-02-22 2013-03-29 2013-04-26 2013-05-31 2013-06-28 2013-07-26 2013-08-30 2013-09-27 2013-10-25 2013-11-29 2013-12-27
Sidef
<lang ruby>require('DateTime'); var (year=2015) = ARGV»to_i»()...;
range(1, 12).each { |month|
var dt = %s'DateTime'.last_day_of_month(year => year, month => month); while (dt.day_of_week != 5) { dt.subtract(days => 1); }; say dt.ymd;
}</lang>
- Output:
$ sidef lastfriday.sf 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
SQL
<lang SQL> select to_char( next_day( last_day( add_months( to_date(
:yr||'01','yyyymm' ),level-1))-7,'Fri') ,'yyyy-mm-dd Dy') lastfriday
from dual connect by level <= 12; </lang>
LASTFRIDAY ----------------------- 2012-01-27 Fri 2012-02-24 Fri 2012-03-30 Fri 2012-04-27 Fri 2012-05-25 Fri 2012-06-29 Fri 2012-07-27 Fri 2012-08-31 Fri 2012-09-28 Fri 2012-10-26 Fri 2012-11-30 Fri 2012-12-28 Fri 12 rows selected.
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>
For systems without ncal:
<lang sh>#!/bin/sh
- usage: last_fridays [ year]
year=${1:-`date +%Y`} # default to current year month=1 while [ 12 -ge $month ]; do
# Ensure 2 digits: if we try to strip off 2 characters but it still # looks the same, that means there was only 1 char, so we'll pad it. [ "$month" = "${month%??}" ] && month=0$month
cal $month $year | awk '{print $6}' | grep . | tail -1 \ | sed "s@^@$year-$month-@"
# Strip leading zeros to avoid octal interpretation month=$(( 1 + ${month#0} ))
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
Visual FoxPro
<lang vfp>
- !* OOP implementaion
LOCAL lnYear As Integer, oCalc As fricalc CLEAR lnYear = VAL(INPUTBOX("Year", "Year")) oCalc = NEWOBJECT("fricalc") oCalc.LastFriday(lnYear)
DEFINE CLASS fricalc As Session DataSession = 2 && Private
PROCEDURE Init
- !* These date settings are private to this class
SET DATE YMD SET CENTURY ON SET MARK TO "-" ENDPROC
FUNCTION LastFriday(tnYear As Integer) As VOID LOCAL i As Integer, ldDate As Date CLEAR ? "Last Fridays in the year " + TRANSFORM(tnYear) FOR i = 1 TO 12 ldDate = DATE(tnYear, i, 1) && 1st of month ldDate = GOMONTH(ldDate, 1) - 1 && last day of month *!* Use the built in function to return the day of the week *!* 6 is Friday DO WHILE DOW(ldDate) # 6 ldDate = ldDate - 1 ENDDO ? ldDate ENDFOR ENDFUNC
ENDDEFINE </lang>
XPL0
<lang XPL0>include c:\cxpl\codes; \intrinsic 'code' declarations
func WeekDay(Year, Month, Day); \Return day of week (0=Sun, 1=Mon ... 6=Sat) int Year, Month, Day; \works for years from 1583 onward [if Month<=2 then [Month:= Month+12; Year:= Year-1]; return rem((Day-1 + (Month+1)*26/10 + Year + Year/4 + Year/100*6 + Year/400)/7); ];
int Year, Month, LastDay, WD; [Year:= IntIn(8); \from command line for Month:= 1 to 12 do
[LastDay:= WeekDay(Year, Month+1, 1) - WeekDay(Year, Month, 28); if LastDay < 0 then LastDay:= LastDay + 7; LastDay:= LastDay + 27; \ = number of days in Month WD:= WeekDay(Year, Month, LastDay); WD:= WD - 5; if WD < 0 then WD:= WD + 7; LastDay:= LastDay - WD; IntOut(0, Year); ChOut(0, ^-); if Month < 10 then ChOut(0, ^0); IntOut(0, Month); ChOut(0, ^-); IntOut(0, LastDay); CrLf(0); ];
]</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
zkl
Gregorian calendar <lang zkl>var [const] D=Time.Date; fcn lastDay(y,_d){[1..12].pump(Console.println,
'wrap(m){D.daysInMonth(y,m) : [_..1,-1].pump(Void,'wrap(d){ D.weekDay(y,m,d) : if (_==_d)return(Void.Stop,"%d-%02d-%02d".fmt(y,m,d)) }) })
} lastDay(2012,D.Friday)</lang> For each month in year y, count back from the last day in the month until a Friday is found and print that date. A pump is a loop over a sequence and Void.Stop stops the pump with a value. The first parameter to a pump is the sink. All the imperative loop constructs are available but I didn't feel like using them. A wrap is a function closure over unknown values in the function, necessary because functions are not lexically scoped.
- 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
- Programming Tasks
- Solutions by Programming Task
- Date and time
- Ada
- AutoHotkey
- AutoIt
- AWK
- Befunge
- C
- C sharp
- C++
- Boost
- Clojure
- Clj-time
- COBOL
- CoffeeScript
- Common Lisp
- D
- Elixir
- Elm
- Erlang
- Fortran
- FreeBASIC
- Go
- Groovy
- Haskell
- Icon
- Unicon
- Icon Programming Library
- J
- Java
- Jq
- Julia
- Lasso
- LiveCode
- Logo
- Lua
- Mathematica
- MATLAB
- Octave
- Maxima
- NetRexx
- Nim
- OCaml
- OCaml Calendar Library
- Oforth
- PARI/GP
- Perl
- Perl 6
- Phix
- PHP
- PicoLisp
- Pike
- PL/I
- PowerShell
- Python
- R
- Racket
- REBOL
- REXX
- Ring
- Ruby
- Run BASIC
- Scala
- Seed7
- Sidef
- SQL
- Tcl
- TUSCRIPT
- UNIX Shell
- Visual FoxPro
- XPL0
- Zkl