I\'d like to be able to start with a year, and calculate occurrences of Friday the 13th. A brute force solution is easy and obvious. I have something slightly better, but
initialize startDate to 13th of the month given in the current year
while (true) {
if (startDate.dayOfWeek == Date.FRIDAY)
break;
else
startDate.year ++;
}
return startDate.year;
Any month that starts with a Sunday has a Friday on the thirteenth. There are only 14 combinations possible knowing what day the first of the year is on (with or without leap year, and sun-sat). You should just calculate it once and get it over with. You'd only check 14*12 possible months to start out with, well with in reason.
resultant table element (from 2009, 2010):
[Thursday,false] => Feb, March, Nov
[Friday,false] => Aug
to fill the table you have a generic month Jan(31),Feb(28).. and then iterate with a seed of each day of the week, noting months that start with sunday, and also with a leap year and without. Pretty straight forward, and once done, you can share it with us :)
Since your brute force algorithm is apparently the intuitive day-by-day iteration option, perhaps you haven't considered the Doomsday Algorithm. It would allow you to simply check if that 13th is a Friday. As far as I know, it is the most efficient solution to the problem.
I use PowerShell 7.1 x64 on Windows 10, I am also interested in this, though my programming skill is not advanced enough to develop an independent and complex algorithm (without built-in) to solve this, currently I can do this:
$start=Read-Host "Input start year"
$end=Read-Host "Input end year"
$years=$start..$end
$blackfriday=@()
foreach ($year in $years) {
$blackfriday+=1..12 | foreach { [datetime]"$year-$_-13" } | where { $_.DayOfWeek -eq 'Friday'} | foreach {$_.tostring("yyyy, MMMM dd, ffffdd")}
}
$blackfriday
Update: Now I have this, by brute forcing year-month-13 to convert date to days, and get the results where days mod 7 equal to 5, I have used all the advanced algorithms found on Wikipedia: https://en.wikipedia.org/wiki/Determination_of_the_day_of_the_week And I found out they don't work well with PowerShell, don't know if it's just me or Wikipedia got it wrong, anyway here is my script, I have fc compared the results of the script with builtin and this script, and it shows"FC: no differences encountered":
$months=@(
[PSCustomObject]@{Month='January';Days=31}
[PSCustomObject]@{Month='February';Days=28}
[PSCustomObject]@{Month='March';Days=31}
[PSCustomObject]@{Month='April';Days=30}
[PSCustomObject]@{Month='May';Days=31}
[PSCustomObject]@{Month='June';Days=30}
[PSCustomObject]@{Month='July';Days=31}
[PSCustomObject]@{Month='August';Days=31}
[PSCustomObject]@{Month='September';Days=30}
[PSCustomObject]@{Month='October';Days=31}
[PSCustomObject]@{Month='November';Days=30}
[PSCustomObject]@{Month='December';Days=31}
)
function BlackFriday {
param(
[Parameter(ValueFromPipeline=$true, Mandatory=$true, Position=0)] [int64] $start,
[Parameter(ValueFromPipeline=$true, Mandatory=$true, Position=1)] [int64] $end
)
$years=$start..$end
$blackfriday=@()
foreach ($year in $years) {
$array=1..12
foreach ($arra in $array) {
$month=0
for ($i=0;$i -lt $arra-1;$i++) {
$month+=$months[$i].Days
}
[int]$ye=$year
if ($arra -le 2) { $ye-=1}
if ($ye % 4 -eq 0) {$leap=$ye/4}
else {while ($ye % 4 -ne 0) {$ye-=1}
$leap=$ye/4}
if ($ye % 100 -eq 0) {$century=$ye/100}
else {while ($ye % 100 -ne 0) {$ye-=4}
$century=$ye/100}
if ($ye % 400 -eq 0) {$cycle=$ye/400}
else {while ($ye % 400 -ne 0) {$ye-=100}
$cycle=$ye/400}
$leap=$leap-$century+$cycle
$date=[int64](($year-1)*365+$month+13+$leap)
if ($date % 7 -eq 5) {
$name=$months[$arra-1].Month
$blackfriday+=[string]"$year, $name 13, Friday"
}
}
}
$blackfriday
}
$start=Read-Host "Input start year"
$end=Read-Host "Input end year"
BlackFriday $start $end
One thing I noticed is that the first of the month falls on a Sunday during months with a Friday the 13th. You can probably leverage this to make it easier to calculate.
This is how I would do it:
Assume year is known and is an integer.
Loop from 1 to 12
Create date with loop index, year and 13 for the day
Determine day of week as per established algorithms
If day of week calculated above is Friday, do your work
If you want to start with a month and year (you have to assume some sort of year), your algorithm becomes
Assume year is known and an integer
Assume month is known and is an integer
Loop
Create date with index of loop as year, known month variable, and 13 for the day
Determine day of week as per established algorithms
If day of week calculate above is Friday, return date, else
Else increment year by 1