# Find all the last weekends in a year

In order to obtain the weekends of a year you'd use something like this:

With[{first = Take[DateList[], 2]},
DayRange[first, DatePlus[first, {{1, "Year"}, {-1, "Day"}}], "Weekend"]]


What I try to find out is how to either formulate this query in order to extract all the dates which are the last weekends of each month or through post-processing of the result.

One problem that occurs is that there are months with four weekends and some with five. Another issue is the case of August where the last weekend is reaching into September.

Formulation of a possible algorithm (post-processing)

1. Partition the list into sublists of size two and group every month
2. If the length of month is 1 = length mod 4, extend this sublist with the first element of the next month
3. Group all the last elements of the sublists

I'd know exactly how to do that in C/C++ but alas still lack enough Mathematica skills. Any help is welcome.

-

I don't think it is possible to get this output directly from DayRange, but post-processing is pretty simple (and efficient, since there are only 52 weeks in a year):

• Get the list of all weekends for the year and gather by the month (second element)
• Take the last two dates in this sublist and:
• if the date difference is 1, keep them (i.e. both Saturday and Sunday of the last weekend are in the same month)
• if the date difference is not 1, take the second date and add 1 day to get the weekends (i.e., Saturday falls on the last day and the Sunday is the first day of the next month).

Here's the code that does this. It should be fairly easy to follow:

getLastWeekends[yr_Integer] := With[
{
Weekends = DayRange[{#}, {# + 1}, "Weekend", "IncludeEndPoints" -> {True, False}] &,
Second = Composition[First, Rest],
LastWE = If[DateDifference @@ # != 1, {Last@#, DayPlus[Last@#, 1]}, #] &
},
Composition[LastWE, #[[-2 ;;]] &] /@ GatherBy[Weekends[yr], Second]
]


Use this as:

getLastWeekends@2013

(* {{{2013, 1, 26}, {2013, 1, 27}}, {{2013, 2, 23}, {2013, 2, 24}},
{{2013, 3, 30}, {2013, 3, 31}}, {{2013, 4, 27}, {2013, 4, 28}},
{{2013, 5, 25}, {2013, 5, 26}}, {{2013, 6, 29}, {2013, 6, 30}},
{{2013, 7, 27}, {2013, 7, 28}}, {{2013, 8, 31}, {2013, 9, 1}},
{{2013, 9, 28}, {2013, 9, 29}}, {{2013, 10, 26}, {2013, 10, 27}},
{{2013, 11, 30}, {2013, 12, 1}}, {{2013, 12, 28}, {2013, 12, 29}}} *)


Using george2079's suggestion to use the last Saturday of the month, the above can be modified as:

getLastWeekends[yr_Integer] := With[
{
Saturdays = DayRange[{#}, {# + 1}, Saturday, "IncludeEndPoints" -> {True, False}] &,
Second = Composition[First, Rest]
},
Composition[{#, # ~DayPlus~ 1} &, Last] /@ GatherBy[Saturdays@yr, Second]
]

-
It might be cleaner to just find last Saturday or last Sunday, depending on how you mean to handle the wrap around weekends. – george2079 Jan 20 '13 at 18:56
@rm Thank you for your illuminating answer. I'm so far away of formulating something like your solution on my own. Makes me sad... ;) – Stefan Jan 20 '13 at 18:58
@george2079 Yes, that would be better (can avoid the comparisons I'm doing right now). I've added it as an edit. – R. M. Jan 20 '13 at 20:08

Make a list of the Saturday(s) of the year :

saturdayList =
With[{first = Take[DateList[], 2]},
DayRange[first, DatePlus[first, {{1, "Year"}, {-1, "Day"}}],Saturday]];


Then gather according to the month, take the last Saturday, and add one day for Sunday :

  {#, DatePlus[#, 1]} & /@ Last /@ GatherBy[saturdayList, #[[2]] &]

-
 wknds1 = With[{first = Take[DateList[], 2]},
DayRange[first, DatePlus[first, {{1, "Year"}, {-1, "Day"}}],  "Weekend"]];
Split[wknds1, #1[[2]] == #2[[2]] &]


(Weekends split between months are highlighted)

Using

If[DayName[#[[-1]]] == Saturday, {#[[-1]]}, #[[-2 ;;]]] & /@
Split[wknds1, #1[[2]] == #2[[2]] &]


or

If[DayName[#] == Saturday, {#}, {#, DatePlus[#, 1]}] & /@ Last /@
Split[wknds1, #1[[2]] == #2[[2]] &]


we get

(* {{{2013, 1, 26}, {2013, 1, 27}}, {{2013, 2, 23}, {2013, 2,  24}},
{{2013, 3, 30}, {2013, 3, 31}}, {{2013, 4, 27}, {2013, 4,  28}},
{{2013, 5, 25}, {2013, 5, 26}}, {{2013, 6, 29}, {2013, 6,  30}},
{{2013, 7, 27}, {2013, 7, 28}},
{{2013, 8, 31}},
{{2013, 9,  28}, {2013, 9, 29}}, {{2013, 10, 26}, {2013, 10, 27}},
{{2013, 11, 30}},
{{2013, 12, 28}, {2013, 12, 29}}}*)

-