Last Friday of each month: Difference between revisions
(Undo revision 231020 by Vince refiti (talk)) |
(Added Easylang) |
||
(95 intermediate revisions by 45 users not shown) | |||
Line 3: | Line 3: | ||
;Task: |
;Task: |
||
Write a program or a script that returns the last Fridays of each month of a given year. |
Write a program or a script that returns the date of 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). |
The year may be given through any simple input method in your language (command line, std in, etc). |
||
Line 30: | Line 30: | ||
* [[Find the last Sunday of each month]] |
* [[Find the last Sunday of each month]] |
||
<br><br> |
<br><br> |
||
=={{header|360 Assembly}}== |
|||
The program uses one ASSIST macro (XPRNT) to keep the code as short as possible. |
|||
<syntaxhighlight lang="360asm">* Last Friday of each month 17/07/2016 |
|||
LASTFRI CSECT |
|||
USING LASTFRI,R13 base register |
|||
B 72(R15) skip savearea |
|||
DC 17F'0' savearea |
|||
STM R14,R12,12(R13) prolog |
|||
ST R13,4(R15) " <- |
|||
ST R15,8(R13) " -> |
|||
LR R13,R15 " addressability |
|||
L R4,YEAR year |
|||
SRDA R4,32 . |
|||
D R4,=F'400' year/400 |
|||
LTR R4,R4 if year//400=0 |
|||
BZ LEAP |
|||
L R4,YEAR year |
|||
SRDA R4,32 . |
|||
D R4,=F'4' year/4 |
|||
LTR R4,R4 if year//4=0 |
|||
BNZ NOTLEAP |
|||
L R4,YEAR year |
|||
SRDA R4,32 . |
|||
D R4,=F'100' year/400 |
|||
LTR R4,R4 if year//100=0 |
|||
BZ NOTLEAP |
|||
LEAP MVC DAYS+4(4),=F'29' days(2)=29 |
|||
NOTLEAP L R8,YEAR year |
|||
BCTR R8,0 y=year-1 |
|||
LA R7,44 44 |
|||
AR R7,R8 +y |
|||
LR R3,R8 y |
|||
SRA R3,2 y/4 |
|||
AR R7,R3 +y/4 |
|||
LR R4,R8 y |
|||
SRDA R4,32 . |
|||
D R4,=F'100' y/100 |
|||
LA R4,0 . |
|||
M R4,=F'6' *6 |
|||
AR R7,R5 +6*(y/100) |
|||
LR R4,R8 y |
|||
SRDA R4,32 . |
|||
D R4,=F'400' y/100 |
|||
AR R7,R5 k=44+y+y/4+6*(y/100)+y/400 |
|||
LA R6,1 m=1 |
|||
LOOPM C R6,=F'12' do m=1 to 12 |
|||
BH ELOOPM |
|||
LR R1,R6 m |
|||
SLA R1,2 . |
|||
L R2,DAYS-4(R1) days(m) |
|||
AR R7,R2 k=k+days(m) |
|||
LR R4,R7 k |
|||
SRDA R4,32 . |
|||
D R4,=F'7' k/7 |
|||
SR R2,R4 days(m)-k//7 |
|||
LR R9,R2 d=days(m)-k//7 |
|||
L R1,YEAR year |
|||
CVD R1,DW year: binary to packed |
|||
OI DW+7,X'0F' zap sign |
|||
UNPK PG(4),DW unpack (ZL4) |
|||
CVD R6,DW m : binary to packed |
|||
OI DW+7,X'0F' zap sign |
|||
UNPK PG+5(2),DW unpack (ZL2) |
|||
CVD R9,DW d: binary to packed |
|||
OI DW+7,X'0F' zap sign |
|||
UNPK PG+8(2),DW unpack (ZL2) |
|||
XPRNT PG,L'PG print buffer |
|||
LA R6,1(R6) m=m+1 |
|||
B LOOPM |
|||
ELOOPM L R13,4(0,R13) epilog |
|||
LM R14,R12,12(R13) " restore |
|||
XR R15,R15 " rc=0 |
|||
BR R14 exit |
|||
YEAR DC F'2016' <== input year |
|||
DAYS DC F'31',F'28',F'31',F'30',F'31',F'30' |
|||
DC F'31',F'31',F'30',F'31',F'30',F'31' |
|||
PG DC CL80'YYYY-MM-DD' buffer |
|||
XDEC DS CL12 temp |
|||
DW DS D packed (PL8) 15num |
|||
YREGS |
|||
END LASTFRI</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
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 |
|||
</pre> |
|||
=={{header|Action!}}== |
|||
<syntaxhighlight lang="action!">;https://en.wikipedia.org/wiki/Determination_of_the_day_of_the_week#Sakamoto.27s_methods |
|||
BYTE FUNC DayOfWeek(INT y BYTE m,d) ;1<=m<=12, y>1752 |
|||
BYTE ARRAY t=[0 3 2 5 0 3 5 1 4 6 2 4] |
|||
BYTE res |
|||
IF m<3 THEN |
|||
y==-1 |
|||
FI |
|||
res=(y+y/4-y/100+y/400+t(m-1)+d) MOD 7 |
|||
RETURN (res) |
|||
BYTE FUNC IsLeapYear(INT y) |
|||
IF y MOD 100=0 THEN |
|||
IF y MOD 400=0 THEN |
|||
RETURN (1) |
|||
ELSE |
|||
RETURN (0) |
|||
FI |
|||
FI |
|||
IF y MOD 4=0 THEN |
|||
RETURN (1) |
|||
FI |
|||
RETURN (0) |
|||
INT FUNC GetMaxDay(INT y BYTE m) |
|||
BYTE ARRAY MaxDay=[31 28 31 30 31 30 31 31 30 31 30 31] |
|||
IF m=2 AND IsLeapYear(y)=1 THEN |
|||
RETURN (29) |
|||
FI |
|||
RETURN (MaxDay(m-1)) |
|||
PROC PrintB2(BYTE x) |
|||
IF x<10 THEN |
|||
Put('0) |
|||
FI |
|||
PrintB(x) |
|||
RETURN |
|||
PROC Main() |
|||
INT MinYear=[1753],MaxYear=[9999],y |
|||
BYTE m,d,last,maxD |
|||
DO |
|||
PrintF("Input year in range %I...%I: ",MinYear,MaxYear) |
|||
y=InputI() |
|||
UNTIL y>=MinYear AND y<=MaxYear |
|||
OD |
|||
FOR m=1 TO 12 |
|||
DO |
|||
last=0 |
|||
maxD=GetMaxDay(y,m) |
|||
FOR d=1 TO maxD |
|||
DO |
|||
IF DayOfWeek(y,m,d)=5 THEN |
|||
last=d |
|||
FI |
|||
OD |
|||
PrintI(y) Put('-) |
|||
PrintB2(m) Put('-) |
|||
PrintB2(last) PutE() |
|||
OD |
|||
RETURN</syntaxhighlight> |
|||
{{out}} |
|||
[https://gitlab.com/amarok8bit/action-rosetta-code/-/raw/master/images/Last_Friday_of_each_month.png Screenshot from Atari 8-bit computer] |
|||
<pre> |
|||
Input year in range 1753...9999: 2021 |
|||
2021-01-29 |
|||
2021-02-26 |
|||
2021-03-26 |
|||
2021-04-30 |
|||
2021-05-28 |
|||
2021-06-25 |
|||
2021-07-30 |
|||
2021-08-27 |
|||
2021-09-24 |
|||
2021-10-29 |
|||
2021-11-26 |
|||
2021-12-31 |
|||
</pre> |
|||
=={{header|Ada}}== |
=={{header|Ada}}== |
||
Line 35: | Line 216: | ||
Uses GNAT. Applicable to any day of the week, cf. [[http://rosettacode.org/wiki/Find_last_sunday_of_each_month#Ada]]. |
Uses GNAT. Applicable to any day of the week, cf. [[http://rosettacode.org/wiki/Find_last_sunday_of_each_month#Ada]]. |
||
< |
<syntaxhighlight lang="ada">with Ada.Text_IO, GNAT.Calendar.Time_IO, Ada.Command_Line, |
||
Ada.Calendar.Formatting, Ada.Calendar.Arithmetic; |
Ada.Calendar.Formatting, Ada.Calendar.Arithmetic; |
||
Line 64: | Line 245: | ||
Put_Line(Selected); |
Put_Line(Selected); |
||
end loop; |
end loop; |
||
end Last_Weekday_In_Month;</ |
end Last_Weekday_In_Month;</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>>./last_weekday_in_month friday 2012 |
<pre>>./last_weekday_in_month friday 2012 |
||
Line 80: | Line 261: | ||
2012-12-28</pre> |
2012-12-28</pre> |
||
=={{header|ALGOL 68}}== |
|||
Basically the same as the "Find the Last Sunday Of Each Month" task solution. |
|||
{{Trans|ALGOL W}} |
|||
<syntaxhighlight lang="algol68">BEGIN # find the last Friday in each month of a year # |
|||
# returns true if year is a leap year, false otherwise # |
|||
# assumes year is in the Gregorian Calendar # |
|||
PROC is leap year = ( INT year )BOOL: |
|||
year MOD 400 = 0 OR ( year MOD 4 = 0 AND year MOD 100 /= 0 ); |
|||
# returns the day of the week of the specified date (d/m/y) # |
|||
# Sunday = 1 # |
|||
PROC day of week = ( INT d, m, y )INT: |
|||
BEGIN |
|||
INT mm := m; |
|||
INT yy := y; |
|||
IF mm <= 2 THEN |
|||
mm := mm + 12; |
|||
yy := yy - 1 |
|||
FI; |
|||
INT j = yy OVER 100; |
|||
INT k = yy MOD 100; |
|||
(d + ( ( mm + 1 ) * 26 ) OVER 10 + k + k OVER 4 + j OVER 4 + 5 * j ) MOD 7 |
|||
END # day of week # ; |
|||
# returns an array of the last Friday of each month in year # |
|||
PROC last fridays = ( INT year )[]INT: |
|||
BEGIN |
|||
[ 1 : 12 ]INT last days := ( 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ); |
|||
IF is leap year( year ) THEN last days[ 2 ] := 29 FI; |
|||
# for each month, determine the day number of the # |
|||
# last Friday # |
|||
[ 1 : 12 ]INT last; |
|||
FOR m pos TO 12 DO |
|||
INT dow := day of week( last days[ m pos ], m pos, year ); |
|||
# dow = 1 Sun, 2 Mon, ... , 6 Fri, 0 Sat # |
|||
# change to 2 Sun, 3 Mon, ... , 0 Fri, 1 Sat # |
|||
dow := ( dow + 1 ) MOD 7; |
|||
# offset the last day to the last Friday # |
|||
last[ m pos ] := last days[ m pos ] - dow |
|||
OD; |
|||
last |
|||
END # last fridays # ; |
|||
# test the last fridays procedure # |
|||
INT year = 2021; |
|||
[]INT last = last fridays( year ); |
|||
FOR m pos TO 12 DO |
|||
print( ( whole( year, 0 ) |
|||
, IF m pos < 10 THEN "-0" ELSE "-1" FI |
|||
, whole( m pos MOD 10, 0 ) |
|||
, "-" |
|||
, whole( last[ m pos ], 0 ) |
|||
, newline |
|||
) |
|||
) |
|||
OD |
|||
END</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
2021-01-29 |
|||
2021-02-26 |
|||
2021-03-26 |
|||
2021-04-30 |
|||
2021-05-28 |
|||
2021-06-25 |
|||
2021-07-30 |
|||
2021-08-27 |
|||
2021-09-24 |
|||
2021-10-29 |
|||
2021-11-26 |
|||
2021-12-31 |
|||
</pre> |
|||
=={{header|ALGOL W}}== |
|||
==AppleScript== |
|||
Basically the same as the "Find the Last Sunday Of Each Month" task solution, uses the Day_of_week and isLeapYear procedures from the the day-of-the-week and leap-year tasks (included here for convenience). |
|||
<syntaxhighlight lang="algolw">begin % find the last Friday in each month of a year % |
|||
% returns true if year is a leap year, false otherwise % |
|||
% assumes year is in the Gregorian Calendar % |
|||
logical procedure isLeapYear ( integer value year ) ; |
|||
year rem 400 = 0 or ( year rem 4 = 0 and year rem 100 not = 0 ); |
|||
% returns the day of the week of the specified date (d/m/y) % |
|||
% Sunday = 1, Friday = 6, Saturday = 0 % |
|||
integer procedure Day_of_week ( integer value d, m, y ); |
|||
begin |
|||
integer j, k, mm, yy; |
|||
mm := m; |
|||
yy := y; |
|||
if mm <= 2 then begin |
|||
mm := mm + 12; |
|||
yy := yy - 1; |
|||
end if_m_le_2; |
|||
j := yy div 100; |
|||
k := yy rem 100; |
|||
(d + ( ( mm + 1 ) * 26 ) div 10 + k + k div 4 + j div 4 + 5 * j ) rem 7 |
|||
end Day_of_week; |
|||
% sets the elements of last to the day of the last Friday % |
|||
% of each month in year % |
|||
procedure lastFridays ( integer value year |
|||
; integer array last ( * ) |
|||
) ; |
|||
begin |
|||
integer array lastDays ( 1 :: 12 ); |
|||
integer m; |
|||
% set ld to the day number od the last day of each % |
|||
% month in year % |
|||
m := 1; |
|||
for ld := 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 do begin |
|||
lastDays( m ) := ld; |
|||
m := m + 1 |
|||
end for_ld ; |
|||
if isLeapYear( year ) then lastDays( 2 ) := 29; |
|||
% for each month, determine the day number of the % |
|||
% last Friday % |
|||
for mPos := 1 until 12 do begin |
|||
integer dow; |
|||
dow := Day_of_week( lastDays( mPos ), mPos, year ); |
|||
% dow = 1 Sun, 2 Mon, ... , 6 Fri, 0 Sat % |
|||
% change to 2 Sun, 3 Mon, ... , 0 Fri, 1 Sat % |
|||
dow := ( dow + 1 ) rem 7; |
|||
% offset the last day to the last Friday % |
|||
last( mPos ) := lastDays( mPos ) - dow |
|||
end for_mPos |
|||
end lastFridays ; |
|||
begin |
|||
% test the lastFridays procedure % |
|||
integer array last ( 1 :: 12 ); |
|||
integer year; |
|||
year := 2020; |
|||
lastFridays( year, last ); |
|||
i_w := 1; s_w := 0; % output formatting % |
|||
for mPos := 1 until 12 do write( year, if mPos < 10 then "-0" else "-1", mPos rem 10, "-", last( mPos ) ) |
|||
end |
|||
end.</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
2020-01-31 |
|||
2020-02-28 |
|||
2020-03-27 |
|||
2020-04-24 |
|||
2020-05-29 |
|||
2020-06-26 |
|||
2020-07-31 |
|||
2020-08-28 |
|||
2020-09-25 |
|||
2020-10-30 |
|||
2020-11-27 |
|||
2020-12-25 |
|||
</pre> |
|||
=={{header|AppleScript}}== |
|||
{{Trans|JavaScript}} |
{{Trans|JavaScript}} |
||
<syntaxhighlight lang="applescript">-- LAST FRIDAYS OF YEAR ------------------------------------------------------ |
|||
-- lastFridaysOfYear :: Int -> [Date] |
|||
on lastFridaysOfYear(y) |
|||
<lang AppleScript>on run argv |
|||
-- lastWeekDaysOfYear :: Int -> Int -> [Date] |
|||
-- Default range in absence of arguments: from two years ago, to two years ahead |
|||
script lastWeekDaysOfYear |
|||
on |λ|(intYear, iWeekday) |
|||
-- Up to two optional command line arguments: [yearFrom], [yearTo] |
|||
-- lastWeekDay :: Int -> Int -> Date |
|||
script lastWeekDay |
|||
on |λ|(iLastDay, iMonth) |
|||
set iYear to intYear |
|||
calendarDate(iYear, iMonth, iLastDay - ¬ |
|||
(((weekday of calendarDate(iYear, iMonth, iLastDay)) ¬ |
|||
as integer) + (7 - (iWeekday))) mod 7) |
|||
end |λ| |
|||
end script |
|||
map(lastWeekDay, lastDaysOfMonths(intYear)) |
|||
end |λ| |
|||
-- isLeapYear :: Int -> Bool |
|||
on isLeapYear(y) |
|||
(0 = y mod 4) and (0 ≠ y mod 100) or (0 = y mod 400) |
|||
end isLeapYear |
|||
-- lastDaysOfMonths :: Int -> [Int] |
|||
on lastDaysOfMonths(y) |
|||
{31, cond(isLeapYear(y), 29, 28), ¬ |
|||
31, 30, 31, 30, 31, 31, 30, 31, 30, 31} |
|||
end lastDaysOfMonths |
|||
end script |
|||
lastWeekDaysOfYear's |λ|(y, Friday as integer) |
|||
-- ~ $ osascript ~/Desktop/lastFridays.scpt |
|||
end lastFridaysOfYear |
|||
-- |
|||
-- ~ $ osascript ~/Desktop/lastFridays.scpt 2013 |
|||
-- |
|||
-- TEST ---------------------------------------------------------------------- |
|||
-- ~ $ osascript ~/Desktop/lastFridays.scpt 2013 2016 |
|||
on run argv |
|||
set intThisYear to year of (current date) |
|||
if class of argv is list then |
|||
set lngArgs to length of argv |
|||
if lngArgs > 0 then |
|||
if lngArgs > 1 then |
|||
set {intFrom, intTo} to argv |
|||
else |
|||
set intYear to item 1 of argv |
|||
set {intFrom, intTo} to {intYear, intYear} |
|||
end if |
|||
else |
|||
set {intFrom, intTo} to {intThisYear - 2, intThisYear + 2} |
|||
end if |
|||
else |
|||
set {intFrom, intTo} to {intThisYear - 2, intThisYear + 2} |
|||
end if |
|||
intercalate(linefeed, ¬ |
intercalate(linefeed, ¬ |
||
map(isoRow, ¬ |
map(isoRow, ¬ |
||
transpose(map(lastFridaysOfYear, |
transpose(map(lastFridaysOfYear, ¬ |
||
apply(cond(class of argv is list and argv ≠ {}, ¬ |
|||
singleYearOrRange, fiveCurrentYears), ¬ |
|||
argIntegers(argv)))))) |
|||
end run |
end run |
||
-- DERIVATION OF LAST FRIDAYS |
|||
-- ARGUMENT HANDLING --------------------------------------------------------- |
|||
-- lastFridaysOfYear :: Int -> [Date] |
|||
on lastFridaysOfYear(y) |
|||
lastWeekDaysOfYear(y, Friday as integer) |
|||
end lastFridaysOfYear |
|||
-- Up to two optional command line arguments: [yearFrom], [yearTo] |
|||
-- (Default range in absence of arguments: |
|||
-- from two years ago, to two years ahead) |
|||
-- ~ $ osascript ~/Desktop/lastFridays.scpt |
|||
-- lastWeekDaysOfYear :: Int -> Int -> [Date] |
|||
-- ~ $ osascript ~/Desktop/lastFridays.scpt 2013 |
|||
on lastWeekDaysOfYear(intYear, iWeekday) |
|||
-- ~ $ osascript ~/Desktop/lastFridays.scpt 2013 2016 |
|||
map(mClosure(my lastWeekDay, ¬ |
|||
{intYear:intYear, iWeekday:iWeekday}), my lastDaysOfMonths(intYear)) |
|||
end lastWeekDaysOfYear |
|||
-- singleYearOrRange :: [Int] -> [Int] |
|||
on singleYearOrRange(argv) |
|||
apply(cond(length of argv > 0, my enumFromTo, my fiveCurrentYears), argv) |
|||
end singleYearOrRange |
|||
-- |
-- fiveCurrentYears :: () -> [Int] |
||
on fiveCurrentYears(_) |
|||
on lastWeekDay(iLastDay, iMonth) |
|||
set |
set intThisYear to year of (current date) |
||
enumFromTo(intThisYear - 2, intThisYear + 2) |
|||
end fiveCurrentYears |
|||
-- argIntegers :: maybe [String] -> [Int] |
|||
on argIntegers(argv) |
|||
-- parseInt :: String -> Int |
|||
script parseInt |
|||
on |λ|(s) |
|||
s as integer |
|||
end |λ| |
|||
end script |
|||
if class of argv is list and argv ≠ {} then |
|||
calendarDate(iYear, iMonth, iLastDay - ¬ |
|||
{map(parseInt, argv)} |
|||
(((weekday of calendarDate(iYear, iMonth, iLastDay)) as integer) + ¬ |
|||
(7 - (iWeekday of my closure))) mod 7) |
|||
end lastWeekDay |
|||
-- lastDaysOfMonths :: Int -> [Int] |
|||
on lastDaysOfMonths(y) |
|||
if (0 = y mod 4) and (0 ≠ y mod 100) or (0 = y mod 400) then |
|||
set iFeb to 29 |
|||
else |
else |
||
{} |
|||
end if |
end if |
||
end argIntegers |
|||
{31, iFeb, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} |
|||
end lastDaysOfMonths |
|||
-- GENERIC FUNCTIONS |
-- GENERIC FUNCTIONS --------------------------------------------------------- |
||
-- Dates and date strings |
-- Dates and date strings ---------------------------------------------------- |
||
-- calendarDate :: Int -> Int -> Int -> Date |
-- calendarDate :: Int -> Int -> Int -> Date |
||
Line 181: | Line 522: | ||
end isoDateString |
end isoDateString |
||
-- Testing and tabulation |
-- Testing and tabulation ---------------------------------------------------- |
||
-- |
-- apply (a -> b) -> a -> b |
||
on |
on apply(f, a) |
||
mReturn(f)'s |λ|(a) |
|||
end apply |
|||
on lambdaCol(_, iCol) |
|||
map(mClosure(my closure's mf's lambdaRow, ¬ |
|||
-- cond :: Bool -> (a -> b) -> (a -> b) -> (a -> b) |
|||
{iCol:iCol}), my closure's xss) |
|||
on cond(bool, f, g) |
|||
end lambdaCol |
|||
if bool then |
|||
f |
|||
else |
|||
item (my closure's iCol) of row |
|||
g |
|||
end |
end if |
||
end cond |
|||
map(mClosure(mf's lambdaCol, {xss:xss, mf:mf}), item 1 of xss) |
|||
end transpose |
|||
-- enumFromTo :: Int -> Int -> [Int] |
|||
on enumFromTo(m, n) |
|||
if m > n then |
|||
set d to -1 |
|||
else |
|||
set d to 1 |
|||
end if |
|||
set lst to {} |
|||
repeat with i from m to n by d |
|||
set end of lst to i |
|||
end repeat |
|||
return lst |
|||
end enumFromTo |
|||
-- intercalate :: Text -> [Text] -> Text |
-- intercalate :: Text -> [Text] -> Text |
||
Line 211: | Line 565: | ||
intercalate(tab, map(my isoDateString, lstDate)) |
intercalate(tab, map(my isoDateString, lstDate)) |
||
end isoRow |
end isoRow |
||
-- range :: Int -> Int -> [Int] |
|||
on range(m, n) |
|||
set lng to (n - m) + 1 |
|||
set base to m - 1 |
|||
set lst to {} |
|||
repeat with i from 1 to lng |
|||
set end of lst to i + base |
|||
end repeat |
|||
return lst |
|||
end range |
|||
-- Higher-order functions |
|||
-- map :: (a -> b) -> [a] -> [b] |
-- map :: (a -> b) -> [a] -> [b] |
||
on map(f, xs) |
on map(f, xs) |
||
tell mReturn(f) |
|||
set lng to length of xs |
set lng to length of xs |
||
set lst to {} |
set lst to {} |
||
repeat with i from 1 to lng |
repeat with i from 1 to lng |
||
set end of lst to |
set end of lst to |λ|(item i of xs, i, xs) |
||
end repeat |
end repeat |
||
return lst |
return lst |
||
end tell |
|||
end map |
end map |
||
Line 240: | Line 581: | ||
-- mReturn :: Handler -> Script |
-- mReturn :: Handler -> Script |
||
on mReturn(f) |
on mReturn(f) |
||
if class of f is script then |
if class of f is script then |
||
f |
|||
else |
|||
property lambda : f |
|||
script |
|||
property |λ| : f |
|||
end script |
|||
end if |
|||
end mReturn |
end mReturn |
||
-- |
-- transpose :: [[a]] -> [[a]] |
||
on transpose(xss) |
|||
on mClosure(f, recBindings) |
|||
script |
script column |
||
on |λ|(_, iCol) |
|||
script row |
|||
on |λ|(xs) |
|||
item iCol of xs |
|||
end |λ| |
|||
end script |
|||
map(row, xss) |
|||
end |λ| |
|||
end script |
end script |
||
end mClosure</lang> |
|||
map(column, item 1 of xss) |
|||
end transpose</syntaxhighlight> |
|||
{{Out}} |
{{Out}} |
||
<pre>2014-01-31 2015-01-30 2016-01-29 2017-01-27 2018-01-26 |
<pre>2014-01-31 2015-01-30 2016-01-29 2017-01-27 2018-01-26 |
||
2014-02-28 2015-02-27 2016-02-26 2017-02-24 2018-02-23 |
2014-02-28 2015-02-27 2016-02-26 2017-02-24 2018-02-23 |
||
Line 269: | Line 619: | ||
2014-11-28 2015-11-27 2016-11-25 2017-11-24 2018-11-30 |
2014-11-28 2015-11-27 2016-11-25 2017-11-24 2018-11-30 |
||
2014-12-26 2015-12-25 2016-12-30 2017-12-29 2018-12-28</pre> |
2014-12-26 2015-12-25 2016-12-30 2017-12-29 2018-12-28</pre> |
||
---- |
|||
A more straightforward solution: |
|||
AppleScript's weekday constants can be coerced either to English text or to the integers 1 (for Sunday) to 7 (Saturday). |
|||
<syntaxhighlight lang="applescript">on lastFridayOfEachMonthInYear(y) |
|||
-- Initialise an AppleScript date to the first day of some month in the specified year. |
|||
tell (current date) to set {firstDayOfNextMonth, its day, its year} to {it, 1, y} |
|||
-- Get a string representation of y, zero-padded if necessary, and initialise the output string. |
|||
set y to text 2 thru 5 of ((10000 + y) as text) |
|||
set outputText to "./last_fridays " & y |
|||
repeat with nextMonth from 2 to 13 -- Yes! |
|||
-- For each month in the year, get the first day of the following month. |
|||
set firstDayOfNextMonth's month to nextMonth |
|||
-- Calculate the date of the Friday which occurs in the seven days prior to that |
|||
-- by subtracting a day plus the difference between the previous day's weekday and the target weekday. |
|||
set lastFridayOfThisMonth to firstDayOfNextMonth - (1 + (firstDayOfNextMonth's weekday) mod 7) * days |
|||
-- Append the required details to the output text. |
|||
set {month:m, day:d} to lastFridayOfThisMonth |
|||
tell (10000 + m * 100 + d) as text to ¬ |
|||
set outputText to outputText & (linefeed & y & "-" & text 2 thru 3 & "-" & text 4 thru 5) |
|||
end repeat |
|||
return outputText |
|||
end lastFridayOfEachMonthInYear |
|||
lastFridayOfEachMonthInYear(2020)</syntaxhighlight> |
|||
{{Out}} |
|||
<pre>"./last_fridays 2020 |
|||
2020-01-31 |
|||
2020-02-28 |
|||
2020-03-27 |
|||
2020-04-24 |
|||
2020-05-29 |
|||
2020-06-26 |
|||
2020-07-31 |
|||
2020-08-28 |
|||
2020-09-25 |
|||
2020-10-30 |
|||
2020-11-27 |
|||
2020-12-25"</pre> |
|||
The above is of course hard-coded for Fridays. It can be made more flexible by taking an AppleScript weekday constant as a parameter: |
|||
<syntaxhighlight lang="applescript">on lastWeekdayWOfEachMonthInYear(w, y) -- Parameters: (AppleScript weekday constant, AD year number) |
|||
-- Initialise an AppleScript date to the first day of some month in the specified year. |
|||
tell (current date) to set {firstDayOfNextMonth, its day, its year} to {it, 1, y} |
|||
-- Get a string representation of y, zero-padded if necessary, and initialise the output string. |
|||
set y to text 2 thru 5 of ((10000 + y) as text) |
|||
set outputText to "./last_" & w & "s " & y |
|||
repeat with nextMonth from 2 to 13 -- Yes! |
|||
-- For each month in the year, get the first day of the following month. |
|||
set firstDayOfNextMonth's month to nextMonth |
|||
-- Calculate the date of the target weekday which occurs in the seven days prior to that. |
|||
-- The calculation can be described in various ways, the simplest being the subtraction of a day plus the difference between the previous day's weekday and the target weekday: |
|||
-- firstDayOfNextMonth - (1 + (((firstDayOfNextMonth's weekday) - 1) - w + 7) mod 7) * days |
|||
-- But they all boil down to: |
|||
set lastWOfThisMonth to firstDayOfNextMonth - (1 + ((firstDayOfNextMonth's weekday) - w + 6) mod 7) * days |
|||
-- Get the day and month of the calculated date and append the required details to the output text. |
|||
set {month:m, day:d} to lastWOfThisMonth |
|||
tell (10000 + m * 100 + d) as text to ¬ |
|||
set outputText to outputText & (linefeed & y & "-" & text 2 thru 3 & "-" & text 4 thru 5) |
|||
end repeat |
|||
return outputText |
|||
end lastWeekdayWOfEachMonthInYear |
|||
lastWeekdayWOfEachMonthInYear(Friday, 2020)</syntaxhighlight> |
|||
{{Out}} |
|||
<pre>"./last_Fridays 2020 |
|||
2020-01-31 |
|||
2020-02-28 |
|||
2020-03-27 |
|||
2020-04-24 |
|||
2020-05-29 |
|||
2020-06-26 |
|||
2020-07-31 |
|||
2020-08-28 |
|||
2020-09-25 |
|||
2020-10-30 |
|||
2020-11-27 |
|||
2020-12-25"</pre> |
|||
=={{header|Arturo}}== |
|||
<syntaxhighlight lang="rebol">lastFridayForMonth: function [m][ |
|||
ensure -> in? m 1..12 |
|||
daysOfMonth: [0 31 27 31 30 31 30 31 31 30 31 30 31] |
|||
loop range get daysOfMonth m 1 [d][ |
|||
dt: to :date.format:"yyyy-M-dd" ~"2012-|m|-|d|" |
|||
if dt\Day = "Friday" -> return dt |
|||
] |
|||
] |
|||
loop 1..12 'month [ |
|||
print to :string.format:"yyyy-MM-dd" lastFridayForMonth month |
|||
]</syntaxhighlight> |
|||
{{out}} |
|||
<pre>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</pre> |
|||
=={{header|AutoHotkey}}== |
=={{header|AutoHotkey}}== |
||
< |
<syntaxhighlight lang="ahk">if 1 = ; no parameter passed |
||
{ |
{ |
||
InputBox, 1, Last Fridays of year, Enter a year:, , , , , , , , %A_YYYY% |
InputBox, 1, Last Fridays of year, Enter a year:, , , , , , , , %A_YYYY% |
||
Line 299: | Line 767: | ||
stmp += 1, days |
stmp += 1, days |
||
} |
} |
||
MsgBox % res</ |
MsgBox % res</syntaxhighlight> |
||
{{out}} for 2012: |
{{out}} for 2012: |
||
<pre>2012-01-27 |
<pre>2012-01-27 |
||
Line 316: | Line 784: | ||
=={{header|AutoIt}}== |
=={{header|AutoIt}}== |
||
<syntaxhighlight lang="autoit"> |
|||
<lang AutoIt> |
|||
#include <Date.au3> |
#include <Date.au3> |
||
Line 339: | Line 807: | ||
ConsoleWrite($sResult) |
ConsoleWrite($sResult) |
||
EndFunc ;==>_GetFridays |
EndFunc ;==>_GetFridays |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 359: | Line 827: | ||
=={{header|AWK}}== |
=={{header|AWK}}== |
||
<syntaxhighlight lang="awk"> |
|||
<lang AWK> |
|||
# syntax: GAWK -f LAST_FRIDAY_OF_EACH_MONTH.AWK year |
# syntax: GAWK -f LAST_FRIDAY_OF_EACH_MONTH.AWK year |
||
# converted from Fortran |
# converted from Fortran |
||
Line 377: | Line 845: | ||
exit(0) |
exit(0) |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 393: | Line 861: | ||
2012-12-28 |
2012-12-28 |
||
</pre> |
</pre> |
||
=={{header|BBC BASIC}}== |
|||
{{works with|BBC BASIC for Windows}} |
|||
<syntaxhighlight lang="bbcbasic"> INSTALL @lib$ + "DATELIB" |
|||
INPUT "What year to calculate (YYYY)? " Year% |
|||
PRINT '"Last Fridays in ";Year% " are on:" |
|||
FOR Month%=1 TO 12 |
|||
PRINT Year% "-" RIGHT$("0" + STR$Month%, 2) "-"; \ |
|||
\ FN_dim(Month%, Year%) - (FN_dow(FN_mjd(FN_dim(Month%, Year%), Month%, Year%)) + 2) MOD 7 |
|||
NEXT</syntaxhighlight> |
|||
{{out}} |
|||
<pre>What year to calculate (YYYY)? 2023 |
|||
Last Fridays in 2023 are on: |
|||
2023-01-27 |
|||
2023-02-24 |
|||
2023-03-31 |
|||
2023-04-28 |
|||
2023-05-26 |
|||
2023-06-30 |
|||
2023-07-28 |
|||
2023-08-25 |
|||
2023-09-29 |
|||
2023-10-27 |
|||
2023-11-24 |
|||
2023-12-29</pre> |
|||
=={{header|Befunge}}== |
=={{header|Befunge}}== |
||
Line 398: | Line 894: | ||
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. |
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. |
||
< |
<syntaxhighlight lang="befunge">":raeY",,,,,&>55+,:::45*:*%\"d"%!*\4%+!3v |
||
v2++1**"I"5\+/*:*54\-/"d"\/4::-1::p53+g5< |
v2++1**"I"5\+/*:*54\-/"d"\/4::-1::p53+g5< |
||
>:00p5g4-+7%\:0\v>,"-",5g+:55+/68*+,55+%v |
>:00p5g4-+7%\:0\v>,"-",5g+:55+/68*+,55+%v |
||
^<<_$$vv*86%+55:<^+*86%+55,+*86/+55:-1:<6 |
^<<_$$vv*86%+55:<^+*86%+55,+*86/+55:-1:<6 |
||
>$$^@$<>+\55+/:#^_$>:#,_$"-",\:04-\-00g^8 |
>$$^@$<>+\55+/:#^_$>:#,_$"-",\:04-\-00g^8 |
||
^<# #"#"##"#"##!` +76:+1g00,+55,+*<</ |
^<# #"#"##"#"##!` +76:+1g00,+55,+*<</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 424: | Line 920: | ||
Doesn't work with Julian calendar (then again, you probably don't need to plan your weekends for middle ages). |
Doesn't work with Julian calendar (then again, you probably don't need to plan your weekends for middle ages). |
||
< |
<syntaxhighlight lang="c">#include <stdio.h> |
||
#include <stdlib.h> |
#include <stdlib.h> |
||
Line 443: | Line 939: | ||
return 0; |
return 0; |
||
}</ |
}</syntaxhighlight> |
||
=={{header|C sharp}}== |
=={{header|C sharp}}== |
||
< |
<syntaxhighlight lang="csharp">using System; |
||
using System.Collections.Generic; |
using System.Collections.Generic; |
||
using System.Globalization; |
using System.Globalization; |
||
Line 483: | Line 979: | ||
} |
} |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>01/27/2012 |
<pre>01/27/2012 |
||
Line 501: | Line 997: | ||
{{libheader|Boost}} |
{{libheader|Boost}} |
||
called with <code>./last_fridays 2012</code> |
called with <code>./last_fridays 2012</code> |
||
< |
<syntaxhighlight lang="cpp">#include <boost/date_time/gregorian/gregorian.hpp> |
||
#include <iostream> |
#include <iostream> |
||
#include <cstdlib> |
#include <cstdlib> |
||
Line 517: | Line 1,013: | ||
} |
} |
||
return 0 ; |
return 0 ; |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>2012-Jan-27 |
<pre>2012-Jan-27 |
||
Line 531: | Line 1,027: | ||
2012-Nov-30 |
2012-Nov-30 |
||
2012-Dec-28 |
2012-Dec-28 |
||
</pre> |
|||
===Using C++20=== |
|||
Using C++20 this task can be completed without external libraries. |
|||
<syntaxhighlight lang="c++"> |
|||
#include <chrono> |
|||
#include <iostream> |
|||
int main() { |
|||
std::cout << "The dates of the last Friday in each month of 2023:" << std::endl; |
|||
for ( unsigned int m = 1; m <= 12; ++m ) { |
|||
std::chrono::days days_in_month = std::chrono::sys_days{std::chrono::year{2023}/m/std::chrono::last} |
|||
- std::chrono::sys_days{std::chrono::year{2023}/m/1} + std::chrono::days{1}; |
|||
const unsigned int last_day = days_in_month / std::chrono::days{1}; |
|||
std::chrono::year_month_day ymd{std::chrono::year{2023}, std::chrono::month{m}, std::chrono::day{last_day}}; |
|||
while ( std::chrono::weekday{ymd} != std::chrono::Friday ) { |
|||
ymd = std::chrono::sys_days{ymd} - std::chrono::days{1}; |
|||
} |
|||
std::cout << ymd << std::endl; |
|||
} |
|||
} |
|||
</syntaxhighlight> |
|||
{{ out }} |
|||
<pre> |
|||
The dates of the last Friday in each month of 2023: |
|||
2023-01-27 |
|||
2023-02-24 |
|||
2023-03-31 |
|||
2023-04-28 |
|||
2023-05-26 |
|||
2023-06-30 |
|||
2023-07-28 |
|||
2023-08-25 |
|||
2023-09-29 |
|||
2023-10-27 |
|||
2023-11-24 |
|||
2023-12-29 |
|||
</pre> |
</pre> |
||
Line 536: | Line 1,073: | ||
{{libheader|clj-time}} |
{{libheader|clj-time}} |
||
< |
<syntaxhighlight lang="clojure">(use '[clj-time.core :only [last-day-of-the-month day-of-week minus days]] |
||
'[clj-time.format :only [unparse formatters]]) |
'[clj-time.format :only [unparse formatters]]) |
||
Line 546: | Line 1,083: | ||
(defn last-fridays-formatted [year] |
(defn last-fridays-formatted [year] |
||
(sort (map #(unparse (formatters :year-month-day) %) (last-fridays year))))</ |
(sort (map #(unparse (formatters :year-month-day) %) (last-fridays year))))</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 564: | Line 1,101: | ||
=={{header|COBOL}}== |
=={{header|COBOL}}== |
||
<syntaxhighlight lang="cobol"> |
|||
<lang COBOL> |
|||
program-id. last-fri. |
program-id. last-fri. |
||
data division. |
data division. |
||
Line 613: | Line 1,150: | ||
. |
. |
||
end program last-fri. |
end program last-fri. |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
Line 632: | Line 1,169: | ||
=={{header|CoffeeScript}}== |
=={{header|CoffeeScript}}== |
||
< |
<syntaxhighlight lang="coffeescript"> |
||
last_friday_of_month = (year, month) -> |
last_friday_of_month = (year, month) -> |
||
# month is 1-based, JS API is 0-based, then we use |
# month is 1-based, JS API is 0-based, then we use |
||
Line 651: | Line 1,188: | ||
year = parseInt process.argv[2] |
year = parseInt process.argv[2] |
||
print_last_fridays_of_month year |
print_last_fridays_of_month year |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<lang> |
<syntaxhighlight lang="text"> |
||
> coffee last_friday.coffee 2012 |
> coffee last_friday.coffee 2012 |
||
Fri Jan 27 2012 |
Fri Jan 27 2012 |
||
Line 667: | Line 1,204: | ||
Fri Nov 30 2012 |
Fri Nov 30 2012 |
||
Fri Dec 28 2012 |
Fri Dec 28 2012 |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Common Lisp}}== |
=={{header|Common Lisp}}== |
||
Line 673: | Line 1,210: | ||
The command-line argument processing is the only CLISP-specific code. |
The command-line argument processing is the only CLISP-specific code. |
||
< |
<syntaxhighlight lang="lisp">(defun friday-before (year month day) |
||
(let* |
(let* |
||
((timestamp (encode-universal-time 0 0 12 day month year)) |
((timestamp (encode-universal-time 0 0 12 day month year)) |
||
Line 686: | Line 1,223: | ||
(let* ((year (read-from-string (car *args*)))) |
(let* ((year (read-from-string (car *args*)))) |
||
(format t "~{~{~a-~2,'0d-~2,'0d~}~%~}" (last-fridays year)))</ |
(format t "~{~{~a-~2,'0d-~2,'0d~}~%~}" (last-fridays year)))</syntaxhighlight> |
||
Sample run for the year 2015: |
Sample run for the year 2015: |
||
Line 704: | Line 1,241: | ||
=={{header|D}}== |
=={{header|D}}== |
||
< |
<syntaxhighlight lang="d">import std.stdio, std.datetime, std.traits; |
||
void lastFridays(in uint year) { |
void lastFridays(in uint year) { |
||
Line 718: | Line 1,255: | ||
void main() { |
void main() { |
||
lastFridays(2012); |
lastFridays(2012); |
||
}</ |
}</syntaxhighlight> |
||
<pre>2012-Jan-27 |
<pre>2012-Jan-27 |
||
2012-Feb-24 |
2012-Feb-24 |
||
Line 731: | Line 1,268: | ||
2012-Nov-30 |
2012-Nov-30 |
||
2012-Dec-28</pre> |
2012-Dec-28</pre> |
||
=={{header|Delphi}}== |
|||
Uses the standard Delphi library. |
|||
<syntaxhighlight lang="delphi">program LastFridayOfMonth; |
|||
{$APPTYPE CONSOLE} |
|||
uses |
|||
System.SysUtils, System.DateUtils; |
|||
var |
|||
Year: Word; |
|||
Month: Word; |
|||
D1: TDateTime; |
|||
D2: Word; |
|||
begin |
|||
Write('Enter year: '); |
|||
ReadLn(Year); |
|||
for Month := MonthJanuary to MonthDecember do begin |
|||
D1 := EndOfAMonth(Year, Month); |
|||
D2 := DayOfTheWeek(D1); |
|||
while D2 <> DayFriday do begin |
|||
D1 := IncDay(D1, -1); |
|||
D2 := DayOfTheWeek(D1); |
|||
end; |
|||
WriteLn(DateToStr(D1)); |
|||
end; |
|||
end.</syntaxhighlight> |
|||
{{out}} |
|||
<pre>Enter year: 2019 |
|||
25.01.2019 |
|||
22.02.2019 |
|||
29.03.2019 |
|||
26.04.2019 |
|||
31.05.2019 |
|||
28.06.2019 |
|||
26.07.2019 |
|||
30.08.2019 |
|||
27.09.2019 |
|||
25.10.2019 |
|||
29.11.2019 |
|||
27.12.2019</pre> |
|||
=={{header|EasyLang}}== |
|||
<syntaxhighlight> |
|||
func leap year . |
|||
return if year mod 4 = 0 and (year mod 100 <> 0 or year mod 400 = 0) |
|||
. |
|||
func weekday year month day . |
|||
normdoom[] = [ 3 7 7 4 2 6 4 1 5 3 7 5 ] |
|||
c = year div 100 |
|||
r = year mod 100 |
|||
s = r div 12 |
|||
t = r mod 12 |
|||
c_anchor = (5 * (c mod 4) + 2) mod 7 |
|||
doom = (s + t + (t div 4) + c_anchor) mod 7 |
|||
anchor = normdoom[month] |
|||
if leap year = 1 and month <= 2 |
|||
anchor = (anchor + 1) mod1 7 |
|||
. |
|||
return (doom + day - anchor + 7) mod 7 + 1 |
|||
. |
|||
mdays[] = [ 31 28 31 30 31 30 31 31 30 31 30 31 ] |
|||
proc last_fridays year . . |
|||
for m to 12 |
|||
d = mdays[m] |
|||
if m = 2 and leap year = 1 |
|||
d = 29 |
|||
. |
|||
d -= (weekday year m d - 6) mod 7 |
|||
m$ = m |
|||
if m < 10 |
|||
m$ = "0" & m |
|||
. |
|||
print year & "-" & m$ & "-" & d |
|||
. |
|||
. |
|||
last_fridays 2023 |
|||
</syntaxhighlight> |
|||
=={{header|Elixir}}== |
=={{header|Elixir}}== |
||
< |
<syntaxhighlight lang="elixir">defmodule RC do |
||
def lastFriday(year) do |
def lastFriday(year) do |
||
Enum.map(1..12, fn month -> |
Enum.map(1..12, fn month -> |
||
Line 747: | Line 1,365: | ||
Enum.each(RC.lastFriday(y), fn {year, month, day} -> |
Enum.each(RC.lastFriday(y), fn {year, month, day} -> |
||
:io.format "~4b-~2..0w-~2..0w~n", [year, month, day] |
:io.format "~4b-~2..0w-~2..0w~n", [year, month, day] |
||
end)</ |
end)</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 764: | Line 1,382: | ||
2012-12-28 |
2012-12-28 |
||
</pre> |
</pre> |
||
=={{header|Elm}}== |
=={{header|Elm}}== |
||
< |
<syntaxhighlight lang="elm">import Html exposing (Html, Attribute, text, div, input) |
||
import Html.App exposing (beginnerProgram) |
import Html.App exposing (beginnerProgram) |
||
import Html.Attributes exposing (placeholder, value, style) |
import Html.Attributes exposing (placeholder, value, style) |
||
Line 831: | Line 1,450: | ||
, view = view |
, view = view |
||
, update = update |
, update = update |
||
}</ |
}</syntaxhighlight> |
||
Link to live demo: http://dc25.github.io/lastFridayOfMonthElm/ |
Link to live demo: http://dc25.github.io/lastFridayOfMonthElm/ |
||
Line 849: | Line 1,468: | ||
December 26, 2003 |
December 26, 2003 |
||
</pre> |
</pre> |
||
=={{header|Emacs Lisp}}== |
|||
<syntaxhighlight lang="lisp">(require 'calendar) |
|||
(defun last-friday (year) |
|||
"Print the last Friday in each month of year" |
|||
(mapcar (lambda (month) |
|||
(let* |
|||
((days (number-sequence 1 (calendar-last-day-of-month month year))) |
|||
(mdy (mapcar (lambda (x) (list month x year)) days)) |
|||
(weekdays (mapcar #'calendar-day-of-week mdy)) |
|||
(lastfriday (1+ (cl-position 5 weekdays :from-end t)))) |
|||
(insert (format "%i-%02i-%02i \n" year month lastfriday)))) |
|||
(number-sequence 1 12))) |
|||
(last-friday 2012)</syntaxhighlight> |
|||
{{output}} |
|||
<pre>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 </pre> |
|||
=={{header|Erlang}}== |
=={{header|Erlang}}== |
||
<syntaxhighlight lang="erlang"> |
|||
<lang Erlang> |
|||
-module( last_date_each_month ). |
-module( last_date_each_month ). |
||
Line 870: | Line 1,518: | ||
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], |
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]. |
[{Year, X, proplists:get_value(X, Months_days)} || X <- Months]. |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
32> [io:fwrite("~B-~2.10.0B-~B~n", [Y,M,D]) || {Y,M,D} <- last_date_each_month:friday(2012)]. |
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 |
|||
</pre> |
|||
=={{header|Factor}}== |
|||
{{works with|Factor|0.98}} |
|||
The <code>last-friday-of-month</code> word in the <code>calendar</code> vocabulary does most of the work. This program expects the year as a command line argument. |
|||
<syntaxhighlight lang="factor">USING: calendar calendar.format command-line io kernel math.parser sequences ; |
|||
IN: rosetta-code.last-fridays |
|||
(command-line) second string>number <year> 12 <iota> |
|||
[ months time+ last-friday-of-month ] with map |
|||
[ timestamp>ymd print ] each</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
>factor last-fridays.factor 2012 |
|||
2012-01-27 |
2012-01-27 |
||
2012-02-24 |
2012-02-24 |
||
Line 891: | Line 1,565: | ||
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. |
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. |
||
< |
<syntaxhighlight lang="fortran">program fridays |
||
implicit none |
implicit none |
||
integer :: days(1:12) = (/31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31/) |
integer :: days(1:12) = (/31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31/) |
||
Line 904: | Line 1,578: | ||
end do |
end do |
||
end program |
end program |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|FreeBASIC}}== |
=={{header|FreeBASIC}}== |
||
< |
<syntaxhighlight lang="freebasic">' version 23-06-2015 |
||
' compile with: fbc -s console |
' compile with: fbc -s console |
||
Line 916: | Line 1,590: | ||
Function leapyear(Year_ As Integer) As Integer |
Function leapyear(Year_ As Integer) As Integer |
||
' from the |
' from the leapyear entry |
||
If (Year_ Mod 4) <> 0 Then Return FALSE |
If (Year_ Mod 4) <> 0 Then Return FALSE |
||
If (Year_ Mod 100) = 0 AndAlso (Year_ Mod 400) <> 0 Then Return FALSE |
If (Year_ Mod 100) = 0 AndAlso (Year_ Mod 400) <> 0 Then Return FALSE |
||
Line 991: | Line 1,665: | ||
Loop |
Loop |
||
End</ |
End</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>For what year do you want to find the last Friday of the month |
<pre>For what year do you want to find the last Friday of the month |
||
any number below 1800 stops program, year in YYYY format? |
any number below 1800 stops program, year in YYYY format? 2017 |
||
Last Friday of the month for |
Last Friday of the month for 2017 |
||
27 January |
|||
24 February |
|||
31 March |
|||
28 April |
|||
26 May |
|||
30 June |
|||
28 July |
|||
25 August |
|||
29 September |
|||
27 October |
|||
24 November |
|||
29 December</pre> |
|||
=={{header|Frink}}== |
|||
<syntaxhighlight lang="frink">d = parseDate[ARGS@0] |
|||
for m = 1 to 12 |
|||
{ |
|||
d = beginningOfNextMonth[d] |
|||
n = d - (((parseInt[d -> ### u ###] + 1) mod 7) + 1) days |
|||
println[n -> ### yyyy-MM-dd ###] |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre>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 |
|||
</pre> |
|||
=={{header|Fōrmulæ}}== |
|||
{{FormulaeEntry|page=https://formulae.org/?script=examples/Last_day_of_each_month_of_a_year%2C_being_a_given_weekday}} |
|||
'''Solution''' |
|||
The following function retrieves the last day of each month of a year, being a given weekday: |
|||
[[File:Fōrmulæ - Last day of each month of a year, being a given weekday 01.png]] |
|||
'''Test case''' |
|||
[[File:Fōrmulæ - Last day of each month of a year, being a given weekday 04.png]] |
|||
[[File:Fōrmulæ - Last day of each month of a year, being a given weekday 05.png]] |
|||
=={{header|Gambas}}== |
|||
<syntaxhighlight lang="gambas">Public Sub Form_Open() |
|||
Dim siYear As Short = InputBox("Please input a year", "Last Friday of each month") |
|||
Dim siMonth, siDay As Short |
|||
Dim dDay As Date |
|||
For siMonth = 1 To 12 |
|||
For siDay = 31 DownTo 22 |
|||
Try dDay = Date(siYear, siMonth, siDay) |
|||
If Error Then Continue |
|||
If WeekDay(dDay) = 5 Then |
|||
Print Format(dDay, "yyyy-mm-dd");; |
|||
Print Space(6) & Format(dDay, "dddd dd mmmm yyyy") |
|||
Break |
|||
End If |
|||
Next |
|||
Next |
|||
Me.Close |
|||
End</syntaxhighlight> |
|||
Output: |
|||
<pre> |
|||
1925-01-30 Friday 30 January 1925 |
|||
1925-02-27 Friday 27 February 1925 |
|||
1925-03-27 Friday 27 March 1925 |
|||
1925-04-24 Friday 24 April 1925 |
|||
1925-05-29 Friday 29 May 1925 |
|||
1925-06-26 Friday 26 June 1925 |
|||
1925-07-31 Friday 31 July 1925 |
|||
1925-08-28 Friday 28 August 1925 |
|||
1925-09-25 Friday 25 September 1925 |
|||
1925-10-30 Friday 30 October 1925 |
|||
1925-11-27 Friday 27 November 1925 |
|||
1925-12-25 Friday 25 December 1925 |
|||
</pre> |
|||
=={{header|Go}}== |
=={{header|Go}}== |
||
< |
<syntaxhighlight lang="go">package main |
||
import ( |
import ( |
||
Line 1,032: | Line 1,783: | ||
fmt.Println(d.Format("2006-01-02")) |
fmt.Println(d.Format("2006-01-02")) |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 1,054: | Line 1,805: | ||
Test: |
Test: |
||
< |
<syntaxhighlight lang="groovy">def ymd = { it.format('yyyy-MM-dd') } |
||
def lastFridays = lastWeekDays.curry(Day.Fri) |
def lastFridays = lastWeekDays.curry(Day.Fri) |
||
lastFridays(args[0] as int).each { println (ymd(it)) }</ |
lastFridays(args[0] as int).each { println (ymd(it)) }</syntaxhighlight> |
||
Execution (Cygwin on Windows 7): |
Execution (Cygwin on Windows 7): |
||
Line 1,076: | Line 1,827: | ||
=={{header|Haskell}}== |
=={{header|Haskell}}== |
||
< |
<syntaxhighlight lang="haskell">import Data.Time.Calendar |
||
(Day, addDays, showGregorian, fromGregorian, gregorianMonthLength) |
|||
import Data.Time.Calendar.WeekDate |
|||
import Data.Time.Calendar.WeekDate (toWeekDate) |
|||
import Data.List (transpose, intercalate) |
|||
-- [1 .. 7] for [Mon .. Sun] |
|||
findFriday date = head $ filter isFriday $ map toDate [-6 .. 0] |
|||
findWeekDay :: Int -> Day -> Day |
|||
where |
|||
findWeekDay dayOfWeek date = |
|||
toDate ago = addDays ago date |
|||
head |
|||
isFriday theDate = let (_ , _ , day) = toWeekDate theDate |
|||
(filter |
|||
in day == 5 |
|||
(\x -> |
|||
let (_, _, day) = toWeekDate x |
|||
in day == dayOfWeek) |
|||
((`addDays` date) <$> [-6 .. 0])) |
|||
weekDayDates :: Int -> Integer -> [String] |
|||
fridayDates year = map (showGregorian . findFriday) lastDaysInMonth |
|||
weekDayDates dayOfWeek year = |
|||
where |
|||
((showGregorian . findWeekDay dayOfWeek) . |
|||
lastDaysInMonth = map findLastDay [1 .. 12] |
|||
(fromGregorian year <*> gregorianMonthLength year)) <$> |
|||
[1 .. 12] |
|||
main |
main :: IO () |
||
main = |
|||
putStrLn "Please enter a year!" |
|||
mapM_ |
|||
year <- getLine |
|||
putStrLn |
|||
(intercalate " " <$> transpose (weekDayDates 5 <$> [2012 .. 2017]))</syntaxhighlight> |
|||
{{out}} |
|||
{{Out}} |
|||
<pre>Please enter a year! |
|||
<pre>2012-01-27 2013-01-25 2014-01-31 2015-01-30 2016-01-29 2017-01-27 |
|||
2012 |
|||
2012-02-24 2013-02-22 2014-02-28 2015-02-27 2016-02-26 2017-02-24 |
|||
2012-01-27 |
|||
2012-03-30 2013-03-29 2014-03-28 2015-03-27 2016-03-25 2017-03-31 |
|||
2012-02-24 |
|||
2012-04-27 2013-04-26 2014-04-25 2015-04-24 2016-04-29 2017-04-28 |
|||
2012-03-30 |
|||
2012-05-25 2013-05-31 2014-05-30 2015-05-29 2016-05-27 2017-05-26 |
|||
2012-04-27 |
|||
2012-06-29 2013-06-28 2014-06-27 2015-06-26 2016-06-24 2017-06-30 |
|||
2012-05-25 |
|||
2012-07-27 2013-07-26 2014-07-25 2015-07-31 2016-07-29 2017-07-28 |
|||
2012-06-29 |
|||
2012-08-31 2013-08-30 2014-08-29 2015-08-28 2016-08-26 2017-08-25 |
|||
2012-07-27 |
|||
2012-09-28 2013-09-27 2014-09-26 2015-09-25 2016-09-30 2017-09-29 |
|||
2012-08-31 |
|||
2012-10-26 2013-10-25 2014-10-31 2015-10-30 2016-10-28 2017-10-27 |
|||
2012-09-28 |
|||
2012-11-30 2013-11-29 2014-11-28 2015-11-27 2016-11-25 2017-11-24 |
|||
2012-10-26 |
|||
2012-12-28 2013-12-27 2014-12-26 2015-12-25 2016-12-30 2017-12-29</pre> |
|||
2012-11-30 |
|||
2012-12-28</pre> |
|||
=={{header|Icon}} and {{header|Unicon}}== |
=={{header|Icon}} and {{header|Unicon}}== |
||
This will write the last fridays for every year given as an argument. There is no error checking on the year. |
This will write the last fridays for every year given as an argument. There is no error checking on the year. |
||
< |
<syntaxhighlight lang="icon">procedure main(A) |
||
every write(lastfridays(!A)) |
every write(lastfridays(!A)) |
||
end |
end |
||
Line 1,131: | Line 1,888: | ||
end |
end |
||
link datetime, printf</ |
link datetime, printf</syntaxhighlight> |
||
{{libheader|Icon Programming Library}} |
{{libheader|Icon Programming Library}} |
||
Line 1,154: | Line 1,911: | ||
=={{header|J}}== |
=={{header|J}}== |
||
< |
<syntaxhighlight lang="j">require 'dates' |
||
last_fridays=: 12 {. [: ({:/.~ }:"1)@(#~ 5 = weekday)@todate (i.366) + todayno@,&1 1</ |
last_fridays=: 12 {. [: ({:/.~ }:"1)@(#~ 5 = weekday)@todate (i.366) + todayno@,&1 1</syntaxhighlight> |
||
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). |
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). |
||
Line 1,161: | Line 1,918: | ||
Example use: |
Example use: |
||
< |
<syntaxhighlight lang="j"> last_fridays 2012 |
||
2012 1 27 |
2012 1 27 |
||
2012 2 24 |
2012 2 24 |
||
Line 1,173: | Line 1,930: | ||
2012 10 26 |
2012 10 26 |
||
2012 11 30 |
2012 11 30 |
||
2012 12 28</ |
2012 12 28</syntaxhighlight> |
||
=={{header|Java}}== |
=={{header|Java}}== |
||
{{works with|Java|1.5+}} |
{{works with|Java|1.5+}} |
||
< |
<syntaxhighlight lang="java5">import java.text.*; |
||
import java.util.*; |
import java.util.*; |
||
Line 1,202: | Line 1,959: | ||
} |
} |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
{{out}} (for <code>java LastFridays 2012</code>): |
{{out}} (for <code>java LastFridays 2012</code>): |
||
<pre>2012 Jan 27 |
<pre>2012 Jan 27 |
||
Line 1,217: | Line 1,974: | ||
2012 Dec 28</pre> |
2012 Dec 28</pre> |
||
=={{header|JavaScript}}== |
|||
== |
===ES5=== |
||
====Iteration==== |
|||
===Imperative=== |
|||
{{works with|Nodejs}} |
{{works with|Nodejs}} |
||
<syntaxhighlight lang="javascript">var last_friday_of_month, print_last_fridays_of_month; |
|||
<lang javascript> |
|||
var last_friday_of_month, print_last_fridays_of_month; |
|||
last_friday_of_month = function(year, month) { |
last_friday_of_month = function(year, month) { |
||
Line 1,251: | Line 2,005: | ||
year = parseInt(process.argv[2]); |
year = parseInt(process.argv[2]); |
||
return print_last_fridays_of_month(year); |
return print_last_fridays_of_month(year); |
||
})(); |
})();</syntaxhighlight> |
||
{{Out}} |
|||
<pre>>node lastfriday.js 2015 |
|||
</lang> |
|||
{{out}} |
|||
<lang> |
|||
>node lastfriday.js 2015 |
|||
Fri Jan 30 2015 |
Fri Jan 30 2015 |
||
Fri Feb 27 2015 |
Fri Feb 27 2015 |
||
Line 1,268: | Line 2,019: | ||
Fri Oct 30 2015 |
Fri Oct 30 2015 |
||
Fri Nov 27 2015 |
Fri Nov 27 2015 |
||
Fri Dec 25 2015 |
Fri Dec 25 2015</pre> |
||
</lang> |
|||
====Functional composition==== |
|||
<syntaxhighlight lang="javascript">(function () { |
|||
===Functional (ES 5)=== |
|||
<lang JavaScript>(function () { |
|||
'use strict'; |
'use strict'; |
||
Line 1,299: | Line 2,047: | ||
}); |
}); |
||
} |
} |
||
// isoDateString :: Date -> String |
// isoDateString :: Date -> String |
||
Line 1,337: | Line 2,082: | ||
// TEST |
// TEST |
||
return transpose( |
return transpose( |
||
range(2012, 2016) |
range(2012, 2016) |
||
Line 1,348: | Line 2,092: | ||
}) |
}) |
||
.join('\n'); |
.join('\n'); |
||
})();</syntaxhighlight> |
|||
})();</lang> |
|||
{{Out}} |
{{Out}} |
||
Line 1,364: | Line 2,107: | ||
2012-11-30 2013-11-29 2014-11-28 2015-11-27 2016-11-25 |
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</pre> |
2012-12-28 2013-12-27 2014-12-26 2015-12-25 2016-12-30</pre> |
||
===ES6=== |
|||
<syntaxhighlight lang="javascript">(() => { |
|||
"use strict"; |
|||
// ------------ LAST FRIDAY OF EACH MONTH ------------ |
|||
// lastWeekDaysOfYear :: Int -> Int -> [Date] |
|||
const lastWeekDaysOfYear = iWeekDay => |
|||
y => { |
|||
const isLeap = n => ( |
|||
(0 === n % 4) && (0 !== n % 100)) || ( |
|||
0 === y % 400 |
|||
); |
|||
return [ |
|||
31, isLeap(y) ? 29 : 28, |
|||
31, 30, 31, 30, 31, 31, 30, 31, 30, 31 |
|||
] |
|||
.map((d, m) => |
|||
new Date(Date.UTC( |
|||
y, m, d - (( |
|||
new Date(Date.UTC( |
|||
y, m, d |
|||
)) |
|||
.getDay() + (7 - iWeekDay) |
|||
) % 7) |
|||
)) |
|||
); |
|||
}; |
|||
const days = { |
|||
sunday: 0, |
|||
monday: 1, |
|||
tuesday: 2, |
|||
wednesday: 3, |
|||
thursday: 4, |
|||
friday: 5, |
|||
saturday: 6 |
|||
}; |
|||
// ---------------------- TEST ----------------------- |
|||
const main = () => |
|||
transpose( |
|||
enumFromTo(2015)(2019) |
|||
.map(lastWeekDaysOfYear(days.friday)) |
|||
) |
|||
.map( |
|||
row => row.map(isoDateString).join("\t") |
|||
) |
|||
.join("\n"); |
|||
// ---------------- GENERIC FUNCTIONS ---------------- |
|||
// enumFromTo :: Int -> Int -> [Int] |
|||
const enumFromTo = m => |
|||
n => Array.from({ |
|||
length: 1 + n - m |
|||
}, (_, i) => m + i); |
|||
// isoDateString :: Date -> String |
|||
const isoDateString = dte => |
|||
dte.toISOString() |
|||
.substr(0, 10); |
|||
// transpose :: [[a]] -> [[a]] |
|||
const transpose = rows => |
|||
// The columns of the input transposed |
|||
// into new rows. |
|||
0 < rows.length ? rows[0].map( |
|||
(x, i) => rows.flatMap( |
|||
v => v[i] |
|||
) |
|||
) : []; |
|||
// MAIN --- |
|||
return main(); |
|||
})();</syntaxhighlight> |
|||
{{Out}} |
|||
<pre>2015-01-30 2016-01-29 2017-01-27 2018-01-26 2019-01-25 |
|||
2015-02-27 2016-02-26 2017-02-24 2018-02-23 2019-02-22 |
|||
2015-03-27 2016-03-25 2017-03-31 2018-03-30 2019-03-29 |
|||
2015-04-24 2016-04-29 2017-04-28 2018-04-27 2019-04-26 |
|||
2015-05-29 2016-05-27 2017-05-26 2018-05-25 2019-05-31 |
|||
2015-06-26 2016-06-24 2017-06-30 2018-06-29 2019-06-28 |
|||
2015-07-31 2016-07-29 2017-07-28 2018-07-27 2019-07-26 |
|||
2015-08-28 2016-08-26 2017-08-25 2018-08-31 2019-08-30 |
|||
2015-09-25 2016-09-30 2017-09-29 2018-09-28 2019-09-27 |
|||
2015-10-30 2016-10-28 2017-10-27 2018-10-26 2019-10-25 |
|||
2015-11-27 2016-11-25 2017-11-24 2018-11-30 2019-11-29 |
|||
2015-12-25 2016-12-30 2017-12-29 2018-12-28 2019-12-27</pre> |
|||
=={{header|jq}}== |
=={{header|jq}}== |
||
{{ works with|jq|1.4}} |
{{ works with|jq|1.4}} |
||
'''Foundations''' |
'''Foundations''' |
||
< |
<syntaxhighlight lang="jq"># In case your jq does not have "until" defined: |
||
def until(cond; next): |
def until(cond; next): |
||
Line 1,394: | Line 2,232: | ||
| if iso == "iso" or iso == "ISO" then 1 + ((. + 5) % 7) |
| if iso == "iso" or iso == "ISO" then 1 + ((. + 5) % 7) |
||
else . % 7 |
else . % 7 |
||
end ;</ |
end ;</syntaxhighlight> |
||
'''findLastFridays''' |
'''findLastFridays''' |
||
< |
<syntaxhighlight lang="jq"># year and month are numbered conventionally |
||
def findLastFriday(year; month): |
def findLastFriday(year; month): |
||
def isLeapYear: |
def isLeapYear: |
||
Line 1,417: | Line 2,255: | ||
(range(0;12) | "\(months[.]) \(findLastFriday($year; .+1))") ; |
(range(0;12) | "\(months[.]) \(findLastFriday($year; .+1))") ; |
||
$year|tonumber|findLastFridays</ |
$year|tonumber|findLastFridays</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
< |
<syntaxhighlight lang="sh">$ jq --arg year 2012 -n -r -f findLastFridays.jq |
||
YEAR: 2012 |
YEAR: 2012 |
||
January 27 |
January 27 |
||
Line 1,432: | Line 2,270: | ||
October 26 |
October 26 |
||
November 30 |
November 30 |
||
December 28</ |
December 28</syntaxhighlight> |
||
=={{header|Julia}}== |
=={{header|Julia}}== |
||
<syntaxhighlight lang="julia">using Dates |
|||
<lang Julia> |
|||
isdefined(:Date) || using Dates |
|||
const wday = Dates.Fri |
const wday = Dates.Fri |
||
Line 1,461: | Line 2,298: | ||
end |
end |
||
end |
end |
||
</syntaxhighlight>{{out}} |
|||
</lang> |
|||
This code uses the <code>Dates</code> module, which is being incorporated into Julian's standard library with the current development version (<tt>0.4</tt>). I've used <code>isdefined</code> to make this code good for the current stable version (<tt>0.3</tt>) as well as for future releases. If <code>Dates</code> is not installed on your instance of Julian try <code>Pkg.add("Dates")</code> from the <tt>REPL</tt>. |
|||
{{out}} |
|||
<pre> |
<pre> |
||
This script will print the last Fridays of each month of the year given. |
This script will print the last Fridays of each month of the year given. |
||
Line 1,489: | Line 2,322: | ||
Year> |
Year> |
||
</pre> |
|||
=={{header|K}}== |
|||
<syntaxhighlight lang="k"> |
|||
/ List the dates of last Fridays of each month of |
|||
/ a given year |
|||
/ lastfridt.k |
|||
isleap: {(+/~x!' 4 100 400)!2} |
|||
wd: {(_jd x)!7} |
|||
dom: (31;28;31;30;31;30;31;31;30;31;30;31) |
|||
init: {:[isleap x;dom[1]::29;dom[1]::28]} |
|||
wdme: {[m;y]; init y; dt:(10000*y)+(100*m)+dom[m-1];jd::(_jd dt);mewd::(wd dt)} |
|||
lfd: {[m;y]; wdme[m;y];:[mewd>3;jd::jd+(4-mewd);jd::jd-(3+mewd)];dt:_dj(jd);yy:$(yr:dt%10000);dd:$(d:dt!100);mm:$(mo:((dt-yr*10000)%100));arr::arr,$(yy,"-",(2$mm),"-",(2$dd))} |
|||
lfd1: {[y];arr::(); m:1; do[12;lfd[m;y];m+:1]} |
|||
main: {[y]; lfd1[y];`0: ,"Dates of last Fridays of ",($y);12 10#arr} |
|||
</syntaxhighlight> |
|||
The output of a session is given below: |
|||
{{out}} |
|||
<pre> |
|||
K Console - Enter \ for help |
|||
\l lastfridt |
|||
main 2012 |
|||
Dates of last Fridays of 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") |
|||
</pre> |
|||
=={{header|Kotlin}}== |
|||
<syntaxhighlight lang="scala">// version 1.0.6 |
|||
import java.util.* |
|||
fun main(args: Array<String>) { |
|||
print("Enter a year : ") |
|||
val year = readLine()!!.toInt() |
|||
println("The last Fridays of each month in $year are as follows:") |
|||
val calendar = GregorianCalendar(year, 0, 31) |
|||
for (month in 1..12) { |
|||
val daysInMonth = calendar.getActualMaximum(Calendar.DAY_OF_MONTH) |
|||
var offset = calendar[Calendar.DAY_OF_WEEK] - Calendar.FRIDAY |
|||
if (offset < 0) offset += 7 |
|||
val lastFriday = daysInMonth - offset |
|||
println("$year-" + "%02d-".format(month) + "%02d".format(lastFriday)) |
|||
if (month < 12) { |
|||
calendar.add(Calendar.DAY_OF_MONTH, 1) |
|||
calendar.add(Calendar.MONTH, 1) |
|||
calendar.add(Calendar.DAY_OF_MONTH, -1) |
|||
} |
|||
} |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
Enter a year : 2012 |
|||
The last Fridays of each month in 2012 are as follows: |
|||
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 |
|||
</pre> |
</pre> |
||
=={{header|Lasso}}== |
=={{header|Lasso}}== |
||
< |
<syntaxhighlight lang="lasso">define isLeapYear(y::integer) => { |
||
#y % 400 == 0 ? return true |
#y % 400 == 0 ? return true |
||
#y % 100 == 0 ? return false |
#y % 100 == 0 ? return false |
||
Line 1,515: | Line 2,431: | ||
with f in fridays(2012) do => {^ |
with f in fridays(2012) do => {^ |
||
#f->format('%Q') + '\r' |
#f->format('%Q') + '\r' |
||
^}</ |
^}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 1,530: | Line 2,446: | ||
2012-11-30 |
2012-11-30 |
||
2012-12-28</pre> |
2012-12-28</pre> |
||
=={{header|LiveCode}}== |
=={{header|LiveCode}}== |
||
< |
<syntaxhighlight lang="livecode">function lastFriday yyyy |
||
-- year,month num,day of month,hour in 24-hour time,minute,second,numeric day of week. |
-- year,month num,day of month,hour in 24-hour time,minute,second,numeric day of week. |
||
convert the long date to dateitems |
convert the long date to dateitems |
||
Line 1,555: | Line 2,470: | ||
sort fridays ascending numeric |
sort fridays ascending numeric |
||
return fridays |
return fridays |
||
end lastFriday</ |
end lastFriday</syntaxhighlight> |
||
Example< |
Example<syntaxhighlight lang="livecode">put lastFriday("2012")</syntaxhighlight>Output<syntaxhighlight lang="livecode">1 27 |
||
2 24 |
2 24 |
||
3 30 |
3 30 |
||
Line 1,567: | Line 2,482: | ||
10 26 |
10 26 |
||
11 30 |
11 30 |
||
12 28</ |
12 28</syntaxhighlight> |
||
=={{header|Logo}}== |
=={{header|Logo}}== |
||
< |
<syntaxhighlight lang="logo">; Determine if a Gregorian calendar year is leap |
||
to leap? :year |
to leap? :year |
||
output (and |
output (and |
||
Line 1,614: | Line 2,529: | ||
print reduce [(word ?1 "- ?2)] (list :year :month :day) |
print reduce [(word ?1 "- ?2)] (list :year :month :day) |
||
] |
] |
||
bye</ |
bye</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 1,632: | Line 2,547: | ||
=={{header|Lua}}== |
=={{header|Lua}}== |
||
< |
<syntaxhighlight lang="lua">function isLeapYear (y) |
||
return (y % 4 == 0 and y % 100 ~=0) or y % 400 == 0 |
return (y % 4 == 0 and y % 100 ~=0) or y % 400 == 0 |
||
end |
end |
||
Line 1,651: | Line 2,566: | ||
end |
end |
||
lastWeekdays("Friday", tonumber(arg[1]))</ |
lastWeekdays("Friday", tonumber(arg[1]))</syntaxhighlight> |
||
Command line session: |
Command line session: |
||
<pre>>lua lastFridays.lua 2012 |
<pre>>lua lastFridays.lua 2012 |
||
Line 1,669: | Line 2,584: | ||
></pre> |
></pre> |
||
=={{header| |
=={{header|M2000 Interpreter}}== |
||
<lang Mathematica>FridaysOfYear[Y_] := |
|||
<syntaxhighlight lang="m2000 interpreter"> |
|||
module lastfriday { |
|||
string year |
|||
integer y% |
|||
input "Year (e.g. 2023):", y% |
|||
year=str$(y%,"") |
|||
date a="1/1/"+year |
|||
date a1="31/12/"+year |
|||
double i, b=a, c=a1 |
|||
for i=b to b+6 |
|||
if val(date$(i, 1033, "d"))=6 then exit for |
|||
next |
|||
document result$="Last Friday per month for year " + year + {: |
|||
} |
|||
for i=i+7 to c step 7 |
|||
if val(date$(i, 1033, "M")) <>val(date$(i+7, 1033, "M")) then |
|||
result$=date$(i, 1033, "M"+chr$(9)+"dd") + { |
|||
} |
|||
end if |
|||
next |
|||
report result$ |
|||
clipboard result$ |
|||
} |
|||
lastfriday |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
Year (e.g. 2023):2023 |
|||
Last Friday per month for year 2023: |
|||
1 27 |
|||
2 24 |
|||
3 31 |
|||
4 28 |
|||
5 26 |
|||
6 30 |
|||
7 28 |
|||
8 25 |
|||
9 29 |
|||
10 27 |
|||
11 24 |
|||
12 29 |
|||
</pre> |
|||
=={{header|Maple}}== |
|||
<syntaxhighlight lang="maple">fridays := proc(year) |
|||
local i, dt, change, last_days; |
|||
last_days := [31,28,31,30,31,30,31,31,30,31,30,31]; |
|||
if (Calendar:-IsLeapYear(year)) then |
|||
last_days[2] := 28; |
|||
end if; |
|||
for i to 12 do |
|||
dt := Date(year, i, last_days[i]); |
|||
change := 0; |
|||
if not(Calendar:-DayOfWeek(dt) = 6) then |
|||
change := -(Calendar:-DayOfWeek(dt) mod 7)-1; |
|||
end if; |
|||
dt := Calendar:-AdjustDateField(dt, "date", change); |
|||
printf("%d-%d-%d\n", year, Month(dt), DayOfMonth(dt)); |
|||
end do; |
|||
end proc; |
|||
fridays(2012);</syntaxhighlight> |
|||
{{Out|Output}} |
|||
<pre>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</pre> |
|||
=={{header|Mathematica}}/{{header|Wolfram Language}}== |
|||
<syntaxhighlight lang="mathematica">FridaysOfYear[Y_] := |
|||
NestWhile[(DaysPlus[#, - 1]) &, #, (DateString[#, "DayName"] != "Friday") &] & /@ |
NestWhile[(DaysPlus[#, - 1]) &, #, (DateString[#, "DayName"] != "Friday") &] & /@ |
||
Most@Reverse@NestList [DaysPlus[# /. {x_, y_, X_} -> {x, y, 1}, - 1] &, {Y + 1, 1, 1}, 12] |
Most@Reverse@NestList [DaysPlus[# /. {x_, y_, X_} -> {x, y, 1}, - 1] &, {Y + 1, 1, 1}, 12] |
||
Column@FridaysOfYear[2012]</ |
Column@FridaysOfYear[2012]</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>{2012,1,27} |
<pre>{2012,1,27} |
||
Line 1,690: | Line 2,686: | ||
=={{header|MATLAB}} / {{header|Octave}}== |
=={{header|MATLAB}} / {{header|Octave}}== |
||
< |
<syntaxhighlight lang="matlab"> function t = last_fridays_of_year(y) |
||
t1 = datenum([y,1,1,0,0,0]); |
t1 = datenum([y,1,1,0,0,0]); |
||
t2 = datenum([y,12,31,0,0,0]); |
t2 = datenum([y,12,31,0,0,0]); |
||
Line 1,699: | Line 2,695: | ||
datestr(last_fridays_of_year(2012),'yyyy-mm-dd') |
datestr(last_fridays_of_year(2012),'yyyy-mm-dd') |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
Line 1,717: | Line 2,713: | ||
=={{header|Maxima}}== |
=={{header|Maxima}}== |
||
< |
<syntaxhighlight lang="maxima">weekday(year, month, day) := block([m: month, y: year, k], |
||
if m < 3 then (m: m + 12, y: y - 1), |
if m < 3 then (m: m + 12, y: y - 1), |
||
k: 1 + remainder(day + quotient((m + 1)*26, 10) + y + quotient(y, 4) |
k: 1 + remainder(day + quotient((m + 1)*26, 10) + y + quotient(y, 4) |
||
Line 1,736: | Line 2,732: | ||
lastfridays(2012); |
lastfridays(2012); |
||
["2012-1-27", "2012-2-24", "2012-3-30", "2012-4-27", "2012-5-25", "2012-6-29", |
["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"]</ |
"2012-7-27","2012-8-31", "2012-9-28", "2012-10-26", "2012-11-30", "2012-12-28"]</syntaxhighlight> |
||
=={{header|Nanoquery}}== |
|||
<syntaxhighlight lang="nanoquery">import Nanoquery.Util |
|||
// a function to check if a year is a leap year |
|||
def isLeapYear(year) |
|||
if (year % 100 = 0) |
|||
return (year % 400 = 0) |
|||
else |
|||
return (year % 4 = 0) |
|||
end |
|||
end |
|||
// a function to format 1-digit numbers as "0x" |
|||
def form(num) |
|||
if (num > 9) |
|||
return str(num) |
|||
else |
|||
return "0" + str(num) |
|||
end |
|||
end |
|||
// get a year from the console |
|||
print "enter year: " |
|||
year = int(input()) |
|||
// build a list of the expected amount of days for each month |
|||
days = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} |
|||
if isLeapYear($year) |
|||
days[1] = 29 |
|||
end |
|||
// loop through each month |
|||
for month in range(1, len($days)) |
|||
// loop through each day of the month |
|||
friday = null |
|||
for day in range(1, days[month - 1]) |
|||
// create a date object for this date |
|||
date = new(Date) |
|||
date.setYear(year).setMonth(month).setDay(day) |
|||
// check if it's a friday |
|||
if (date.getDayOfWeek() = "Friday") |
|||
// if it is, keep it |
|||
friday = new(Date, date) |
|||
end |
|||
end for |
|||
// display the last friday found |
|||
print friday.getYear() + "-" |
|||
print form(friday.getMonth()) + "-" |
|||
println form(friday.getDay()) |
|||
end</syntaxhighlight> |
|||
=={{header|NetRexx}}== |
=={{header|NetRexx}}== |
||
Line 1,742: | Line 2,791: | ||
{{trans|C}} |
{{trans|C}} |
||
Implements the algorithms from both the [[#Java|Java]] and [[#C|C]] implementations. |
Implements the algorithms from both the [[#Java|Java]] and [[#C|C]] implementations. |
||
< |
<syntaxhighlight lang="netrexx">/* NetRexx */ |
||
options replace format comments java crossref symbols nobinary |
options replace format comments java crossref symbols nobinary |
||
Line 1,818: | Line 2,867: | ||
end |
end |
||
return |
return |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 1,853: | Line 2,902: | ||
=={{header|Nim}}== |
=={{header|Nim}}== |
||
< |
<syntaxhighlight lang="nim">import os, strutils, times |
||
const |
|||
var timeinfo = getLocalTime getTime() |
|||
DaysInMonth: array[Month, int] = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] |
|||
timeinfo.year = paramStr(1).parseInt |
|||
DayDiffs: array[WeekDay, int] = [3, 4, 5, 6, 0, 1, 2] |
|||
for month in mJan .. mDec: |
|||
timeinfo.month = month |
|||
let year = paramStr(1).parseInt |
|||
for day in countdown(31, 1): |
|||
timeinfo.monthday = day |
|||
for month in mJan..mDec: |
|||
let t = getLocalTime(timeInfoToTime timeinfo) |
|||
var lastDay = DaysInMonth[month] |
|||
if t.month == month and t.weekday == dFri: |
|||
if month == mFeb and year.isLeapYear: lastDay = 29 |
|||
echo t.format "yyyy-MM-dd" |
|||
var date = initDateTime(lastDay, month, year, 0, 0, 0) |
|||
break</lang> |
|||
date = date - days(DayDiffs[date.weekday]) |
|||
Sample usage: |
|||
echo date.format("yyyy-MM-dd")</syntaxhighlight> |
|||
<pre>./lastfriday 2012 |
|||
{{out}} |
|||
Sample usage: ./lastfridays 2012 |
|||
<pre> |
|||
2012-01-27 |
2012-01-27 |
||
2012-02-24 |
2012-02-24 |
||
Line 1,884: | Line 2,937: | ||
Using the module [http://caml.inria.fr/pub/docs/manual-ocaml/libref/Unix.html Unix] from the standard OCaml library: |
Using the module [http://caml.inria.fr/pub/docs/manual-ocaml/libref/Unix.html Unix] from the standard OCaml library: |
||
< |
<syntaxhighlight lang="ocaml">#load "unix.cma" |
||
open Unix |
open Unix |
||
Line 1,919: | Line 2,972: | ||
done; |
done; |
||
done; |
done; |
||
Array.iter print_date fridays</ |
Array.iter print_date fridays</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 1,939: | Line 2,992: | ||
{{libheader|OCaml Calendar Library}} |
{{libheader|OCaml Calendar Library}} |
||
< |
<syntaxhighlight lang="ocaml">open CalendarLib |
||
let usage() = |
let usage() = |
||
Line 1,963: | Line 3,016: | ||
aux num_days |
aux num_days |
||
done; |
done; |
||
List.iter print_date (List.rev !fridays)</ |
List.iter print_date (List.rev !fridays)</syntaxhighlight> |
||
Run this script with the command: |
Run this script with the command: |
||
ocaml unix.cma str.cma -I +calendar calendarLib.cma last_fridays.ml 2012 |
ocaml unix.cma str.cma -I +calendar calendarLib.cma last_fridays.ml 2012 |
||
=={{header|Oforth}}== |
=={{header|Oforth}}== |
||
< |
<syntaxhighlight lang="oforth">import: date |
||
: lastFridays(y) |
: lastFridays(y) |
||
Line 1,980: | Line 3,032: | ||
while(dup dayOfWeek Date.FRIDAY <>) [ addDays(-1) ] |
while(dup dayOfWeek Date.FRIDAY <>) [ addDays(-1) ] |
||
println |
println |
||
] ;</ |
] ;</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 2,000: | Line 3,052: | ||
=={{header|PARI/GP}}== |
=={{header|PARI/GP}}== |
||
< |
<syntaxhighlight lang="parigp">\\ Normalized Julian Day Number from date |
||
njd(D) = |
njd(D) = |
||
{ |
{ |
||
Line 2,026: | Line 3,078: | ||
} |
} |
||
for (m=1, 12, a=njd([2012,m+1,0]); print(njdate(a-(a+1)%7)))</ |
for (m=1, 12, a=njd([2012,m+1,0]); print(njdate(a-(a+1)%7)))</syntaxhighlight> |
||
Output:<pre> |
Output:<pre> |
||
Line 2,041: | Line 3,093: | ||
[2012, 11, 30] |
[2012, 11, 30] |
||
[2012, 12, 28]</pre> |
[2012, 12, 28]</pre> |
||
=={{header|Pascal}}== |
|||
{{works with|Free Pascal}} |
|||
Using Free Pascal's DateUtils library would dramatically simplify the coding (see the Delphi example) but for older Pascal implementations the needed routines are the programmer's responsibility. |
|||
<syntaxhighlight lang="pascal"> |
|||
program LastFriday; |
|||
{$mode objfpc}{$H+} |
|||
uses |
|||
SysUtils; |
|||
type |
|||
weekdays = (Sun,Mon,Tue,Wed,Thu,Fri,Sat); |
|||
var |
|||
m, d, y : integer; |
|||
function IsLeapYear(Year : integer) : boolean; |
|||
begin |
|||
if Year mod 4 <> 0 { quick exit in most likely case } |
|||
then IsLeapYear := false |
|||
else if Year mod 400 = 0 |
|||
then IsLeapYear := true |
|||
else if Year mod 100 = 0 |
|||
then IsLeapYear := false |
|||
else { non-century year and divisible by 4 } |
|||
IsLeapYear := true; |
|||
end; |
|||
function DaysInMonth(Month, Year : integer) : integer; |
|||
const |
|||
LastDay : array[1..12] of integer = |
|||
(31,28,31,30,31,30,31,31,30,31,30,31); |
|||
begin |
|||
if (Month = 2) and (IsLeapYear(Year)) then |
|||
DaysInMonth := 29 |
|||
else |
|||
DaysInMonth := LastDay[Month]; |
|||
end; |
|||
{ return day of week (Sun = 0, Mon = 1, etc.) for a } |
|||
{ given mo, da, and yr using Zeller's congruence } |
|||
function DayOfWeek(mo, da, yr : integer) : weekdays; |
|||
var |
|||
y, c, z : integer; |
|||
begin |
|||
if mo < 3 then |
|||
begin |
|||
mo := mo + 10; |
|||
yr := yr - 1 |
|||
end |
|||
else mo := mo - 2; |
|||
y := yr mod 100; |
|||
c := yr div 100; |
|||
z := (26 * mo - 2) div 10; |
|||
z := z + da + y + (y div 4) + (c div 4) - 2 * c + 777; |
|||
DayOfWeek := weekdays(z mod 7); |
|||
end; |
|||
{ return the calendar day of the last occurrence of the } |
|||
{ specified weekday in the given month and year } |
|||
function LastWeekday(k : weekdays; m, y : integer) : integer; |
|||
var |
|||
d : integer; |
|||
w : weekdays; |
|||
begin |
|||
{ determine weekday for the last day of the month } |
|||
d := DaysInMonth(m, y); |
|||
w := DayOfWeek(m, d, y); |
|||
{ back up as needed to desired weekday } |
|||
if w >= k then |
|||
LastWeekday := d - (ord(w) - ord(k)) |
|||
else |
|||
LastWeekday := d - (7 - ord(k)) - ord(w); |
|||
end; |
|||
begin { main program } |
|||
write('Find last Fridays in what year? '); |
|||
readln(y); |
|||
writeln; |
|||
writeln('Month Last Fri'); |
|||
for m := 1 to 12 do |
|||
begin |
|||
d := LastWeekday(Fri, m, y); |
|||
writeln(m:5,' ',d:5); |
|||
end; |
|||
end. |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
Find last Fridays in what year? 2020 |
|||
Month Last Fri |
|||
1 31 |
|||
2 28 |
|||
3 27 |
|||
4 24 |
|||
5 29 |
|||
6 26 |
|||
7 31 |
|||
8 28 |
|||
9 25 |
|||
10 30 |
|||
11 27 |
|||
12 25 |
|||
</pre> |
|||
=={{header|Perl}}== |
=={{header|Perl}}== |
||
< |
<syntaxhighlight lang="perl">#!/usr/bin/perl -w |
||
use strict ; |
use strict ; |
||
use DateTime ; |
use DateTime ; |
||
Line 2,054: | Line 3,214: | ||
} |
} |
||
say $dt->ymd ; |
say $dt->ymd ; |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>2012-01-27 |
<pre>2012-01-27 |
||
Line 2,069: | Line 3,229: | ||
2012-12-28 |
2012-12-28 |
||
</pre> |
</pre> |
||
=={{header|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: |
|||
<pre>$ ./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</pre> |
|||
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, <code>classify</code> sorts the dates into one bin per month (but preserves the order in each bin). We then take the list inside each bin (<code>.value</code>) and find the last (<code>.reverse.first</code>) 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> |
|||
=={{header|Phix}}== |
=={{header|Phix}}== |
||
<!--<syntaxhighlight lang="phix">(phixonline)--> |
|||
<lang Phix>include timedate.e |
|||
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span> |
|||
<span style="color: #008080;">procedure</span> <span style="color: #000000;">last_day_of_month</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">dow</span><span style="color: #0000FF;">)</span> |
|||
constant FRIDAY=6 |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">m</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">12</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #004080;">integer</span> <span style="color: #000000;">d</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">days_in_month</span><span style="color: #0000FF;">(</span><span style="color: #000000;">y</span><span style="color: #0000FF;">,</span><span style="color: #000000;">m</span><span style="color: #0000FF;">),</span> |
|||
procedure showlast(integer dow, integer doy, timedate td) |
|||
<span style="color: #000000;">a</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">dow</span><span style="color: #0000FF;">-</span><span style="color: #7060A8;">day_of_week</span><span style="color: #0000FF;">(</span><span style="color: #000000;">y</span><span style="color: #0000FF;">,</span><span style="color: #000000;">m</span><span style="color: #0000FF;">,</span><span style="color: #000000;">d</span><span style="color: #0000FF;">)</span> |
|||
td = adjust_timedate(td,timedelta(days:=doy-1)) |
|||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%4d-%02d-%02d\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">y</span><span style="color: #0000FF;">,</span><span style="color: #000000;">m</span><span style="color: #0000FF;">,</span><span style="color: #000000;">d</span><span style="color: #0000FF;">+</span><span style="color: #000000;">a</span><span style="color: #0000FF;">-</span><span style="color: #000000;">7</span><span style="color: #0000FF;">*(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">></span><span style="color: #000000;">0</span><span style="color: #0000FF;">)})</span> |
|||
integer {year,month,day} = td |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
while day_of_week(year,month,day)!=dow do day-=1 end while |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span> |
|||
printf(1,"%4d-%02d-%02d\n",{year,month,day}) |
|||
<span style="color: #008080;">constant</span> <span style="color: #000000;">FRIDAY</span><span style="color: #0000FF;">=</span><span style="color: #000000;">5</span> |
|||
end procedure |
|||
<span style="color: #000080;font-style:italic;">--prompt_number() is not compatible with pwa/p2js |
|||
--last_day_of_month(prompt_number("Year:",{1752,9999}),FRIDAY)</span> |
|||
<span style="color: #000000;">last_day_of_month</span><span style="color: #0000FF;">(</span><span style="color: #000000;">2012</span><span style="color: #0000FF;">,</span><span style="color: #000000;">FRIDAY</span><span style="color: #0000FF;">)</span> |
|||
integer doy |
|||
<!--</syntaxhighlight>--> |
|||
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> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 2,150: | Line 3,260: | ||
2012-12-28 |
2012-12-28 |
||
</pre> |
</pre> |
||
=={{header|PHP}}== |
=={{header|PHP}}== |
||
PHP is generally used for web apps, so I am not implementing the command-line component of this task. |
PHP is generally used for web apps, so I am not implementing the command-line component of this task. |
||
< |
<syntaxhighlight lang="php"><?php |
||
function last_friday_of_month($year, $month) { |
function last_friday_of_month($year, $month) { |
||
$day = 0; |
$day = 0; |
||
Line 2,176: | Line 3,285: | ||
$year = 2012; |
$year = 2012; |
||
print_last_fridays_of_month($year); |
print_last_fridays_of_month($year); |
||
?></ |
?></syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 2,193: | Line 3,302: | ||
2012-12-28 |
2012-12-28 |
||
</pre> |
</pre> |
||
=={{header|Picat}}== |
|||
<syntaxhighlight lang="picat">% for command line argument |
|||
main(ARGV) => |
|||
if ARGV.length > 0 then |
|||
Year = ARGV[1].to_integer(), |
|||
show_year(Year), |
|||
nl |
|||
end. |
|||
% Without command line argument |
|||
main => go. |
|||
go => |
|||
show_year(2022), |
|||
nl. |
|||
% Show the months |
|||
show_year(Year) => |
|||
foreach(Date in get_months(Year)) |
|||
println(format_date(Date)) |
|||
end, |
|||
nl. |
|||
% Format date to YYYY-DD-MM |
|||
format_date(Date) = to_fstring("%4d-%02d-%02d",Date[1],Date[2],Date[3]). |
|||
% Return the last Fridays of each month for year Year |
|||
get_months(Year) = |
|||
[ [ [Year,Month,Day] : Day in 1..max_days_in_month(Year,Month), |
|||
dow(Year, Month, Day) == 5].last() : Month in 1..12]. |
|||
% Day of week, Sakamoto's method |
|||
dow(Y, M, D) = R => |
|||
T = [0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4], |
|||
if M < 3 then |
|||
Y := Y - 1 |
|||
end, |
|||
R = (Y + Y // 4 - Y // 100 + Y // 400 + T[M] + D) mod 7. |
|||
% Maximum days in month |
|||
max_days_in_month(Year,Month) = Days => |
|||
if member(Month, [1,3,5,7,8,10,12]) then |
|||
Days = 31 |
|||
elseif member(Month,[4,6,9,11]) then |
|||
Days = 30 |
|||
else |
|||
if leap_year(Year) then |
|||
Days = 29 |
|||
else |
|||
Days = 28 |
|||
end |
|||
end. |
|||
% Is Year a leap year? |
|||
leap_year(Year) => |
|||
(Year mod 4 == 0, Year mod 100 != 0) |
|||
; |
|||
Year mod 400 == 0. </syntaxhighlight> |
|||
===Running the program=== |
|||
There are several ways to run this program; let's call it "last_friday_of_each_month.pi": |
|||
===From Picat's shell=== |
|||
<pre>$ picat |
|||
Picat> cl(last_friday_of_each_month) |
|||
Picat> show_year(2022) |
|||
2022-01-28 |
|||
2022-02-25 |
|||
2022-03-25 |
|||
2022-04-29 |
|||
2022-05-27 |
|||
2022-06-24 |
|||
2022-07-29 |
|||
2022-08-26 |
|||
2022-09-30 |
|||
2022-10-28 |
|||
2022-11-25 |
|||
2022-12-30</pre> |
|||
===From the command line, year as parameter=== |
|||
Via <code>main(ARGV)</code>. |
|||
<pre>$ picat last_friday_of_each_month.pi 2022</pre> |
|||
===From the command line, as a goal=== |
|||
<pre>$ picat -g "show_year(2022)" last_friday_of_each_month.pi</pre> |
|||
===Run the default goal (go/0))=== |
|||
<pre>$ picat last_friday_of_each_month.pi</pre> |
|||
=={{header|PicoLisp}}== |
=={{header|PicoLisp}}== |
||
< |
<syntaxhighlight lang="picolisp">(de lastFridays (Y) |
||
(for M 12 |
(for M 12 |
||
(prinl |
(prinl |
||
Line 2,201: | Line 3,401: | ||
(find '((D) (= "Friday" (day D))) |
(find '((D) (= "Friday" (day D))) |
||
(mapcar '((D) (date Y M D)) `(range 31 22)) ) |
(mapcar '((D) (date Y M D)) `(range 31 22)) ) |
||
"-" ) ) ) )</ |
"-" ) ) ) )</syntaxhighlight> |
||
Test: |
Test: |
||
< |
<syntaxhighlight lang="picolisp">: (lastFridays 2012) |
||
2012-01-27 |
2012-01-27 |
||
2012-02-24 |
2012-02-24 |
||
Line 2,215: | Line 3,415: | ||
2012-10-26 |
2012-10-26 |
||
2012-11-30 |
2012-11-30 |
||
2012-12-28</ |
2012-12-28</syntaxhighlight> |
||
=={{header|Pike}}== |
=={{header|Pike}}== |
||
< |
<syntaxhighlight lang="pike">int(0..1) last_friday(object day) |
||
{ |
{ |
||
return day->week_day() == 5 && |
return day->week_day() == 5 && |
||
Line 2,229: | Line 3,429: | ||
write("%{%s\n%}", days->format_ymd()); |
write("%{%s\n%}", days->format_ymd()); |
||
return 0; |
return 0; |
||
}</ |
}</syntaxhighlight> |
||
=={{header|PL/I}}== |
=={{header|PL/I}}== |
||
<syntaxhighlight lang="pl/i"> |
|||
<lang PL/I> |
|||
Fridays: procedure (year) options (main); /* 8 January 2013 */ |
Fridays: procedure (year) options (main); /* 8 January 2013 */ |
||
declare year character (4) varying; |
declare year character (4) varying; |
||
Line 2,255: | Line 3,455: | ||
end; |
end; |
||
end Fridays; |
end Fridays; |
||
</syntaxhighlight> |
|||
</lang> |
|||
The command: FRIDAYS /2008 produces: |
The command: FRIDAYS /2008 produces: |
||
<pre> |
<pre> |
||
Line 2,290: | Line 3,490: | ||
=={{header|PowerShell}}== |
=={{header|PowerShell}}== |
||
<syntaxhighlight lang="powershell"> |
|||
<lang PowerShell> |
|||
function last-dayofweek { |
function last-dayofweek { |
||
param( |
param( |
||
Line 2,304: | Line 3,504: | ||
} |
} |
||
last-dayofweek 2012 "Friday" |
last-dayofweek 2012 "Friday" |
||
</syntaxhighlight> |
|||
</lang> |
|||
<b>Output:</b> |
<b>Output:</b> |
||
<pre> |
<pre> |
||
Line 2,320: | Line 3,520: | ||
2012-12-28 |
2012-12-28 |
||
</pre> |
</pre> |
||
===Alternate Version=== |
|||
This script finds the first and/or last or all dates of any of the days of week; accepts <code>[Int32]</code> and <code>[DateTime]</code> values for Month and Year parameters; outputs <code>[DateTime]</code> objects by default but has an option to output time strings in various formats. This script also allows for pipeline input based mainly upon the Month parameter. |
|||
This script has a syntax as complex as any PowerShell Cmdlet because it attempts to do everything. |
|||
<syntaxhighlight lang="powershell"> |
|||
function Get-Date0fDayOfWeek |
|||
{ |
|||
[CmdletBinding(DefaultParameterSetName="None")] |
|||
[OutputType([datetime])] |
|||
Param |
|||
( |
|||
[Parameter(Mandatory=$false, |
|||
ValueFromPipeline=$true, |
|||
ValueFromPipelineByPropertyName=$true, |
|||
Position=0)] |
|||
[ValidateRange(1,12)] |
|||
[int] |
|||
$Month = (Get-Date).Month, |
|||
[Parameter(Mandatory=$false, |
|||
ValueFromPipelineByPropertyName=$true, |
|||
Position=1)] |
|||
[ValidateRange(1,9999)] |
|||
[int] |
|||
$Year = (Get-Date).Year, |
|||
[Parameter(Mandatory=$true, ParameterSetName="Sunday")] |
|||
[switch] |
|||
$Sunday, |
|||
[Parameter(Mandatory=$true, ParameterSetName="Monday")] |
|||
[switch] |
|||
$Monday, |
|||
[Parameter(Mandatory=$true, ParameterSetName="Tuesday")] |
|||
[switch] |
|||
$Tuesday, |
|||
[Parameter(Mandatory=$true, ParameterSetName="Wednesday")] |
|||
[switch] |
|||
$Wednesday, |
|||
[Parameter(Mandatory=$true, ParameterSetName="Thursday")] |
|||
[switch] |
|||
$Thursday, |
|||
[Parameter(Mandatory=$true, ParameterSetName="Friday")] |
|||
[switch] |
|||
$Friday, |
|||
[Parameter(Mandatory=$true, ParameterSetName="Saturday")] |
|||
[switch] |
|||
$Saturday, |
|||
[switch] |
|||
$First, |
|||
[switch] |
|||
$Last, |
|||
[switch] |
|||
$AsString, |
|||
[Parameter(Mandatory=$false)] |
|||
[ValidateNotNullOrEmpty()] |
|||
[string] |
|||
$Format = "dd-MMM-yyyy" |
|||
) |
|||
Process |
|||
{ |
|||
[datetime[]]$dates = 1..[DateTime]::DaysInMonth($Year,$Month) | ForEach-Object { |
|||
Get-Date -Year $Year -Month $Month -Day $_ -Hour 0 -Minute 0 -Second 0 | |
|||
Where-Object -Property DayOfWeek -Match $PSCmdlet.ParameterSetName |
|||
} |
|||
if ($First -or $Last) |
|||
{ |
|||
if ($AsString) |
|||
{ |
|||
if ($First) {$dates[0].ToString($Format)} |
|||
if ($Last) {$dates[-1].ToString($Format)} |
|||
} |
|||
else |
|||
{ |
|||
if ($First) {$dates[0]} |
|||
if ($Last) {$dates[-1]} |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
if ($AsString) |
|||
{ |
|||
$dates | ForEach-Object {$_.ToString($Format)} |
|||
} |
|||
else |
|||
{ |
|||
$dates |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</syntaxhighlight> |
|||
The default is to return <code>[DateTime]</code> objects: |
|||
<syntaxhighlight lang="powershell"> |
|||
1..12 | Get-Date0fDayOfWeek -Year 2012 -Last -Friday |
|||
</syntaxhighlight> |
|||
{{Out}} |
|||
<pre> |
|||
Friday, January 27, 2012 12:00:00 AM |
|||
Friday, February 24, 2012 12:00:00 AM |
|||
Friday, March 30, 2012 12:00:00 AM |
|||
Friday, April 27, 2012 12:00:00 AM |
|||
Friday, May 25, 2012 12:00:00 AM |
|||
Friday, June 29, 2012 12:00:00 AM |
|||
Friday, July 27, 2012 12:00:00 AM |
|||
Friday, August 31, 2012 12:00:00 AM |
|||
Friday, September 28, 2012 12:00:00 AM |
|||
Friday, October 26, 2012 12:00:00 AM |
|||
Friday, November 30, 2012 12:00:00 AM |
|||
Friday, December 28, 2012 12:00:00 AM |
|||
</pre> |
|||
Return the <code>[DateTime]</code> objects as strings (using the default string format): |
|||
<syntaxhighlight lang="powershell"> |
|||
1..12 | Get-Date0fDayOfWeek -Year 2012 -Last -Friday -AsString |
|||
</syntaxhighlight> |
|||
{{Out}} |
|||
<pre> |
|||
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 |
|||
</pre> |
|||
Return the <code>[DateTime]</code> objects as strings (specifying the string format): |
|||
<syntaxhighlight lang="powershell"> |
|||
1..12 | Get-Date0fDayOfWeek -Year 2012 -Last -Friday -AsString -Format yyyy-MM-dd |
|||
</syntaxhighlight> |
|||
{{Out}} |
|||
<pre> |
|||
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 |
|||
</pre> |
|||
=={{header|PureBasic}}== |
|||
<syntaxhighlight lang="purebasic">Procedure LastFridayOfEachMonth(yyyy.i,List lfem.i()) |
|||
Define dv.i=ParseDate("%yyyy",Str(yyyy)), mv.i=1 |
|||
NewList d.i() |
|||
For d=1 To 365 |
|||
dv=AddDate(dv,#PB_Date_Day,1) |
|||
If DayOfWeek(dv)=5 |
|||
AddElement(d()) : d()=dv |
|||
EndIf |
|||
Next |
|||
dv=0 |
|||
For mv=1 To 12 |
|||
ForEach d() |
|||
If dv<d() And Month(d())=mv |
|||
dv=d() |
|||
EndIf |
|||
Next |
|||
AddElement(lfem()) : lfem()=dv |
|||
Next |
|||
EndProcedure |
|||
NewList lf.i() |
|||
Define y.i |
|||
OpenConsole("Last Friday of each month") |
|||
Print("Input Year [ 1971 < y < 2038 ]: ") |
|||
y=Val(Input()) |
|||
If y>1971 And y<2038 |
|||
PrintN("Last Friday of each month...") |
|||
LastFridayOfEachMonth(y,lf()) |
|||
ForEach lf() |
|||
PrintN(FormatDate("%dd.%mm.%yyyy",lf())) |
|||
Next |
|||
EndIf |
|||
Print("...End") |
|||
Input()</syntaxhighlight> |
|||
{{out}} |
|||
<pre>Input Year [ 1971 < y < 2038 ]: 2017 |
|||
Last Friday of each month... |
|||
27.01.2017 |
|||
24.02.2017 |
|||
31.03.2017 |
|||
28.04.2017 |
|||
26.05.2017 |
|||
30.06.2017 |
|||
28.07.2017 |
|||
25.08.2017 |
|||
29.09.2017 |
|||
27.10.2017 |
|||
24.11.2017 |
|||
29.12.2017 |
|||
...End</pre> |
|||
=={{header|Python}}== |
=={{header|Python}}== |
||
< |
<syntaxhighlight lang="python">import calendar |
||
def last_fridays(year): |
|||
for month in range(1, 13): |
|||
last_friday = max(week[calendar.FRIDAY] |
|||
for week in calendar.monthcalendar(year, month)) |
|||
print('{:4d}-{:02d}-{:02d}'.format(year, month, last_friday))</syntaxhighlight> |
|||
{{out}} |
|||
<pre>>>> 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</pre> |
|||
Another solution |
|||
<syntaxhighlight lang="python">import calendar |
|||
c=calendar.Calendar() |
c=calendar.Calendar() |
||
fridays={} |
fridays={} |
||
Line 2,336: | Line 3,771: | ||
for item in sorted((month+"-"+day for month,day in fridays.items()), |
for item in sorted((month+"-"+day for month,day in fridays.items()), |
||
key=lambda x:int(x.split("-")[1])): |
key=lambda x:int(x.split("-")[1])): |
||
print item</ |
print item</syntaxhighlight> |
||
Using reduce |
Using reduce |
||
< |
<syntaxhighlight lang="python">import calendar |
||
c=calendar.Calendar() |
c=calendar.Calendar() |
||
fridays={} |
fridays={} |
||
Line 2,353: | Line 3,788: | ||
for item in sorted((month+"-"+day for month,day in fridays.items()), |
for item in sorted((month+"-"+day for month,day in fridays.items()), |
||
key=lambda x:int(x.split("-")[1])): |
key=lambda x:int(x.split("-")[1])): |
||
print item</ |
print item</syntaxhighlight> |
||
using itertools |
using itertools |
||
< |
<syntaxhighlight lang="python">import calendar |
||
from itertools import chain |
from itertools import chain |
||
f=chain.from_iterable |
f=chain.from_iterable |
||
Line 2,373: | Line 3,808: | ||
for item in sorted((month+"-"+day for month,day in fridays.items()), |
for item in sorted((month+"-"+day for month,day in fridays.items()), |
||
key=lambda x:int(x.split("-")[1])): |
key=lambda x:int(x.split("-")[1])): |
||
print item</ |
print item</syntaxhighlight> |
||
=={{header|Quackery}}== |
|||
<syntaxhighlight lang="quackery"> [ over 3 < if [ 1 - ] |
|||
dup 4 / over + |
|||
over 100 / - |
|||
swap 400 / + |
|||
swap 1 - |
|||
[ table |
|||
0 3 2 5 0 3 |
|||
5 1 4 6 2 4 ] |
|||
+ + 7 mod ] is dayofweek ( day month year --> weekday ) |
|||
[ dup 400 mod 0 = iff |
|||
[ drop true ] done |
|||
dup 100 mod 0 = iff |
|||
[ drop false ] done |
|||
4 mod 0 = ] is leap ( year --> b ) |
|||
[ swap 1 - |
|||
[ table |
|||
31 [ dup leap 28 + ] |
|||
31 30 31 30 31 31 30 |
|||
31 30 31 ] |
|||
do nip ] is monthdays ( month year --> n ) |
|||
[ number$ |
|||
2 times |
|||
[ char - join |
|||
over 10 < if |
|||
[ char 0 join ] |
|||
swap number$ join ] |
|||
echo$ ] is echoymd ( day month year --> ) |
|||
[ dip |
|||
[ 2dup monthdays |
|||
dup temp put |
|||
unrot dayofweek ] |
|||
- dup 0 < if [ 7 + ] |
|||
temp take swap - ] is lastwkday ( month year wkd --> n ) |
|||
[ temp put |
|||
12 times |
|||
[ i^ 1+ over |
|||
2dup temp share lastwkday |
|||
unrot echoymd cr ] |
|||
drop temp release ] is lastwkdays ( year wkd --> ) |
|||
[ 5 lastwkdays ] is lastfridays ( year --> ) |
|||
2012 lastfridays</syntaxhighlight> |
|||
{{out}} |
|||
<pre>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</pre> |
|||
=={{header|R}}== |
=={{header|R}}== |
||
< |
<syntaxhighlight lang="rsplus">year = commandArgs(T) |
||
d = as.Date(paste0(year, "-01-01")) |
d = as.Date(paste0(year, "-01-01")) |
||
fridays = d + seq(by = 7, |
fridays = d + seq(by = 7, |
||
Line 2,382: | Line 3,883: | ||
364 + (months(d + 30 + 29) == "February")) |
364 + (months(d + 30 + 29) == "February")) |
||
message(paste(collapse = "\n", fridays[tapply( |
message(paste(collapse = "\n", fridays[tapply( |
||
seq_along(fridays), as.POSIXlt(fridays)$mon, max)]))</ |
seq_along(fridays), as.POSIXlt(fridays)$mon, max)]))</syntaxhighlight> |
||
=={{header|Racket}}== |
=={{header|Racket}}== |
||
< |
<syntaxhighlight lang="racket"> |
||
#lang racket |
#lang racket |
||
(require srfi/19 math) |
(require srfi/19 math) |
||
Line 2,427: | Line 3,928: | ||
(for ([d (last-fridays 2012)]) |
(for ([d (last-fridays 2012)]) |
||
(displayln (~a (date->string d "~a ~d ~b ~Y")))) |
(displayln (~a (date->string d "~a ~d ~b ~Y")))) |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 2,443: | Line 3,944: | ||
Fri 28 Dec 2012 |
Fri 28 Dec 2012 |
||
</pre> |
</pre> |
||
=={{header|Raku}}== |
|||
(formerly Perl 6) |
|||
<syntaxhighlight lang="raku" line>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]; |
|||
}</syntaxhighlight> |
|||
Example: |
|||
<pre>$ ./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</pre> |
|||
A solution without a result array to store things in: |
|||
<syntaxhighlight lang="raku" line>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"); |
|||
}</syntaxhighlight> |
|||
Here, <code>classify</code> sorts the dates into one bin per month (but preserves the order in each bin). We then take the list inside each bin (<code>.value</code>) and find the last (<code>.reverse.first</code>) date which is a Friday. |
|||
Another variation where the data flow can be read left to right using feed operators: |
|||
<syntaxhighlight lang="raku" line>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 |
|||
}</syntaxhighlight> |
|||
=={{header|REBOL}}== |
=={{header|REBOL}}== |
||
The longer version: |
The longer version: |
||
< |
<syntaxhighlight 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-feb: function [year] [either leap-year? year [29] [28]] |
||
Line 2,468: | Line 4,010: | ||
year: to-integer input |
year: to-integer input |
||
repeat month 12 [print last-friday-of-month month year] |
repeat month 12 [print last-friday-of-month month year] |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre>rebol last-fridays.reb <<< 2012 |
<pre>rebol last-fridays.reb <<< 2012 |
||
Line 2,485: | Line 4,027: | ||
</pre> |
</pre> |
||
A shorter version: |
A shorter version: |
||
< |
<syntaxhighlight lang="rebol">last-fridays-of-year: function [year] [ |
||
collect [ |
collect [ |
||
repeat month 12 [ |
repeat month 12 [ |
||
Line 2,497: | Line 4,039: | ||
foreach friday last-fridays-of-year to-integer input [print friday] |
foreach friday last-fridays-of-year to-integer input [print friday] |
||
</syntaxhighlight> |
|||
</lang> |
|||
NB. See "Find the last Sunday of each month" Rosetta for alternative (even more succinct) solution |
NB. See "Find the last Sunday of each month" Rosetta for alternative (even more succinct) solution |
||
Line 2,504: | Line 4,046: | ||
<br>It wasn't optimized just to find a particular day-of-week. |
<br>It wasn't optimized just to find a particular day-of-week. |
||
The documentation for the '''lastDOW''' function (used in the REXX program below): |
The documentation for the '''lastDOW''' function (used in the REXX program below): |
||
<pre> |
|||
╔════════════════════════════════════════════════════════════════════════════════════════════════╗ |
|||
╔════════════════════════════════════════════════════════════════════╗ |
|||
║ 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. ║ |
|||
║ (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.: TU for Tuesday. 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 4=April 5=May 6=June ... 12=December ║ |
|||
║ or the English name of the month, with a minimum length that causes no ambiguity. ║ |
|||
║ I.E.: JA for January, AP for April, JUN for June, JUL for July, 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. ║ |
|||
║ If omitted [or an asterisk(*)], the current year is used. ║ |
|||
║ ║ |
|||
║ Years < 100 must be specified with (at least 2) leading zeroes.║ |
|||
║ The method used is: find the "day number" of the 1st of the next month and 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. ║ |
|||
║ 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 ║ |
|||
<syntaxhighlight lang="rexx">/*REXX program displays the dates of the last Fridays of each month for any given year.*/ |
|||
║ then obtained straightforwardly, or via subtraction. ║ |
|||
parse arg yyyy /*obtain optional argument from the CL.*/ |
|||
╚════════════════════════════════════════════════════════════════════╝ |
|||
do j=1 for 12 /*traipse through all the year's months*/ |
|||
</pre> |
|||
<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.*/ |
say lastDOW('Friday', j, yyyy) /*find last Friday for the Jth month.*/ |
||
end /*j*/ |
end /*j*/ |
||
exit /*stick a fork in it, we're all done. */ |
exit /*stick a fork in it, we're all done. */ |
||
/*──────────────────────────────────────────────────────────────────────────────────────*/ |
/*──────────────────────────────────────────────────────────────────────────────────────*/ |
||
lastDOW: procedure; arg dow .,mm .,yy .; parse arg a.1,a.2,a.3 |
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) |
if mm=='' | mm=='*' then mm= left( date('U'), 2) /*use default month*/ |
||
if yy=='' | yy=='*' then yy=left( date('S'), 4) |
if yy=='' | yy=='*' then yy= left( date('S'), 4) /*use default year */ |
||
if length(yy)==2 then yy=left( date('S'), 2)yy |
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 October November December" |
!=" JAnuary February MARch APril MAY JUNe JULy AUgust September 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 /*no month given ? */ |
||
if arg()>3 then call .er 'arguments specified',4 |
if arg()>3 then call .er 'arguments specified', 4 /*too many args ? */ |
||
do j=1 for 3 /*any plural args ?*/ |
do j=1 for 3 /*any plural args ?*/ |
||
if words(arg(j))>1 |
if words( arg(j) ) > 1 then call .er 'is illegal:', j /*check if plural. */ |
||
end |
end |
||
/*find DOW in list.*/ |
|||
dw= pos(' 'dow, $) /*find day-of-week*/ |
|||
if dw==0 then call .er 'is invalid:' , 1 /*no DOW was found?*/ |
|||
if dw\==lastpos(' 'dow,$) then call .er 'is ambiguous:', 1 /*check min length.*/ |
|||
if datatype(mm, 'M') then do /*is MM alphabetic?*/ |
|||
m= pos(' 'mm, !) /*maybe its good...*/ |
|||
if |
if m==0 then call .er 'is invalid:' , 1 |
||
if m\==lastpos(' 'mm,!) then call .er 'is ambiguous:', 2 |
|||
mm= wordpos( word( substr(!,m), 1), !)-1 /*now, use true Mon*/ |
|||
end |
|||
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') |
if \datatype(mm, 'W') then call .er "isn't an integer:", 2 /*MM (mon) ¬integer*/ |
||
if \datatype(yy,'W') |
if \datatype(yy, 'W') then call .er "isn't an integer:", 3 /*YY (yr) ¬integer*/ |
||
if mm<1 | mm>12 |
if mm<1 | mm>12 then call .er "isn't in range 1──►12:", 2 /*MM out─of─range. */ |
||
if yy=0 |
if yy=0 then call .er "can't be 0 (zero):", 3 /*YY can't be zero.*/ |
||
if yy<0 |
if yy<0 then call .er "can't be negative:", 3 /* " " " neg. */ |
||
if yy>9999 |
if yy>9999 then call .er "can't be > 9999:", 3 /* " " " huge.*/ |
||
tdow=wordpos(word(substr($,dw),1),$)- |
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 |
?= _ // 7 /*calc. DOW, 0──►6*/ |
||
if ?\==tdow then _=_ - ? - 7 + tdow + 7 * (?>tdow) |
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)'; |
.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._ /*plug in a choice.*/ |
||
say; exit 13 |
say; exit 13 /*··· then exit. */</syntaxhighlight> |
||
{{out|output|text= when using the following input of: <tt> 2012 </tt> or <tt> 12 </tt>}} |
|||
<pre> |
<pre> |
||
Friday 27 Jan 2012 |
Friday 27 Jan 2012 |
||
Line 2,601: | Line 4,139: | ||
=={{header|Ring}}== |
=={{header|Ring}}== |
||
< |
<syntaxhighlight lang="ring"> |
||
see "What year to calculate (yyyy) : " |
see "What year to calculate (yyyy) : " |
||
give year |
give year |
||
Line 2,623: | Line 4,161: | ||
next |
next |
||
</syntaxhighlight> |
|||
</lang> |
|||
Output: |
Output: |
||
<pre> |
<pre> |
||
Line 2,640: | Line 4,178: | ||
2012-11-30 |
2012-11-30 |
||
2012-12-28 |
2012-12-28 |
||
</pre> |
|||
=={{header|RPL}}== |
|||
With the release of the HP-48, RPL gained some basic functions for calculating the date, but nothing for directly obtaining the day of the week. |
|||
{{works with|HP|48}} |
|||
≪ { "MON" TUE" "WED" "THU" "FRI" "SAT" "SUN" } |
|||
SWAP 0 TSTR 1 3 SUB POS |
|||
≫ '<span style="color:blue">WKDAY</span>' STO <span style="color:grey">@ ( dd.mmyyyy → 1..7 )</span> |
|||
≪ → year |
|||
≪ { } |
|||
.02 .13 '''FOR''' month |
|||
1 month .13 == DUP .01 month IFTE SWAP year + 1000000 / + + |
|||
DUP <span style="color:blue">WKDAY</span> 1 + 7 MOD 1 + NEG DATE+ 2 TRNC + |
|||
0.01 '''STEP''' 2 FIX |
|||
≫ ≫ '<span style="color:blue">TGIF</span>' STO |
|||
2012 <span style="color:blue">TGIF</span> |
|||
{{out}} |
|||
<pre> |
|||
1: {27.01 24.02 30.03 27.04 25.05 29.06 27.07 31.08 28.09 26.10 30.11 28.12 } |
|||
</pre> |
</pre> |
||
=={{header|Ruby}}== |
=={{header|Ruby}}== |
||
< |
<syntaxhighlight lang="ruby">require 'date' |
||
def last_friday(year, month) |
def last_friday(year, month) |
||
Line 2,652: | Line 4,211: | ||
year = Integer(ARGV.shift) |
year = Integer(ARGV.shift) |
||
(1..12).each {|month| puts last_friday(year, month)}</ |
(1..12).each {|month| puts last_friday(year, month)}</syntaxhighlight> |
||
Friday is <code>d.wday == 5</code>; the expression <code>(d.wday - 5) % 7</code> counts days after Friday. |
Friday is <code>d.wday == 5</code>; the expression <code>(d.wday - 5) % 7</code> counts days after Friday. |
||
Line 2,672: | Line 4,231: | ||
Or get the last day of the month and go to the previous day until it's a Friday. |
Or get the last day of the month and go to the previous day until it's a Friday. |
||
< |
<syntaxhighlight lang="ruby">require 'date' |
||
def last_friday(year, month) |
def last_friday(year, month) |
||
Line 2,679: | Line 4,238: | ||
d |
d |
||
end |
end |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Run BASIC}}== |
=={{header|Run BASIC}}== |
||
< |
<syntaxhighlight lang="runbasic">input "Year:";yr |
||
dayOne$ = "01-01-";yr |
dayOne$ = "01-01-";yr |
||
n1 = date$(dayOne$) |
n1 = date$(dayOne$) |
||
Line 2,696: | Line 4,255: | ||
wend |
wend |
||
print date$(n1) ' print last Friday's date |
print date$(n1) ' print last Friday's date |
||
next i</ |
next i</syntaxhighlight> |
||
<pre>Year:?2013 |
<pre>Year:?2013 |
||
01/25/2013 |
01/25/2013 |
||
Line 2,710: | Line 4,269: | ||
11/29/2013 |
11/29/2013 |
||
12/27/2013</pre> |
12/27/2013</pre> |
||
=={{header|Rust}}== |
|||
<syntaxhighlight lang="rust">use std::env::args; |
|||
use time::{Date, Duration}; |
|||
fn main() { |
|||
let year = args().nth(1).unwrap().parse::<i32>().unwrap(); |
|||
(1..=12) |
|||
.map(|month| Date::try_from_ymd(year + month / 12, ((month % 12) + 1) as u8, 1)) |
|||
.filter_map(|date| date.ok()) |
|||
.for_each(|date| { |
|||
let days_back = |
|||
Duration::days(((date.weekday().number_from_sunday() as i64) % 7) + 1); |
|||
println!("{}", date - days_back); |
|||
}); |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
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 |
|||
</pre> |
|||
=={{header|Scala}}== |
=={{header|Scala}}== |
||
< |
<syntaxhighlight lang="scala">import java.util.Calendar |
||
import java.text.SimpleDateFormat |
import java.text.SimpleDateFormat |
||
Line 2,735: | Line 4,326: | ||
} |
} |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>2012-Jan-27 |
<pre>2012-Jan-27 |
||
Line 2,755: | Line 4,346: | ||
Applicable to any day of the week, cf. [[http://rosettacode.org/wiki/Find_last_sunday_of_each_month#Seed7]]. |
Applicable to any day of the week, cf. [[http://rosettacode.org/wiki/Find_last_sunday_of_each_month#Seed7]]. |
||
< |
<syntaxhighlight lang="seed7">$ include "seed7_05.s7i"; |
||
include "time.s7i"; |
include "time.s7i"; |
||
include "duration.s7i"; |
include "duration.s7i"; |
||
Line 2,784: | Line 4,375: | ||
end for; |
end for; |
||
end if; |
end if; |
||
end func;</ |
end func;</syntaxhighlight> |
||
{{out}} when called with <tt>s7 rosetta/lastWeekdayInMonth 5 2013</tt>: |
{{out}} when called with <tt>s7 rosetta/lastWeekdayInMonth 5 2013</tt>: |
||
Line 2,800: | Line 4,391: | ||
2013-11-29 |
2013-11-29 |
||
2013-12-27 |
2013-12-27 |
||
</pre> |
|||
=={{header|SenseTalk}}== |
|||
<syntaxhighlight lang="sensetalk"> |
|||
ask "What year?" |
|||
put it into year |
|||
put !"The last Fridays of each month in [[year]] are:" |
|||
set lastDayOfMonth to year & "-01-31" -- start with January 31 of the year |
|||
repeat 12 times |
|||
set lastFriday to lastDayOfMonth |
|||
repeat until weekdayName of lastFriday is "Friday" |
|||
subtract a day from lastFriday -- work back to Friday |
|||
end repeat |
|||
put the monthName of lastFriday && ordinalWords of the day of lastFriday |
|||
add a month to lastDayOfMonth -- advance to last day of next month |
|||
end repeat |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
The last Fridays of each month in 2008 are: |
|||
January twenty-fifth |
|||
February twenty-ninth |
|||
March twenty-eighth |
|||
April twenty-fifth |
|||
May thirtieth |
|||
June twenty-seventh |
|||
July twenty-fifth |
|||
August twenty-ninth |
|||
September twenty-sixth |
|||
October thirty-first |
|||
November twenty-eighth |
|||
December twenty-sixth |
|||
</pre> |
</pre> |
||
=={{header|Sidef}}== |
=={{header|Sidef}}== |
||
{{trans|Perl}} |
{{trans|Perl}} |
||
< |
<syntaxhighlight lang="ruby">require('DateTime') |
||
var (year= |
var (year=2016) = ARGV.map{.to_i}... |
||
for month (1..12) { |
|||
var dt = % |
var dt = %O<DateTime>.last_day_of_month(year => year, month => month) |
||
while (dt.day_of_week |
while (dt.day_of_week != 5) { |
||
dt.subtract(days => 1) |
dt.subtract(days => 1) |
||
} |
} |
||
say dt.ymd |
say dt.ymd |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 2,829: | Line 4,457: | ||
2012-11-30 |
2012-11-30 |
||
2012-12-28 |
2012-12-28 |
||
</pre> |
|||
=={{header|Smalltalk}}== |
|||
<syntaxhighlight lang="smalltalk"> |
|||
Pharo Smalltalk |
|||
[ :yr | | firstDay firstFriday | |
|||
firstDay := Date year: yr month: 1 day: 1. |
|||
firstFriday := firstDay addDays: (6 - firstDay dayOfWeek). |
|||
(0 to: 53) |
|||
collect: [ :each | firstFriday addDays: (each * 7) ] |
|||
thenSelect: [ :each | |
|||
(((Date daysInMonth: each monthIndex forYear: yr) - each dayOfMonth) <= 6) and: [ each year = yr ] ] ] |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
Send value: 2012 to the above block to return an array: |
|||
(27 January 2012 24 February 2012 30 March 2012 27 April 2012 25 May 2012 29 June 2012 27 July 2012 31 August 2012 28 September 2012 26 October 2012 30 November 2012 28 December 2012) |
|||
</pre> |
</pre> |
||
=={{header|SQL}}== |
=={{header|SQL}}== |
||
<syntaxhighlight lang="sql"> |
|||
<lang SQL> |
|||
select to_char( next_day( last_day( add_months( to_date( |
select to_char( next_day( last_day( add_months( to_date( |
||
:yr||'01','yyyymm' ),level-1))-7,'Fri') ,'yyyy-mm-dd Dy') lastfriday |
:yr||'01','yyyymm' ),level-1))-7,'Fri') ,'yyyy-mm-dd Dy') lastfriday |
||
from dual |
from dual |
||
connect by level <= 12; |
connect by level <= 12; |
||
</syntaxhighlight> |
|||
</lang> |
|||
<pre> |
<pre> |
||
LASTFRIDAY |
LASTFRIDAY |
||
Line 2,855: | Line 4,502: | ||
12 rows selected. |
12 rows selected. |
||
</pre> |
|||
=={{header|Stata}}== |
|||
<syntaxhighlight lang="stata">program last_fridays |
|||
args year |
|||
clear |
|||
qui set obs 12 |
|||
gen day=dofm(mofd(mdy(_n,1,`year'))+1)-1 |
|||
qui replace day=day-mod(dow(day)-5,7) |
|||
format %td day |
|||
list, noobs noheader sep(6) |
|||
end |
|||
last_fridays 2012 |
|||
+-----------+ |
|||
| 27jan2012 | |
|||
| 24feb2012 | |
|||
| 30mar2012 | |
|||
| 27apr2012 | |
|||
| 25may2012 | |
|||
| 29jun2012 | |
|||
|-----------| |
|||
| 27jul2012 | |
|||
| 31aug2012 | |
|||
| 28sep2012 | |
|||
| 26oct2012 | |
|||
| 30nov2012 | |
|||
| 28dec2012 | |
|||
+-----------+</syntaxhighlight> |
|||
=={{header|Swift}}== |
|||
<syntaxhighlight lang="swift"> |
|||
import Foundation |
|||
func lastFridays(of year: Int) -> [Date] { |
|||
let calendar = Calendar.current |
|||
var dates = [Date]() |
|||
for month in 2...13 { |
|||
let lastDayOfMonth = DateComponents(calendar: calendar, |
|||
year: year, |
|||
month: month, |
|||
day: 0, |
|||
hour: 12) |
|||
let date = calendar.date(from: lastDayOfMonth)! |
|||
let isFriday = calendar.component(.weekday, from: date) == 6 |
|||
if isFriday { |
|||
dates.append(calendar.date(from: lastDayOfMonth)!) |
|||
} else { |
|||
let lastWeekofMonth = calendar.ordinality(of: .weekOfMonth, |
|||
in: .month, |
|||
for: date)! |
|||
let lastWithFriday = lastWeekofMonth - (calendar.component(.weekday, from: date) > 6 ? 0 : 1) |
|||
let lastFridayOfMonth = DateComponents(calendar: calendar, |
|||
year: year, |
|||
month: month - 1, |
|||
hour: 12, |
|||
weekday: 6, |
|||
weekOfMonth: lastWithFriday) |
|||
dates.append(calendar.date(from: lastFridayOfMonth)!) |
|||
} |
|||
} |
|||
return dates |
|||
} |
|||
var dateFormatter = DateFormatter() |
|||
dateFormatter.dateStyle = .short |
|||
print(lastFridays(of: 2013).map(dateFormatter.string).joined(separator: "\n")) |
|||
</syntaxhighlight> |
|||
<pre> |
|||
1/27/12 |
|||
2/24/12 |
|||
3/30/12 |
|||
4/27/12 |
|||
5/25/12 |
|||
6/29/12 |
|||
7/27/12 |
|||
8/31/12 |
|||
9/28/12 |
|||
10/26/12 |
|||
11/30/12 |
|||
12/28/12 |
|||
</pre> |
</pre> |
||
=={{header|Tcl}}== |
=={{header|Tcl}}== |
||
< |
<syntaxhighlight lang="tcl">package require Tcl 8.5 |
||
set year [lindex $argv 0] |
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} { |
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} { |
||
Line 2,865: | Line 4,607: | ||
# Print the interesting part |
# Print the interesting part |
||
puts [clock format $t -format "%Y-%m-%d" -gmt 1] |
puts [clock format $t -format "%Y-%m-%d" -gmt 1] |
||
}</ |
}</syntaxhighlight> |
||
Sample execution: |
Sample execution: |
||
<pre> |
<pre> |
||
Line 2,884: | Line 4,626: | ||
=={{header|TUSCRIPT}}== |
=={{header|TUSCRIPT}}== |
||
< |
<syntaxhighlight lang="tuscript"> |
||
$$ MODE TUSCRIPT |
$$ MODE TUSCRIPT |
||
year=2012 |
year=2012 |
||
Line 2,896: | Line 4,638: | ||
ENDLOOP |
ENDLOOP |
||
ENDLOOP |
ENDLOOP |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre style='height:30ex;overflow:scroll'> |
<pre style='height:30ex;overflow:scroll'> |
||
Line 2,915: | Line 4,657: | ||
=={{header|UNIX Shell}}== |
=={{header|UNIX Shell}}== |
||
Using <code>ncal</code>. 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). |
Using <code>ncal</code>. 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). |
||
< |
<syntaxhighlight lang="bash">#!/bin/sh |
||
if [ -z $1 ]; then exit 1; fi |
if [ -z $1 ]; then exit 1; fi |
||
Line 2,923: | Line 4,665: | ||
for m in 01 02 03 04 05 06 07 08 09 10 11 12; do |
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/'` |
echo $1-$m-`ncal $m $1 | grep Fr | sed 's/.* \([0-9]\)/\1/'` |
||
done</ |
done</syntaxhighlight> |
||
For systems without ncal: |
For systems without ncal: |
||
< |
<syntaxhighlight lang="sh">#!/bin/sh |
||
# usage: last_fridays [ year] |
# usage: last_fridays [ year] |
||
Line 2,943: | Line 4,685: | ||
# Strip leading zeros to avoid octal interpretation |
# Strip leading zeros to avoid octal interpretation |
||
month=$(( 1 + ${month#0} )) |
month=$(( 1 + ${month#0} )) |
||
done</ |
done</syntaxhighlight> |
||
Using <code>date --date</code> from GNU date??? This code is not portable. |
Using <code>date --date</code> from GNU date??? This code is not portable. |
||
< |
<syntaxhighlight lang="bash">#!/bin/sh |
||
# Free code, no limit work |
# Free code, no limit work |
||
Line 3,017: | Line 4,759: | ||
# main |
# main |
||
last_fridays ${1:-2012}</ |
last_fridays ${1:-2012}</syntaxhighlight> |
||
Sample execution: |
Sample execution: |
||
Line 3,037: | Line 4,779: | ||
=={{header|Visual FoxPro}}== |
=={{header|Visual FoxPro}}== |
||
< |
<syntaxhighlight lang="vfp"> |
||
*!* OOP implementaion |
*!* OOP implementaion |
||
LOCAL lnYear As Integer, oCalc As fricalc |
LOCAL lnYear As Integer, oCalc As fricalc |
||
Line 3,072: | Line 4,814: | ||
ENDDEFINE |
ENDDEFINE |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|V (Vlang)}}== |
|||
<syntaxhighlight lang="v (vlang)">import time |
|||
import os |
|||
fn main() { |
|||
mut year := 0 |
|||
mut t := time.now() |
|||
year = os.input("Please select a year: ").int() |
|||
println("Last Fridays of each month of $year") |
|||
println("==================================") |
|||
for i in 1..13 { |
|||
mut j := time.month_days[i-1] |
|||
if i == 2 { |
|||
if time.is_leap_year(year) {j = 29} |
|||
} |
|||
for { |
|||
t = time.parse('$year-${i:02}-$j 12:30:00')! |
|||
if t.weekday_str() == 'Fri' { |
|||
println("${time.long_months[i-1]}: $j") |
|||
break |
|||
} |
|||
j-- |
|||
} |
|||
} |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre>Please select a year: 2012 |
|||
Last Fridays of each month of 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 |
|||
</pre> |
|||
=={{header|Wren}}== |
|||
{{libheader|Wren-date}} |
|||
<syntaxhighlight lang="wren">import "os" for Process |
|||
import "./date" for Date |
|||
var args = Process.arguments |
|||
if (args.count != 1) { |
|||
Fiber.abort("Please pass just the year to be processed.") |
|||
} |
|||
var year = Num.fromString(args[0]) |
|||
System.print("The dates of the last Fridays in the month for %(year) are:") |
|||
Date.default = Date.isoDate |
|||
for (m in 1..12) { |
|||
var d = Date.monthLength(year, m) |
|||
var dt = Date.new(year, m, d) |
|||
var wd = dt.dayOfWeek |
|||
if (wd == 5) { |
|||
System.print(dt) |
|||
} else if (wd > 5) { |
|||
System.print(dt.addDays(-wd + 5)) |
|||
} else { |
|||
System.print(dt.addDays(-wd - 2)) |
|||
} |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
$ wren last_friday.wren 2012 |
|||
The dates of the last Fridays in the month for 2012 are: |
|||
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 |
|||
$ wren last_friday.wren 2020 |
|||
The dates of the last Fridays in the month for 2020 are: |
|||
2020-01-31 |
|||
2020-02-28 |
|||
2020-03-27 |
|||
2020-04-24 |
|||
2020-05-29 |
|||
2020-06-26 |
|||
2020-07-31 |
|||
2020-08-28 |
|||
2020-09-25 |
|||
2020-10-30 |
|||
2020-11-27 |
|||
2020-12-25 |
|||
</pre> |
|||
=={{header|XPL0}}== |
=={{header|XPL0}}== |
||
< |
<syntaxhighlight lang="xpl0">include c:\cxpl\codes; \intrinsic 'code' declarations |
||
func WeekDay(Year, Month, Day); \Return day of week (0=Sun, 1=Mon ... 6=Sat) |
func WeekDay(Year, Month, Day); \Return day of week (0=Sun, 1=Mon ... 6=Sat) |
||
Line 3,097: | Line 4,941: | ||
IntOut(0, LastDay); CrLf(0); |
IntOut(0, LastDay); CrLf(0); |
||
]; |
]; |
||
]</ |
]</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 3,117: | Line 4,961: | ||
=={{header|zkl}}== |
=={{header|zkl}}== |
||
Gregorian calendar |
Gregorian calendar |
||
< |
<syntaxhighlight lang="zkl">var [const] D=Time.Date; |
||
fcn lastDay(y, |
fcn lastDay(y,d){ |
||
'wrap(m){ |
[1..12].pump(List,'wrap(m){ // 12 months, closure for y & d |
||
[ |
[D.daysInMonth(y,m)..1,-1].pump(Void,'wrap(_d){ // work backwards |
||
D.weekDay(y,m, |
D.weekDay(y,m,_d) : |
||
if (_== |
if (_==d) return(Void.Stop,D.toYMDString(y,m,_d)) |
||
}) |
}) |
||
}) |
}) |
||
} |
} |
||
lastDay(2012,D.Friday)</ |
lastDay(2012,D.Friday).concat("\n").println();</syntaxhighlight> |
||
For each month in year y, count back from the last day in the month |
For each month in year y, count back from the last day in the month |
||
until a Friday is found and print that date. |
until a Friday is found and print that date. |
Latest revision as of 17:10, 16 December 2023
![Task](http://static.miraheze.org/rosettacodewiki/thumb/b/ba/Rcode-button-task-crushed.png/64px-Rcode-button-task-crushed.png)
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 date of 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
360 Assembly
The program uses one ASSIST macro (XPRNT) to keep the code as short as possible.
* Last Friday of each month 17/07/2016
LASTFRI CSECT
USING LASTFRI,R13 base register
B 72(R15) skip savearea
DC 17F'0' savearea
STM R14,R12,12(R13) prolog
ST R13,4(R15) " <-
ST R15,8(R13) " ->
LR R13,R15 " addressability
L R4,YEAR year
SRDA R4,32 .
D R4,=F'400' year/400
LTR R4,R4 if year//400=0
BZ LEAP
L R4,YEAR year
SRDA R4,32 .
D R4,=F'4' year/4
LTR R4,R4 if year//4=0
BNZ NOTLEAP
L R4,YEAR year
SRDA R4,32 .
D R4,=F'100' year/400
LTR R4,R4 if year//100=0
BZ NOTLEAP
LEAP MVC DAYS+4(4),=F'29' days(2)=29
NOTLEAP L R8,YEAR year
BCTR R8,0 y=year-1
LA R7,44 44
AR R7,R8 +y
LR R3,R8 y
SRA R3,2 y/4
AR R7,R3 +y/4
LR R4,R8 y
SRDA R4,32 .
D R4,=F'100' y/100
LA R4,0 .
M R4,=F'6' *6
AR R7,R5 +6*(y/100)
LR R4,R8 y
SRDA R4,32 .
D R4,=F'400' y/100
AR R7,R5 k=44+y+y/4+6*(y/100)+y/400
LA R6,1 m=1
LOOPM C R6,=F'12' do m=1 to 12
BH ELOOPM
LR R1,R6 m
SLA R1,2 .
L R2,DAYS-4(R1) days(m)
AR R7,R2 k=k+days(m)
LR R4,R7 k
SRDA R4,32 .
D R4,=F'7' k/7
SR R2,R4 days(m)-k//7
LR R9,R2 d=days(m)-k//7
L R1,YEAR year
CVD R1,DW year: binary to packed
OI DW+7,X'0F' zap sign
UNPK PG(4),DW unpack (ZL4)
CVD R6,DW m : binary to packed
OI DW+7,X'0F' zap sign
UNPK PG+5(2),DW unpack (ZL2)
CVD R9,DW d: binary to packed
OI DW+7,X'0F' zap sign
UNPK PG+8(2),DW unpack (ZL2)
XPRNT PG,L'PG print buffer
LA R6,1(R6) m=m+1
B LOOPM
ELOOPM L R13,4(0,R13) epilog
LM R14,R12,12(R13) " restore
XR R15,R15 " rc=0
BR R14 exit
YEAR DC F'2016' <== input year
DAYS DC F'31',F'28',F'31',F'30',F'31',F'30'
DC F'31',F'31',F'30',F'31',F'30',F'31'
PG DC CL80'YYYY-MM-DD' buffer
XDEC DS CL12 temp
DW DS D packed (PL8) 15num
YREGS
END LASTFRI
- 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
Action!
;https://en.wikipedia.org/wiki/Determination_of_the_day_of_the_week#Sakamoto.27s_methods
BYTE FUNC DayOfWeek(INT y BYTE m,d) ;1<=m<=12, y>1752
BYTE ARRAY t=[0 3 2 5 0 3 5 1 4 6 2 4]
BYTE res
IF m<3 THEN
y==-1
FI
res=(y+y/4-y/100+y/400+t(m-1)+d) MOD 7
RETURN (res)
BYTE FUNC IsLeapYear(INT y)
IF y MOD 100=0 THEN
IF y MOD 400=0 THEN
RETURN (1)
ELSE
RETURN (0)
FI
FI
IF y MOD 4=0 THEN
RETURN (1)
FI
RETURN (0)
INT FUNC GetMaxDay(INT y BYTE m)
BYTE ARRAY MaxDay=[31 28 31 30 31 30 31 31 30 31 30 31]
IF m=2 AND IsLeapYear(y)=1 THEN
RETURN (29)
FI
RETURN (MaxDay(m-1))
PROC PrintB2(BYTE x)
IF x<10 THEN
Put('0)
FI
PrintB(x)
RETURN
PROC Main()
INT MinYear=[1753],MaxYear=[9999],y
BYTE m,d,last,maxD
DO
PrintF("Input year in range %I...%I: ",MinYear,MaxYear)
y=InputI()
UNTIL y>=MinYear AND y<=MaxYear
OD
FOR m=1 TO 12
DO
last=0
maxD=GetMaxDay(y,m)
FOR d=1 TO maxD
DO
IF DayOfWeek(y,m,d)=5 THEN
last=d
FI
OD
PrintI(y) Put('-)
PrintB2(m) Put('-)
PrintB2(last) PutE()
OD
RETURN
- Output:
Screenshot from Atari 8-bit computer
Input year in range 1753...9999: 2021 2021-01-29 2021-02-26 2021-03-26 2021-04-30 2021-05-28 2021-06-25 2021-07-30 2021-08-27 2021-09-24 2021-10-29 2021-11-26 2021-12-31
Ada
Uses GNAT. Applicable to any day of the week, cf. [[1]].
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;
- 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
ALGOL 68
Basically the same as the "Find the Last Sunday Of Each Month" task solution.
BEGIN # find the last Friday in each month of a year #
# returns true if year is a leap year, false otherwise #
# assumes year is in the Gregorian Calendar #
PROC is leap year = ( INT year )BOOL:
year MOD 400 = 0 OR ( year MOD 4 = 0 AND year MOD 100 /= 0 );
# returns the day of the week of the specified date (d/m/y) #
# Sunday = 1 #
PROC day of week = ( INT d, m, y )INT:
BEGIN
INT mm := m;
INT yy := y;
IF mm <= 2 THEN
mm := mm + 12;
yy := yy - 1
FI;
INT j = yy OVER 100;
INT k = yy MOD 100;
(d + ( ( mm + 1 ) * 26 ) OVER 10 + k + k OVER 4 + j OVER 4 + 5 * j ) MOD 7
END # day of week # ;
# returns an array of the last Friday of each month in year #
PROC last fridays = ( INT year )[]INT:
BEGIN
[ 1 : 12 ]INT last days := ( 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 );
IF is leap year( year ) THEN last days[ 2 ] := 29 FI;
# for each month, determine the day number of the #
# last Friday #
[ 1 : 12 ]INT last;
FOR m pos TO 12 DO
INT dow := day of week( last days[ m pos ], m pos, year );
# dow = 1 Sun, 2 Mon, ... , 6 Fri, 0 Sat #
# change to 2 Sun, 3 Mon, ... , 0 Fri, 1 Sat #
dow := ( dow + 1 ) MOD 7;
# offset the last day to the last Friday #
last[ m pos ] := last days[ m pos ] - dow
OD;
last
END # last fridays # ;
# test the last fridays procedure #
INT year = 2021;
[]INT last = last fridays( year );
FOR m pos TO 12 DO
print( ( whole( year, 0 )
, IF m pos < 10 THEN "-0" ELSE "-1" FI
, whole( m pos MOD 10, 0 )
, "-"
, whole( last[ m pos ], 0 )
, newline
)
)
OD
END
- Output:
2021-01-29 2021-02-26 2021-03-26 2021-04-30 2021-05-28 2021-06-25 2021-07-30 2021-08-27 2021-09-24 2021-10-29 2021-11-26 2021-12-31
ALGOL W
Basically the same as the "Find the Last Sunday Of Each Month" task solution, uses the Day_of_week and isLeapYear procedures from the the day-of-the-week and leap-year tasks (included here for convenience).
begin % find the last Friday in each month of a year %
% returns true if year is a leap year, false otherwise %
% assumes year is in the Gregorian Calendar %
logical procedure isLeapYear ( integer value year ) ;
year rem 400 = 0 or ( year rem 4 = 0 and year rem 100 not = 0 );
% returns the day of the week of the specified date (d/m/y) %
% Sunday = 1, Friday = 6, Saturday = 0 %
integer procedure Day_of_week ( integer value d, m, y );
begin
integer j, k, mm, yy;
mm := m;
yy := y;
if mm <= 2 then begin
mm := mm + 12;
yy := yy - 1;
end if_m_le_2;
j := yy div 100;
k := yy rem 100;
(d + ( ( mm + 1 ) * 26 ) div 10 + k + k div 4 + j div 4 + 5 * j ) rem 7
end Day_of_week;
% sets the elements of last to the day of the last Friday %
% of each month in year %
procedure lastFridays ( integer value year
; integer array last ( * )
) ;
begin
integer array lastDays ( 1 :: 12 );
integer m;
% set ld to the day number od the last day of each %
% month in year %
m := 1;
for ld := 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 do begin
lastDays( m ) := ld;
m := m + 1
end for_ld ;
if isLeapYear( year ) then lastDays( 2 ) := 29;
% for each month, determine the day number of the %
% last Friday %
for mPos := 1 until 12 do begin
integer dow;
dow := Day_of_week( lastDays( mPos ), mPos, year );
% dow = 1 Sun, 2 Mon, ... , 6 Fri, 0 Sat %
% change to 2 Sun, 3 Mon, ... , 0 Fri, 1 Sat %
dow := ( dow + 1 ) rem 7;
% offset the last day to the last Friday %
last( mPos ) := lastDays( mPos ) - dow
end for_mPos
end lastFridays ;
begin
% test the lastFridays procedure %
integer array last ( 1 :: 12 );
integer year;
year := 2020;
lastFridays( year, last );
i_w := 1; s_w := 0; % output formatting %
for mPos := 1 until 12 do write( year, if mPos < 10 then "-0" else "-1", mPos rem 10, "-", last( mPos ) )
end
end.
- Output:
2020-01-31 2020-02-28 2020-03-27 2020-04-24 2020-05-29 2020-06-26 2020-07-31 2020-08-28 2020-09-25 2020-10-30 2020-11-27 2020-12-25
AppleScript
-- LAST FRIDAYS OF YEAR ------------------------------------------------------
-- lastFridaysOfYear :: Int -> [Date]
on lastFridaysOfYear(y)
-- lastWeekDaysOfYear :: Int -> Int -> [Date]
script lastWeekDaysOfYear
on |λ|(intYear, iWeekday)
-- lastWeekDay :: Int -> Int -> Date
script lastWeekDay
on |λ|(iLastDay, iMonth)
set iYear to intYear
calendarDate(iYear, iMonth, iLastDay - ¬
(((weekday of calendarDate(iYear, iMonth, iLastDay)) ¬
as integer) + (7 - (iWeekday))) mod 7)
end |λ|
end script
map(lastWeekDay, lastDaysOfMonths(intYear))
end |λ|
-- isLeapYear :: Int -> Bool
on isLeapYear(y)
(0 = y mod 4) and (0 ≠ y mod 100) or (0 = y mod 400)
end isLeapYear
-- lastDaysOfMonths :: Int -> [Int]
on lastDaysOfMonths(y)
{31, cond(isLeapYear(y), 29, 28), ¬
31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
end lastDaysOfMonths
end script
lastWeekDaysOfYear's |λ|(y, Friday as integer)
end lastFridaysOfYear
-- TEST ----------------------------------------------------------------------
on run argv
intercalate(linefeed, ¬
map(isoRow, ¬
transpose(map(lastFridaysOfYear, ¬
apply(cond(class of argv is list and argv ≠ {}, ¬
singleYearOrRange, fiveCurrentYears), ¬
argIntegers(argv))))))
end run
-- ARGUMENT HANDLING ---------------------------------------------------------
-- Up to two optional command line arguments: [yearFrom], [yearTo]
-- (Default range in absence of arguments:
-- from two years ago, to two years ahead)
-- ~ $ osascript ~/Desktop/lastFridays.scpt
-- ~ $ osascript ~/Desktop/lastFridays.scpt 2013
-- ~ $ osascript ~/Desktop/lastFridays.scpt 2013 2016
-- singleYearOrRange :: [Int] -> [Int]
on singleYearOrRange(argv)
apply(cond(length of argv > 0, my enumFromTo, my fiveCurrentYears), argv)
end singleYearOrRange
-- fiveCurrentYears :: () -> [Int]
on fiveCurrentYears(_)
set intThisYear to year of (current date)
enumFromTo(intThisYear - 2, intThisYear + 2)
end fiveCurrentYears
-- argIntegers :: maybe [String] -> [Int]
on argIntegers(argv)
-- parseInt :: String -> Int
script parseInt
on |λ|(s)
s as integer
end |λ|
end script
if class of argv is list and argv ≠ {} then
{map(parseInt, argv)}
else
{}
end if
end argIntegers
-- GENERIC FUNCTIONS ---------------------------------------------------------
-- Dates and date strings ----------------------------------------------------
-- calendarDate :: Int -> Int -> Int -> Date
on calendarDate(intYear, intMonth, intDay)
tell (current date)
set {its year, its month, its day, its time} to ¬
{intYear, intMonth, intDay, 0}
return it
end tell
end calendarDate
-- isoDateString :: Date -> String
on isoDateString(dte)
(((year of dte) as string) & ¬
"-" & text items -2 thru -1 of ¬
("0" & ((month of dte) as integer) as string)) & ¬
"-" & text items -2 thru -1 of ¬
("0" & day of dte)
end isoDateString
-- Testing and tabulation ----------------------------------------------------
-- apply (a -> b) -> a -> b
on apply(f, a)
mReturn(f)'s |λ|(a)
end apply
-- cond :: Bool -> (a -> b) -> (a -> b) -> (a -> b)
on cond(bool, f, g)
if bool then
f
else
g
end if
end cond
-- enumFromTo :: Int -> Int -> [Int]
on enumFromTo(m, n)
if m > n then
set d to -1
else
set d to 1
end if
set lst to {}
repeat with i from m to n by d
set end of lst to i
end repeat
return lst
end enumFromTo
-- intercalate :: Text -> [Text] -> Text
on intercalate(strText, lstText)
set {dlm, my text item delimiters} to ¬
{my text item delimiters, strText}
set strJoined to lstText as text
set my text item delimiters to dlm
return strJoined
end intercalate
-- isoRow :: [Date] -> String
on isoRow(lstDate)
intercalate(tab, map(my isoDateString, lstDate))
end isoRow
-- map :: (a -> b) -> [a] -> [b]
on map(f, xs)
tell mReturn(f)
set lng to length of xs
set lst to {}
repeat with i from 1 to lng
set end of lst to |λ|(item i of xs, i, xs)
end repeat
return lst
end tell
end map
-- Lift 2nd class handler function into 1st class script wrapper
-- mReturn :: Handler -> Script
on mReturn(f)
if class of f is script then
f
else
script
property |λ| : f
end script
end if
end mReturn
-- transpose :: [[a]] -> [[a]]
on transpose(xss)
script column
on |λ|(_, iCol)
script row
on |λ|(xs)
item iCol of xs
end |λ|
end script
map(row, xss)
end |λ|
end script
map(column, item 1 of xss)
end transpose
- Output:
2014-01-31 2015-01-30 2016-01-29 2017-01-27 2018-01-26 2014-02-28 2015-02-27 2016-02-26 2017-02-24 2018-02-23 2014-03-28 2015-03-27 2016-03-25 2017-03-31 2018-03-30 2014-04-25 2015-04-24 2016-04-29 2017-04-28 2018-04-27 2014-05-30 2015-05-29 2016-05-27 2017-05-26 2018-05-25 2014-06-27 2015-06-26 2016-06-24 2017-06-30 2018-06-29 2014-07-25 2015-07-31 2016-07-29 2017-07-28 2018-07-27 2014-08-29 2015-08-28 2016-08-26 2017-08-25 2018-08-31 2014-09-26 2015-09-25 2016-09-30 2017-09-29 2018-09-28 2014-10-31 2015-10-30 2016-10-28 2017-10-27 2018-10-26 2014-11-28 2015-11-27 2016-11-25 2017-11-24 2018-11-30 2014-12-26 2015-12-25 2016-12-30 2017-12-29 2018-12-28
A more straightforward solution:
AppleScript's weekday constants can be coerced either to English text or to the integers 1 (for Sunday) to 7 (Saturday).
on lastFridayOfEachMonthInYear(y)
-- Initialise an AppleScript date to the first day of some month in the specified year.
tell (current date) to set {firstDayOfNextMonth, its day, its year} to {it, 1, y}
-- Get a string representation of y, zero-padded if necessary, and initialise the output string.
set y to text 2 thru 5 of ((10000 + y) as text)
set outputText to "./last_fridays " & y
repeat with nextMonth from 2 to 13 -- Yes!
-- For each month in the year, get the first day of the following month.
set firstDayOfNextMonth's month to nextMonth
-- Calculate the date of the Friday which occurs in the seven days prior to that
-- by subtracting a day plus the difference between the previous day's weekday and the target weekday.
set lastFridayOfThisMonth to firstDayOfNextMonth - (1 + (firstDayOfNextMonth's weekday) mod 7) * days
-- Append the required details to the output text.
set {month:m, day:d} to lastFridayOfThisMonth
tell (10000 + m * 100 + d) as text to ¬
set outputText to outputText & (linefeed & y & "-" & text 2 thru 3 & "-" & text 4 thru 5)
end repeat
return outputText
end lastFridayOfEachMonthInYear
lastFridayOfEachMonthInYear(2020)
- Output:
"./last_fridays 2020 2020-01-31 2020-02-28 2020-03-27 2020-04-24 2020-05-29 2020-06-26 2020-07-31 2020-08-28 2020-09-25 2020-10-30 2020-11-27 2020-12-25"
The above is of course hard-coded for Fridays. It can be made more flexible by taking an AppleScript weekday constant as a parameter:
on lastWeekdayWOfEachMonthInYear(w, y) -- Parameters: (AppleScript weekday constant, AD year number)
-- Initialise an AppleScript date to the first day of some month in the specified year.
tell (current date) to set {firstDayOfNextMonth, its day, its year} to {it, 1, y}
-- Get a string representation of y, zero-padded if necessary, and initialise the output string.
set y to text 2 thru 5 of ((10000 + y) as text)
set outputText to "./last_" & w & "s " & y
repeat with nextMonth from 2 to 13 -- Yes!
-- For each month in the year, get the first day of the following month.
set firstDayOfNextMonth's month to nextMonth
-- Calculate the date of the target weekday which occurs in the seven days prior to that.
-- The calculation can be described in various ways, the simplest being the subtraction of a day plus the difference between the previous day's weekday and the target weekday:
-- firstDayOfNextMonth - (1 + (((firstDayOfNextMonth's weekday) - 1) - w + 7) mod 7) * days
-- But they all boil down to:
set lastWOfThisMonth to firstDayOfNextMonth - (1 + ((firstDayOfNextMonth's weekday) - w + 6) mod 7) * days
-- Get the day and month of the calculated date and append the required details to the output text.
set {month:m, day:d} to lastWOfThisMonth
tell (10000 + m * 100 + d) as text to ¬
set outputText to outputText & (linefeed & y & "-" & text 2 thru 3 & "-" & text 4 thru 5)
end repeat
return outputText
end lastWeekdayWOfEachMonthInYear
lastWeekdayWOfEachMonthInYear(Friday, 2020)
- Output:
"./last_Fridays 2020 2020-01-31 2020-02-28 2020-03-27 2020-04-24 2020-05-29 2020-06-26 2020-07-31 2020-08-28 2020-09-25 2020-10-30 2020-11-27 2020-12-25"
Arturo
lastFridayForMonth: function [m][
ensure -> in? m 1..12
daysOfMonth: [0 31 27 31 30 31 30 31 31 30 31 30 31]
loop range get daysOfMonth m 1 [d][
dt: to :date.format:"yyyy-M-dd" ~"2012-|m|-|d|"
if dt\Day = "Friday" -> return dt
]
]
loop 1..12 'month [
print to :string.format:"yyyy-MM-dd" lastFridayForMonth month
]
- 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
AutoHotkey
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
- 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
#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
- 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
# 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)
}
- 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
BBC BASIC
INSTALL @lib$ + "DATELIB"
INPUT "What year to calculate (YYYY)? " Year%
PRINT '"Last Fridays in ";Year% " are on:"
FOR Month%=1 TO 12
PRINT Year% "-" RIGHT$("0" + STR$Month%, 2) "-"; \
\ FN_dim(Month%, Year%) - (FN_dow(FN_mjd(FN_dim(Month%, Year%), Month%, Year%)) + 2) MOD 7
NEXT
- Output:
What year to calculate (YYYY)? 2023 Last Fridays in 2023 are on: 2023-01-27 2023-02-24 2023-03-31 2023-04-28 2023-05-26 2023-06-30 2023-07-28 2023-08-25 2023-09-29 2023-10-27 2023-11-24 2023-12-29
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.
":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,+*<
- 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).
#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;
}
C#
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));
}
}
}
}
- 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
#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 ;
}
- 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
Using C++20
Using C++20 this task can be completed without external libraries.
#include <chrono>
#include <iostream>
int main() {
std::cout << "The dates of the last Friday in each month of 2023:" << std::endl;
for ( unsigned int m = 1; m <= 12; ++m ) {
std::chrono::days days_in_month = std::chrono::sys_days{std::chrono::year{2023}/m/std::chrono::last}
- std::chrono::sys_days{std::chrono::year{2023}/m/1} + std::chrono::days{1};
const unsigned int last_day = days_in_month / std::chrono::days{1};
std::chrono::year_month_day ymd{std::chrono::year{2023}, std::chrono::month{m}, std::chrono::day{last_day}};
while ( std::chrono::weekday{ymd} != std::chrono::Friday ) {
ymd = std::chrono::sys_days{ymd} - std::chrono::days{1};
}
std::cout << ymd << std::endl;
}
}
- Output:
The dates of the last Friday in each month of 2023: 2023-01-27 2023-02-24 2023-03-31 2023-04-28 2023-05-26 2023-06-30 2023-07-28 2023-08-25 2023-09-29 2023-10-27 2023-11-24 2023-12-29
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))))
- 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
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.
- 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
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
- Output:
> 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
Common Lisp
The command-line argument processing is the only CLISP-specific code.
(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)))
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
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);
}
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
Delphi
Uses the standard Delphi library.
program LastFridayOfMonth;
{$APPTYPE CONSOLE}
uses
System.SysUtils, System.DateUtils;
var
Year: Word;
Month: Word;
D1: TDateTime;
D2: Word;
begin
Write('Enter year: ');
ReadLn(Year);
for Month := MonthJanuary to MonthDecember do begin
D1 := EndOfAMonth(Year, Month);
D2 := DayOfTheWeek(D1);
while D2 <> DayFriday do begin
D1 := IncDay(D1, -1);
D2 := DayOfTheWeek(D1);
end;
WriteLn(DateToStr(D1));
end;
end.
- Output:
Enter year: 2019 25.01.2019 22.02.2019 29.03.2019 26.04.2019 31.05.2019 28.06.2019 26.07.2019 30.08.2019 27.09.2019 25.10.2019 29.11.2019 27.12.2019
EasyLang
func leap year .
return if year mod 4 = 0 and (year mod 100 <> 0 or year mod 400 = 0)
.
func weekday year month day .
normdoom[] = [ 3 7 7 4 2 6 4 1 5 3 7 5 ]
c = year div 100
r = year mod 100
s = r div 12
t = r mod 12
c_anchor = (5 * (c mod 4) + 2) mod 7
doom = (s + t + (t div 4) + c_anchor) mod 7
anchor = normdoom[month]
if leap year = 1 and month <= 2
anchor = (anchor + 1) mod1 7
.
return (doom + day - anchor + 7) mod 7 + 1
.
mdays[] = [ 31 28 31 30 31 30 31 31 30 31 30 31 ]
proc last_fridays year . .
for m to 12
d = mdays[m]
if m = 2 and leap year = 1
d = 29
.
d -= (weekday year m d - 6) mod 7
m$ = m
if m < 10
m$ = "0" & m
.
print year & "-" & m$ & "-" & d
.
.
last_fridays 2023
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)
- 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
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
}
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
Emacs Lisp
(require 'calendar)
(defun last-friday (year)
"Print the last Friday in each month of year"
(mapcar (lambda (month)
(let*
((days (number-sequence 1 (calendar-last-day-of-month month year)))
(mdy (mapcar (lambda (x) (list month x year)) days))
(weekdays (mapcar #'calendar-day-of-week mdy))
(lastfriday (1+ (cl-position 5 weekdays :from-end t))))
(insert (format "%i-%02i-%02i \n" year month lastfriday))))
(number-sequence 1 12)))
(last-friday 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
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].
- 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
Factor
The last-friday-of-month
word in the calendar
vocabulary does most of the work. This program expects the year as a command line argument.
USING: calendar calendar.format command-line io kernel math.parser sequences ;
IN: rosetta-code.last-fridays
(command-line) second string>number <year> 12 <iota>
[ months time+ last-friday-of-month ] with map
[ timestamp>ymd print ] each
- Output:
>factor last-fridays.factor 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.
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
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 leapyear 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
- 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? 2017 Last Friday of the month for 2017 27 January 24 February 31 March 28 April 26 May 30 June 28 July 25 August 29 September 27 October 24 November 29 December
Frink
d = parseDate[ARGS@0]
for m = 1 to 12
{
d = beginningOfNextMonth[d]
n = d - (((parseInt[d -> ### u ###] + 1) mod 7) + 1) days
println[n -> ### yyyy-MM-dd ###]
}
- 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
Fōrmulæ
Fōrmulæ programs are not textual, visualization/edition of programs is done showing/manipulating structures but not text. Moreover, there can be multiple visual representations of the same program. Even though it is possible to have textual representation —i.e. XML, JSON— they are intended for storage and transfer purposes more than visualization and edition.
Programs in Fōrmulæ are created/edited online in its website.
In this page you can see and run the program(s) related to this task and their results. You can also change either the programs or the parameters they are called with, for experimentation, but remember that these programs were created with the main purpose of showing a clear solution of the task, and they generally lack any kind of validation.
Solution
The following function retrieves the last day of each month of a year, being a given weekday:
Test case
Gambas
Public Sub Form_Open()
Dim siYear As Short = InputBox("Please input a year", "Last Friday of each month")
Dim siMonth, siDay As Short
Dim dDay As Date
For siMonth = 1 To 12
For siDay = 31 DownTo 22
Try dDay = Date(siYear, siMonth, siDay)
If Error Then Continue
If WeekDay(dDay) = 5 Then
Print Format(dDay, "yyyy-mm-dd");;
Print Space(6) & Format(dDay, "dddd dd mmmm yyyy")
Break
End If
Next
Next
Me.Close
End
Output:
1925-01-30 Friday 30 January 1925 1925-02-27 Friday 27 February 1925 1925-03-27 Friday 27 March 1925 1925-04-24 Friday 24 April 1925 1925-05-29 Friday 29 May 1925 1925-06-26 Friday 26 June 1925 1925-07-31 Friday 31 July 1925 1925-08-28 Friday 28 August 1925 1925-09-25 Friday 25 September 1925 1925-10-30 Friday 30 October 1925 1925-11-27 Friday 27 November 1925 1925-12-25 Friday 25 December 1925
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"))
}
}
- 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:
def ymd = { it.format('yyyy-MM-dd') }
def lastFridays = lastWeekDays.curry(Day.Fri)
lastFridays(args[0] as int).each { println (ymd(it)) }
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
import Data.Time.Calendar
(Day, addDays, showGregorian, fromGregorian, gregorianMonthLength)
import Data.Time.Calendar.WeekDate (toWeekDate)
import Data.List (transpose, intercalate)
-- [1 .. 7] for [Mon .. Sun]
findWeekDay :: Int -> Day -> Day
findWeekDay dayOfWeek date =
head
(filter
(\x ->
let (_, _, day) = toWeekDate x
in day == dayOfWeek)
((`addDays` date) <$> [-6 .. 0]))
weekDayDates :: Int -> Integer -> [String]
weekDayDates dayOfWeek year =
((showGregorian . findWeekDay dayOfWeek) .
(fromGregorian year <*> gregorianMonthLength year)) <$>
[1 .. 12]
main :: IO ()
main =
mapM_
putStrLn
(intercalate " " <$> transpose (weekDayDates 5 <$> [2012 .. 2017]))
- Output:
2012-01-27 2013-01-25 2014-01-31 2015-01-30 2016-01-29 2017-01-27 2012-02-24 2013-02-22 2014-02-28 2015-02-27 2016-02-26 2017-02-24 2012-03-30 2013-03-29 2014-03-28 2015-03-27 2016-03-25 2017-03-31 2012-04-27 2013-04-26 2014-04-25 2015-04-24 2016-04-29 2017-04-28 2012-05-25 2013-05-31 2014-05-30 2015-05-29 2016-05-27 2017-05-26 2012-06-29 2013-06-28 2014-06-27 2015-06-26 2016-06-24 2017-06-30 2012-07-27 2013-07-26 2014-07-25 2015-07-31 2016-07-29 2017-07-28 2012-08-31 2013-08-30 2014-08-29 2015-08-28 2016-08-26 2017-08-25 2012-09-28 2013-09-27 2014-09-26 2015-09-25 2016-09-30 2017-09-29 2012-10-26 2013-10-25 2014-10-31 2015-10-30 2016-10-28 2017-10-27 2012-11-30 2013-11-29 2014-11-28 2015-11-27 2016-11-25 2017-11-24 2012-12-28 2013-12-27 2014-12-26 2015-12-25 2016-12-30 2017-12-29
Icon and Unicon
This will write the last fridays for every year given as an argument. There is no error checking on the year.
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
require 'dates'
last_fridays=: 12 {. [: ({:/.~ }:"1)@(#~ 5 = weekday)@todate (i.366) + todayno@,&1 1
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:
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
Java
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);
}
}
}
}
- 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
ES5
Iteration
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);
})();
- Output:
>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
Functional composition
(function () {
'use strict';
// lastFridaysOfYear :: Int -> [Date]
function lastFridaysOfYear(y) {
return lastWeekDaysOfYear(y, days.friday);
}
// lastWeekDaysOfYear :: Int -> 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, d - (
(dte.getDay() + (7 - iWeekDay)) % 7
)
));
});
}
// isoDateString :: Date -> String
function isoDateString(dte) {
return dte.toISOString()
.substr(0, 10);
}
// range :: Int -> Int -> [Int]
function range(m, n) {
return Array.apply(null, Array(n - m + 1))
.map(function (x, i) {
return m + i;
});
}
// transpose :: [[a]] -> [[a]]
function transpose(lst) {
return lst[0].map(function (_, iCol) {
return lst.map(function (row) {
return row[iCol];
});
});
}
var days = {
sunday: 0,
monday: 1,
tuesday: 2,
wednesday: 3,
thursday: 4,
friday: 5,
saturday: 6
}
// TEST
return transpose(
range(2012, 2016)
.map(lastFridaysOfYear)
)
.map(function (row) {
return row
.map(isoDateString)
.join('\t');
})
.join('\n');
})();
- 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
ES6
(() => {
"use strict";
// ------------ LAST FRIDAY OF EACH MONTH ------------
// lastWeekDaysOfYear :: Int -> Int -> [Date]
const lastWeekDaysOfYear = iWeekDay =>
y => {
const isLeap = n => (
(0 === n % 4) && (0 !== n % 100)) || (
0 === y % 400
);
return [
31, isLeap(y) ? 29 : 28,
31, 30, 31, 30, 31, 31, 30, 31, 30, 31
]
.map((d, m) =>
new Date(Date.UTC(
y, m, d - ((
new Date(Date.UTC(
y, m, d
))
.getDay() + (7 - iWeekDay)
) % 7)
))
);
};
const days = {
sunday: 0,
monday: 1,
tuesday: 2,
wednesday: 3,
thursday: 4,
friday: 5,
saturday: 6
};
// ---------------------- TEST -----------------------
const main = () =>
transpose(
enumFromTo(2015)(2019)
.map(lastWeekDaysOfYear(days.friday))
)
.map(
row => row.map(isoDateString).join("\t")
)
.join("\n");
// ---------------- GENERIC FUNCTIONS ----------------
// enumFromTo :: Int -> Int -> [Int]
const enumFromTo = m =>
n => Array.from({
length: 1 + n - m
}, (_, i) => m + i);
// isoDateString :: Date -> String
const isoDateString = dte =>
dte.toISOString()
.substr(0, 10);
// transpose :: [[a]] -> [[a]]
const transpose = rows =>
// The columns of the input transposed
// into new rows.
0 < rows.length ? rows[0].map(
(x, i) => rows.flatMap(
v => v[i]
)
) : [];
// MAIN ---
return main();
})();
- Output:
2015-01-30 2016-01-29 2017-01-27 2018-01-26 2019-01-25 2015-02-27 2016-02-26 2017-02-24 2018-02-23 2019-02-22 2015-03-27 2016-03-25 2017-03-31 2018-03-30 2019-03-29 2015-04-24 2016-04-29 2017-04-28 2018-04-27 2019-04-26 2015-05-29 2016-05-27 2017-05-26 2018-05-25 2019-05-31 2015-06-26 2016-06-24 2017-06-30 2018-06-29 2019-06-28 2015-07-31 2016-07-29 2017-07-28 2018-07-27 2019-07-26 2015-08-28 2016-08-26 2017-08-25 2018-08-31 2019-08-30 2015-09-25 2016-09-30 2017-09-29 2018-09-28 2019-09-27 2015-10-30 2016-10-28 2017-10-27 2018-10-26 2019-10-25 2015-11-27 2016-11-25 2017-11-24 2018-11-30 2019-11-29 2015-12-25 2016-12-30 2017-12-29 2018-12-28 2019-12-27
jq
Foundations
# 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 ;
findLastFridays
# 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
- Output:
$ 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
Julia
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
- 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>
K
/ List the dates of last Fridays of each month of
/ a given year
/ lastfridt.k
isleap: {(+/~x!' 4 100 400)!2}
wd: {(_jd x)!7}
dom: (31;28;31;30;31;30;31;31;30;31;30;31)
init: {:[isleap x;dom[1]::29;dom[1]::28]}
wdme: {[m;y]; init y; dt:(10000*y)+(100*m)+dom[m-1];jd::(_jd dt);mewd::(wd dt)}
lfd: {[m;y]; wdme[m;y];:[mewd>3;jd::jd+(4-mewd);jd::jd-(3+mewd)];dt:_dj(jd);yy:$(yr:dt%10000);dd:$(d:dt!100);mm:$(mo:((dt-yr*10000)%100));arr::arr,$(yy,"-",(2$mm),"-",(2$dd))}
lfd1: {[y];arr::(); m:1; do[12;lfd[m;y];m+:1]}
main: {[y]; lfd1[y];`0: ,"Dates of last Fridays of ",($y);12 10#arr}
The output of a session is given below:
- Output:
K Console - Enter \ for help \l lastfridt main 2012 Dates of last Fridays of 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")
Kotlin
// version 1.0.6
import java.util.*
fun main(args: Array<String>) {
print("Enter a year : ")
val year = readLine()!!.toInt()
println("The last Fridays of each month in $year are as follows:")
val calendar = GregorianCalendar(year, 0, 31)
for (month in 1..12) {
val daysInMonth = calendar.getActualMaximum(Calendar.DAY_OF_MONTH)
var offset = calendar[Calendar.DAY_OF_WEEK] - Calendar.FRIDAY
if (offset < 0) offset += 7
val lastFriday = daysInMonth - offset
println("$year-" + "%02d-".format(month) + "%02d".format(lastFriday))
if (month < 12) {
calendar.add(Calendar.DAY_OF_MONTH, 1)
calendar.add(Calendar.MONTH, 1)
calendar.add(Calendar.DAY_OF_MONTH, -1)
}
}
}
- Output:
Enter a year : 2012 The last Fridays of each month in 2012 are as follows: 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
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'
^}
- 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
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
Example
put lastFriday("2012")
Output
1 27
2 24
3 30
4 27
5 25
6 29
7 27
8 31
9 28
10 26
11 30
12 28
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
- 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
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]))
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 >
M2000 Interpreter
module lastfriday {
string year
integer y%
input "Year (e.g. 2023):", y%
year=str$(y%,"")
date a="1/1/"+year
date a1="31/12/"+year
double i, b=a, c=a1
for i=b to b+6
if val(date$(i, 1033, "d"))=6 then exit for
next
document result$="Last Friday per month for year " + year + {:
}
for i=i+7 to c step 7
if val(date$(i, 1033, "M")) <>val(date$(i+7, 1033, "M")) then
result$=date$(i, 1033, "M"+chr$(9)+"dd") + {
}
end if
next
report result$
clipboard result$
}
lastfriday
- Output:
Year (e.g. 2023):2023 Last Friday per month for year 2023: 1 27 2 24 3 31 4 28 5 26 6 30 7 28 8 25 9 29 10 27 11 24 12 29
Maple
fridays := proc(year)
local i, dt, change, last_days;
last_days := [31,28,31,30,31,30,31,31,30,31,30,31];
if (Calendar:-IsLeapYear(year)) then
last_days[2] := 28;
end if;
for i to 12 do
dt := Date(year, i, last_days[i]);
change := 0;
if not(Calendar:-DayOfWeek(dt) = 6) then
change := -(Calendar:-DayOfWeek(dt) mod 7)-1;
end if;
dt := Calendar:-AdjustDateField(dt, "date", change);
printf("%d-%d-%d\n", year, Month(dt), DayOfMonth(dt));
end do;
end proc;
fridays(2012);
- 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
Mathematica/Wolfram Language
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]
- 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
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')
- 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
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"]
Nanoquery
import Nanoquery.Util
// a function to check if a year is a leap year
def isLeapYear(year)
if (year % 100 = 0)
return (year % 400 = 0)
else
return (year % 4 = 0)
end
end
// a function to format 1-digit numbers as "0x"
def form(num)
if (num > 9)
return str(num)
else
return "0" + str(num)
end
end
// get a year from the console
print "enter year: "
year = int(input())
// build a list of the expected amount of days for each month
days = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
if isLeapYear($year)
days[1] = 29
end
// loop through each month
for month in range(1, len($days))
// loop through each day of the month
friday = null
for day in range(1, days[month - 1])
// create a date object for this date
date = new(Date)
date.setYear(year).setMonth(month).setDay(day)
// check if it's a friday
if (date.getDayOfWeek() = "Friday")
// if it is, keep it
friday = new(Date, date)
end
end for
// display the last friday found
print friday.getYear() + "-"
print form(friday.getMonth()) + "-"
println form(friday.getDay())
end
NetRexx
Implements the algorithms from both the Java and C implementations.
/* 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
- 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
import os, strutils, times
const
DaysInMonth: array[Month, int] = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
DayDiffs: array[WeekDay, int] = [3, 4, 5, 6, 0, 1, 2]
let year = paramStr(1).parseInt
for month in mJan..mDec:
var lastDay = DaysInMonth[month]
if month == mFeb and year.isLeapYear: lastDay = 29
var date = initDateTime(lastDay, month, year, 0, 0, 0)
date = date - days(DayDiffs[date.weekday])
echo date.format("yyyy-MM-dd")
- Output:
Sample usage: ./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
OCaml
Using the module Unix from the standard OCaml library:
#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
- 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
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)
Run this script with the command:
ocaml unix.cma str.cma -I +calendar calendarLib.cma last_fridays.ml 2012
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
] ;
- 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
\\ 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)))
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]
Pascal
Using Free Pascal's DateUtils library would dramatically simplify the coding (see the Delphi example) but for older Pascal implementations the needed routines are the programmer's responsibility.
program LastFriday;
{$mode objfpc}{$H+}
uses
SysUtils;
type
weekdays = (Sun,Mon,Tue,Wed,Thu,Fri,Sat);
var
m, d, y : integer;
function IsLeapYear(Year : integer) : boolean;
begin
if Year mod 4 <> 0 { quick exit in most likely case }
then IsLeapYear := false
else if Year mod 400 = 0
then IsLeapYear := true
else if Year mod 100 = 0
then IsLeapYear := false
else { non-century year and divisible by 4 }
IsLeapYear := true;
end;
function DaysInMonth(Month, Year : integer) : integer;
const
LastDay : array[1..12] of integer =
(31,28,31,30,31,30,31,31,30,31,30,31);
begin
if (Month = 2) and (IsLeapYear(Year)) then
DaysInMonth := 29
else
DaysInMonth := LastDay[Month];
end;
{ return day of week (Sun = 0, Mon = 1, etc.) for a }
{ given mo, da, and yr using Zeller's congruence }
function DayOfWeek(mo, da, yr : integer) : weekdays;
var
y, c, z : integer;
begin
if mo < 3 then
begin
mo := mo + 10;
yr := yr - 1
end
else mo := mo - 2;
y := yr mod 100;
c := yr div 100;
z := (26 * mo - 2) div 10;
z := z + da + y + (y div 4) + (c div 4) - 2 * c + 777;
DayOfWeek := weekdays(z mod 7);
end;
{ return the calendar day of the last occurrence of the }
{ specified weekday in the given month and year }
function LastWeekday(k : weekdays; m, y : integer) : integer;
var
d : integer;
w : weekdays;
begin
{ determine weekday for the last day of the month }
d := DaysInMonth(m, y);
w := DayOfWeek(m, d, y);
{ back up as needed to desired weekday }
if w >= k then
LastWeekday := d - (ord(w) - ord(k))
else
LastWeekday := d - (7 - ord(k)) - ord(w);
end;
begin { main program }
write('Find last Fridays in what year? ');
readln(y);
writeln;
writeln('Month Last Fri');
for m := 1 to 12 do
begin
d := LastWeekday(Fri, m, y);
writeln(m:5,' ',d:5);
end;
end.
- Output:
Find last Fridays in what year? 2020 Month Last Fri 1 31 2 28 3 27 4 24 5 29 6 26 7 31 8 28 9 25 10 30 11 27 12 25
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 ;
}
- 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
Phix
with javascript_semantics procedure last_day_of_month(integer y, dow) for m=1 to 12 do integer d = days_in_month(y,m), a = dow-day_of_week(y,m,d) printf(1,"%4d-%02d-%02d\n",{y,m,d+a-7*(a>0)}) end for end procedure constant FRIDAY=5 --prompt_number() is not compatible with pwa/p2js --last_day_of_month(prompt_number("Year:",{1752,9999}),FRIDAY) last_day_of_month(2012,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
PHP
PHP is generally used for web apps, so I am not implementing the command-line component of this task.
<?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), "<br>";
}
}
date_default_timezone_set("GMT");
$year = 2012;
print_last_fridays_of_month($year);
?>
- 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
Picat
% for command line argument
main(ARGV) =>
if ARGV.length > 0 then
Year = ARGV[1].to_integer(),
show_year(Year),
nl
end.
% Without command line argument
main => go.
go =>
show_year(2022),
nl.
% Show the months
show_year(Year) =>
foreach(Date in get_months(Year))
println(format_date(Date))
end,
nl.
% Format date to YYYY-DD-MM
format_date(Date) = to_fstring("%4d-%02d-%02d",Date[1],Date[2],Date[3]).
% Return the last Fridays of each month for year Year
get_months(Year) =
[ [ [Year,Month,Day] : Day in 1..max_days_in_month(Year,Month),
dow(Year, Month, Day) == 5].last() : Month in 1..12].
% Day of week, Sakamoto's method
dow(Y, M, D) = R =>
T = [0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4],
if M < 3 then
Y := Y - 1
end,
R = (Y + Y // 4 - Y // 100 + Y // 400 + T[M] + D) mod 7.
% Maximum days in month
max_days_in_month(Year,Month) = Days =>
if member(Month, [1,3,5,7,8,10,12]) then
Days = 31
elseif member(Month,[4,6,9,11]) then
Days = 30
else
if leap_year(Year) then
Days = 29
else
Days = 28
end
end.
% Is Year a leap year?
leap_year(Year) =>
(Year mod 4 == 0, Year mod 100 != 0)
;
Year mod 400 == 0.
Running the program
There are several ways to run this program; let's call it "last_friday_of_each_month.pi":
From Picat's shell
$ picat Picat> cl(last_friday_of_each_month) Picat> show_year(2022) 2022-01-28 2022-02-25 2022-03-25 2022-04-29 2022-05-27 2022-06-24 2022-07-29 2022-08-26 2022-09-30 2022-10-28 2022-11-25 2022-12-30
From the command line, year as parameter
Via main(ARGV)
.
$ picat last_friday_of_each_month.pi 2022
From the command line, as a goal
$ picat -g "show_year(2022)" last_friday_of_each_month.pi
Run the default goal (go/0))
$ picat last_friday_of_each_month.pi
PicoLisp
(de lastFridays (Y)
(for M 12
(prinl
(dat$
(find '((D) (= "Friday" (day D)))
(mapcar '((D) (date Y M D)) `(range 31 22)) )
"-" ) ) ) )
Test:
: (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
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;
}
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;
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
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"
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
Alternate Version
This script finds the first and/or last or all dates of any of the days of week; accepts [Int32]
and [DateTime]
values for Month and Year parameters; outputs [DateTime]
objects by default but has an option to output time strings in various formats. This script also allows for pipeline input based mainly upon the Month parameter.
This script has a syntax as complex as any PowerShell Cmdlet because it attempts to do everything.
function Get-Date0fDayOfWeek
{
[CmdletBinding(DefaultParameterSetName="None")]
[OutputType([datetime])]
Param
(
[Parameter(Mandatory=$false,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true,
Position=0)]
[ValidateRange(1,12)]
[int]
$Month = (Get-Date).Month,
[Parameter(Mandatory=$false,
ValueFromPipelineByPropertyName=$true,
Position=1)]
[ValidateRange(1,9999)]
[int]
$Year = (Get-Date).Year,
[Parameter(Mandatory=$true, ParameterSetName="Sunday")]
[switch]
$Sunday,
[Parameter(Mandatory=$true, ParameterSetName="Monday")]
[switch]
$Monday,
[Parameter(Mandatory=$true, ParameterSetName="Tuesday")]
[switch]
$Tuesday,
[Parameter(Mandatory=$true, ParameterSetName="Wednesday")]
[switch]
$Wednesday,
[Parameter(Mandatory=$true, ParameterSetName="Thursday")]
[switch]
$Thursday,
[Parameter(Mandatory=$true, ParameterSetName="Friday")]
[switch]
$Friday,
[Parameter(Mandatory=$true, ParameterSetName="Saturday")]
[switch]
$Saturday,
[switch]
$First,
[switch]
$Last,
[switch]
$AsString,
[Parameter(Mandatory=$false)]
[ValidateNotNullOrEmpty()]
[string]
$Format = "dd-MMM-yyyy"
)
Process
{
[datetime[]]$dates = 1..[DateTime]::DaysInMonth($Year,$Month) | ForEach-Object {
Get-Date -Year $Year -Month $Month -Day $_ -Hour 0 -Minute 0 -Second 0 |
Where-Object -Property DayOfWeek -Match $PSCmdlet.ParameterSetName
}
if ($First -or $Last)
{
if ($AsString)
{
if ($First) {$dates[0].ToString($Format)}
if ($Last) {$dates[-1].ToString($Format)}
}
else
{
if ($First) {$dates[0]}
if ($Last) {$dates[-1]}
}
}
else
{
if ($AsString)
{
$dates | ForEach-Object {$_.ToString($Format)}
}
else
{
$dates
}
}
}
}
The default is to return [DateTime]
objects:
1..12 | Get-Date0fDayOfWeek -Year 2012 -Last -Friday
- Output:
Friday, January 27, 2012 12:00:00 AM Friday, February 24, 2012 12:00:00 AM Friday, March 30, 2012 12:00:00 AM Friday, April 27, 2012 12:00:00 AM Friday, May 25, 2012 12:00:00 AM Friday, June 29, 2012 12:00:00 AM Friday, July 27, 2012 12:00:00 AM Friday, August 31, 2012 12:00:00 AM Friday, September 28, 2012 12:00:00 AM Friday, October 26, 2012 12:00:00 AM Friday, November 30, 2012 12:00:00 AM Friday, December 28, 2012 12:00:00 AM
Return the [DateTime]
objects as strings (using the default string format):
1..12 | Get-Date0fDayOfWeek -Year 2012 -Last -Friday -AsString
- Output:
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
Return the [DateTime]
objects as strings (specifying the string format):
1..12 | Get-Date0fDayOfWeek -Year 2012 -Last -Friday -AsString -Format yyyy-MM-dd
- 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
PureBasic
Procedure LastFridayOfEachMonth(yyyy.i,List lfem.i())
Define dv.i=ParseDate("%yyyy",Str(yyyy)), mv.i=1
NewList d.i()
For d=1 To 365
dv=AddDate(dv,#PB_Date_Day,1)
If DayOfWeek(dv)=5
AddElement(d()) : d()=dv
EndIf
Next
dv=0
For mv=1 To 12
ForEach d()
If dv<d() And Month(d())=mv
dv=d()
EndIf
Next
AddElement(lfem()) : lfem()=dv
Next
EndProcedure
NewList lf.i()
Define y.i
OpenConsole("Last Friday of each month")
Print("Input Year [ 1971 < y < 2038 ]: ")
y=Val(Input())
If y>1971 And y<2038
PrintN("Last Friday of each month...")
LastFridayOfEachMonth(y,lf())
ForEach lf()
PrintN(FormatDate("%dd.%mm.%yyyy",lf()))
Next
EndIf
Print("...End")
Input()
- Output:
Input Year [ 1971 < y < 2038 ]: 2017 Last Friday of each month... 27.01.2017 24.02.2017 31.03.2017 28.04.2017 26.05.2017 30.06.2017 28.07.2017 25.08.2017 29.09.2017 27.10.2017 24.11.2017 29.12.2017 ...End
Python
import calendar
def last_fridays(year):
for month in range(1, 13):
last_friday = max(week[calendar.FRIDAY]
for week in calendar.monthcalendar(year, month))
print('{:4d}-{:02d}-{:02d}'.format(year, month, last_friday))
- 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
Another solution
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
Using reduce
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
using itertools
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
Quackery
[ over 3 < if [ 1 - ]
dup 4 / over +
over 100 / -
swap 400 / +
swap 1 -
[ table
0 3 2 5 0 3
5 1 4 6 2 4 ]
+ + 7 mod ] is dayofweek ( day month year --> weekday )
[ dup 400 mod 0 = iff
[ drop true ] done
dup 100 mod 0 = iff
[ drop false ] done
4 mod 0 = ] is leap ( year --> b )
[ swap 1 -
[ table
31 [ dup leap 28 + ]
31 30 31 30 31 31 30
31 30 31 ]
do nip ] is monthdays ( month year --> n )
[ number$
2 times
[ char - join
over 10 < if
[ char 0 join ]
swap number$ join ]
echo$ ] is echoymd ( day month year --> )
[ dip
[ 2dup monthdays
dup temp put
unrot dayofweek ]
- dup 0 < if [ 7 + ]
temp take swap - ] is lastwkday ( month year wkd --> n )
[ temp put
12 times
[ i^ 1+ over
2dup temp share lastwkday
unrot echoymd cr ]
drop temp release ] is lastwkdays ( year wkd --> )
[ 5 lastwkdays ] is lastfridays ( year --> )
2012 lastfridays
- 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
R
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)]))
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"))))
- 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
Raku
(formerly Perl 6)
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];
}
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:
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");
}
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:
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
}
REBOL
The longer version:
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]
- 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:
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]
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.: TU for Tuesday. 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 4=April 5=May 6=June ... 12=December ║ ║ or the English name of the month, with a minimum length that causes no ambiguity. ║ ║ I.E.: JA for January, AP for April, JUN for June, JUL for July, 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. ║ ║ ║ ║ The method used is: find the "day number" of the 1st of the next month and 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. ║ ╚════════════════════════════════════════════════════════════════════════════════════════════════╝
/*REXX program displays the dates of the last Fridays of each month for any given year.*/
parse arg yyyy /*obtain optional argument from the CL.*/
do j=1 for 12 /*traipse through all the year's months*/
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 /*no month given ? */
if arg()>3 then call .er 'arguments specified', 4 /*too many args ? */
do j=1 for 3 /*any plural args ?*/
if words( arg(j) ) > 1 then call .er 'is illegal:', j /*check if plural. */
end
/*find DOW in list.*/
dw= pos(' 'dow, $) /*find day-of-week*/
if dw==0 then call .er 'is invalid:' , 1 /*no DOW was found?*/
if dw\==lastpos(' 'dow,$) then call .er 'is ambiguous:', 1 /*check min length.*/
if datatype(mm, 'M') then do /*is MM alphabetic?*/
m= pos(' 'mm, !) /*maybe its good...*/
if m==0 then call .er 'is invalid:' , 1
if m\==lastpos(' 'mm,!) then call .er 'is ambiguous:', 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 /*MM (mon) ¬integer*/
if \datatype(yy, 'W') then call .er "isn't an integer:", 3 /*YY (yr) ¬integer*/
if mm<1 | mm>12 then call .er "isn't in range 1──►12:", 2 /*MM out─of─range. */
if yy=0 then call .er "can't be 0 (zero):", 3 /*YY can't be zero.*/
if yy<0 then call .er "can't be negative:", 3 /* " " " neg. */
if yy>9999 then call .er "can't be > 9999:", 3 /* " " " huge.*/
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._ /*plug in a choice.*/
say; exit 13 /*··· then exit. */
- output when using the following input of: 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
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
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
RPL
With the release of the HP-48, RPL gained some basic functions for calculating the date, but nothing for directly obtaining the day of the week.
≪ { "MON" TUE" "WED" "THU" "FRI" "SAT" "SUN" } SWAP 0 TSTR 1 3 SUB POS ≫ 'WKDAY' STO @ ( dd.mmyyyy → 1..7 ) ≪ → year ≪ { } .02 .13 FOR month 1 month .13 == DUP .01 month IFTE SWAP year + 1000000 / + + DUP WKDAY 1 + 7 MOD 1 + NEG DATE+ 2 TRNC + 0.01 STEP 2 FIX ≫ ≫ 'TGIF' STO
2012 TGIF
- Output:
1: {27.01 24.02 30.03 27.04 25.05 29.06 27.07 31.08 28.09 26.10 30.11 28.12 }
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)}
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.
require 'date'
def last_friday(year, month)
d = Date.new(year, month, -1)
d = d.prev_day until d.friday?
d
end
Run BASIC
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
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
Rust
use std::env::args;
use time::{Date, Duration};
fn main() {
let year = args().nth(1).unwrap().parse::<i32>().unwrap();
(1..=12)
.map(|month| Date::try_from_ymd(year + month / 12, ((month % 12) + 1) as u8, 1))
.filter_map(|date| date.ok())
.for_each(|date| {
let days_back =
Duration::days(((date.weekday().number_from_sunday() as i64) % 7) + 1);
println!("{}", date - days_back);
});
}
- 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
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))
}
}
}
- 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]].
$ 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;
- 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
SenseTalk
ask "What year?"
put it into year
put !"The last Fridays of each month in [[year]] are:"
set lastDayOfMonth to year & "-01-31" -- start with January 31 of the year
repeat 12 times
set lastFriday to lastDayOfMonth
repeat until weekdayName of lastFriday is "Friday"
subtract a day from lastFriday -- work back to Friday
end repeat
put the monthName of lastFriday && ordinalWords of the day of lastFriday
add a month to lastDayOfMonth -- advance to last day of next month
end repeat
- Output:
The last Fridays of each month in 2008 are: January twenty-fifth February twenty-ninth March twenty-eighth April twenty-fifth May thirtieth June twenty-seventh July twenty-fifth August twenty-ninth September twenty-sixth October thirty-first November twenty-eighth December twenty-sixth
Sidef
require('DateTime')
var (year=2016) = ARGV.map{.to_i}...
for month (1..12) {
var dt = %O<DateTime>.last_day_of_month(year => year, month => month)
while (dt.day_of_week != 5) {
dt.subtract(days => 1)
}
say dt.ymd
}
- 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
Smalltalk
Pharo Smalltalk
[ :yr | | firstDay firstFriday |
firstDay := Date year: yr month: 1 day: 1.
firstFriday := firstDay addDays: (6 - firstDay dayOfWeek).
(0 to: 53)
collect: [ :each | firstFriday addDays: (each * 7) ]
thenSelect: [ :each |
(((Date daysInMonth: each monthIndex forYear: yr) - each dayOfMonth) <= 6) and: [ each year = yr ] ] ]
- Output:
Send value: 2012 to the above block to return an array: (27 January 2012 24 February 2012 30 March 2012 27 April 2012 25 May 2012 29 June 2012 27 July 2012 31 August 2012 28 September 2012 26 October 2012 30 November 2012 28 December 2012)
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;
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.
Stata
program last_fridays
args year
clear
qui set obs 12
gen day=dofm(mofd(mdy(_n,1,`year'))+1)-1
qui replace day=day-mod(dow(day)-5,7)
format %td day
list, noobs noheader sep(6)
end
last_fridays 2012
+-----------+
| 27jan2012 |
| 24feb2012 |
| 30mar2012 |
| 27apr2012 |
| 25may2012 |
| 29jun2012 |
|-----------|
| 27jul2012 |
| 31aug2012 |
| 28sep2012 |
| 26oct2012 |
| 30nov2012 |
| 28dec2012 |
+-----------+
Swift
import Foundation
func lastFridays(of year: Int) -> [Date] {
let calendar = Calendar.current
var dates = [Date]()
for month in 2...13 {
let lastDayOfMonth = DateComponents(calendar: calendar,
year: year,
month: month,
day: 0,
hour: 12)
let date = calendar.date(from: lastDayOfMonth)!
let isFriday = calendar.component(.weekday, from: date) == 6
if isFriday {
dates.append(calendar.date(from: lastDayOfMonth)!)
} else {
let lastWeekofMonth = calendar.ordinality(of: .weekOfMonth,
in: .month,
for: date)!
let lastWithFriday = lastWeekofMonth - (calendar.component(.weekday, from: date) > 6 ? 0 : 1)
let lastFridayOfMonth = DateComponents(calendar: calendar,
year: year,
month: month - 1,
hour: 12,
weekday: 6,
weekOfMonth: lastWithFriday)
dates.append(calendar.date(from: lastFridayOfMonth)!)
}
}
return dates
}
var dateFormatter = DateFormatter()
dateFormatter.dateStyle = .short
print(lastFridays(of: 2013).map(dateFormatter.string).joined(separator: "\n"))
1/27/12 2/24/12 3/30/12 4/27/12 5/25/12 6/29/12 7/27/12 8/31/12 9/28/12 10/26/12 11/30/12 12/28/12
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]
}
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
$$ 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
- 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).
#!/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
For systems without ncal:
#!/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
Using date --date
from GNU date??? This code is not portable.
#!/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}
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
*!* 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
V (Vlang)
import time
import os
fn main() {
mut year := 0
mut t := time.now()
year = os.input("Please select a year: ").int()
println("Last Fridays of each month of $year")
println("==================================")
for i in 1..13 {
mut j := time.month_days[i-1]
if i == 2 {
if time.is_leap_year(year) {j = 29}
}
for {
t = time.parse('$year-${i:02}-$j 12:30:00')!
if t.weekday_str() == 'Fri' {
println("${time.long_months[i-1]}: $j")
break
}
j--
}
}
}
- Output:
Please select a year: 2012 Last Fridays of each month of 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
Wren
import "os" for Process
import "./date" for Date
var args = Process.arguments
if (args.count != 1) {
Fiber.abort("Please pass just the year to be processed.")
}
var year = Num.fromString(args[0])
System.print("The dates of the last Fridays in the month for %(year) are:")
Date.default = Date.isoDate
for (m in 1..12) {
var d = Date.monthLength(year, m)
var dt = Date.new(year, m, d)
var wd = dt.dayOfWeek
if (wd == 5) {
System.print(dt)
} else if (wd > 5) {
System.print(dt.addDays(-wd + 5))
} else {
System.print(dt.addDays(-wd - 2))
}
}
- Output:
$ wren last_friday.wren 2012 The dates of the last Fridays in the month for 2012 are: 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 $ wren last_friday.wren 2020 The dates of the last Fridays in the month for 2020 are: 2020-01-31 2020-02-28 2020-03-27 2020-04-24 2020-05-29 2020-06-26 2020-07-31 2020-08-28 2020-09-25 2020-10-30 2020-11-27 2020-12-25
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);
];
]
- 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
var [const] D=Time.Date;
fcn lastDay(y,d){
[1..12].pump(List,'wrap(m){ // 12 months, closure for y & d
[D.daysInMonth(y,m)..1,-1].pump(Void,'wrap(_d){ // work backwards
D.weekDay(y,m,_d) :
if (_==d) return(Void.Stop,D.toYMDString(y,m,_d))
})
})
}
lastDay(2012,D.Friday).concat("\n").println();
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
- 360 Assembly
- Action!
- Ada
- ALGOL 68
- ALGOL W
- AppleScript
- Arturo
- AutoHotkey
- AutoIt
- AWK
- BBC BASIC
- Befunge
- C
- C sharp
- C++
- Boost
- Clojure
- Clj-time
- COBOL
- CoffeeScript
- Common Lisp
- D
- Delphi
- EasyLang
- Elixir
- Elm
- Emacs Lisp
- Erlang
- Factor
- Fortran
- FreeBASIC
- Frink
- Fōrmulæ
- Gambas
- Go
- Groovy
- Haskell
- Icon
- Unicon
- Icon Programming Library
- J
- Java
- JavaScript
- Jq
- Julia
- K
- Kotlin
- Lasso
- LiveCode
- Logo
- Lua
- M2000 Interpreter
- Maple
- Mathematica
- Wolfram Language
- MATLAB
- Octave
- Maxima
- Nanoquery
- NetRexx
- Nim
- OCaml
- OCaml Calendar Library
- Oforth
- PARI/GP
- Pascal
- Perl
- Phix
- PHP
- Picat
- PicoLisp
- Pike
- PL/I
- PowerShell
- PureBasic
- Python
- Quackery
- R
- Racket
- Raku
- REBOL
- REXX
- Ring
- RPL
- Ruby
- Run BASIC
- Rust
- Scala
- Seed7
- SenseTalk
- Sidef
- Smalltalk
- SQL
- Stata
- Swift
- Tcl
- TUSCRIPT
- UNIX Shell
- Visual FoxPro
- V (Vlang)
- Wren
- Wren-date
- XPL0
- Zkl