I know, a bit late.

# Challenge

Your challenge is, given a date, output if it's not an Advent Sunday, or the Advent Sunday of the year.

# Rules

• The $$\4^\text{th}\$$ Advent is determined by the Sunday before Christmas day (the $$\25^\text{th}\$$ of December). The $$\3^\text{rd}\$$ Advent is the Sunday before the $$\4^\text{th}\$$ Advent, and so on until the $$\1^\text{st}\$$ Advent.
• If Christmas Day falls on a Sunday, then the Sunday before is still the $$\4^\text{th}\$$ Advent.
• Input will consist of day, month and year, as an iterable with any order, or a string, or 3 separate integers.
• Input will be a valid date, numerically and also calendrically.
• Output should be falsey (0 or Boolean False) if the date is not an Advent Sunday, or else an integer denoting which Advent Sunday it is.
• This is , so the shortest answer wins.

# Examples

[In]: [2, 12, 2021]
[Out]: 0

[In]: [6, 5, 2023]
[Out]: False

[In]: [12, 12, 2021]
[Out]: 3

[In]: [30, 11, 1997]
[Out]: 1

[In]: [25, 12, 2011]
[Out]: false

[In]: [21, 12, 3000]
[Out]: 4


Good Luck!

• May we take input as 3 integers instead of a collection? Commented Dec 27, 2021 at 18:21
• @chunes yes, 'll add that in Commented Dec 27, 2021 at 18:32

# Excel, 71 66 Bytes

Saved 5 bytes thanks to Taylor Raine

Aside: At the time of posting, this answer has the smallest byte count. That is baffling. Score one for Excel's date handling, I guess.

=LET(a,4-(INT(("12/23/"&YEAR(A1))/7)*7+1-A1)/7,(LEN(a)=1)*(a<5)*a)


Input is in cell A1. Output is wherever the formula is. Returns a number 1-4 for advent Sundays and a 0 for all other dates.

LET(a,4-(INT(("12/23/"&YEAR(A1))/7)*7+1-A1)/7


The first part calculates which advent Sunday an input is and does most of the heavy lifting.

• ("12/23/"&YEAR(A1)) finds Christmas Eve Eve (CEE) in the year of the input. We find Eve Eve hear because it saves us some extra bytes of adjustment later.
• INT(~/7)*7 takes that date, divides by 7 (b/c 7 days per week), rounds it down, then multiplies it by 7. This finds the Saturday before CEE. If CEE is a Saturday, then it returns that date.
• (INT(~/7)*7+1-A2)/7 adds one to get Sunday, subtracts the input, and divides by 7 to get the number of weeks between the input and the Sunday before Christmas. This may not be a whole number.
• 4-(~) subtracts that result from 4 to invert the result. I.E., the Sunday before Christmas needs to be the 4th Sunday, not the 1 week before.
LET(a,~,(LEN(a)=1)*(a<5)*a)


Now that the heavy lifting is out of the way, we can examine the results. Note that using TRUE and FALSE values in math will treat TRUE = 1 and FALSE = 0. By multiplying various statements that will evaluate to either TRUE or FALSE, we can filter out undesirable results.

• (LEN(a)=1) filters out any non-integers as well as negative integers. This removes every non-Sunday in the advent calendar and all dates before the first Sunday. This does not filter out the 0th Sunday but the end result will still be 0 so it works.
• (a<5) filters out Sundays after the 4th Sunday.
• (~)*(~)*a returns the value if it has passed both those filters. Otherwise, it returns 0.

In this screenshot, I have added a column to return the value of a since that's so much of the calculation. I have also extended the data beyond the samples above to show some edge cases.

• Wow. Another spreadsheet fan. Commented Dec 29, 2021 at 17:31
• I'm just realising now that THIS IS SO UNDERRATED. Excel beat Mathematica!!! Commented Dec 30, 2021 at 7:55
• You can get this down to 66 bytes if you use some implicit date conversion and Boolean multiplication as =LET(a,4-(INT(("12/23/"&YEAR(A1))/7)*7+1-A1)/7,(a<5)*(LEN(a)=1)*a) - but this will change the falsey output to be 0 rather than false Commented Jan 5, 2022 at 17:54
• @TaylorRaine This is great! I haven't golfed in a while so the refresher course on Excel tricks is fantastic. I welcome your comments. I don't think I even knew about implicit date conversion. Commented Jan 5, 2022 at 18:39

# Factor + calendar.holidays.us, 85 bytes

[ <date> dup christmas-day 4 [ dup last-sunday ] times 0 5 narray reverse nip index ]


Takes input as three integers in <year> <month> <day> order. The last-sunday word postdates build 1525, the one TIO uses, so here's a screenshot of running the above code in build 2101's listener:

## Explanation

                             ! 2021 12 12
<date>                       ! 2021-12-12
dup                          ! 2021-12-12 2021-12-12
christmas-day                ! 2021-12-12 2021-12-25
4 [ dup last-sunday ] times  ! 2021-12-12 2021-12-25 2021-12-19 2021-12-12 2021-12-5 2021-11-28
0 5 narray                   ! 2021-12-12 2021-12-25 { 2021-12-19 2021-12-12 2021-12-5 2021-11-28 0 }
reverse                      ! 2021-12-12 2021-12-25 { 0 2021-11-28 2021-12-5 2021-12-12 2021-12-19 }
nip                          ! 2021-12-12 { 0 2021-11-28 2021-12-5 2021-12-12 2021-12-19 }
index                        ! 3


# Python 3.8 (pre-release), 114 bytes

lambda a,b,c:(y:=int((c+10.5)/7))%5+y//5 if date(a,b,c).weekday()==6 and[b,c]!=[12,25]else 0
from datetime import*


Try it online!

• Welcome to Code Golf, and nice first answer! Commented Dec 28, 2021 at 13:23
• You can make it 112 bytes by removing the space in 5 if and 6 and[b,c] Commented Dec 28, 2021 at 21:56
• 107 bytes Commented Apr 21 at 10:22

# JavaScript (Node.js), 78 bytes

(y,m,d)=>/Su/.test(c=new Date(y,m-1,d))*'01234'[(c-new Date(y,9,51))/6048e5|0]


Try it online!

Falsy may be 0 or NaN. Add 2 bytes (append |0) to always get 0. User must run this program with computer configured to UTC timezone or any other timezone that: 1. No DST shift during Nov 20 to Dec 31, 2. Name of timezone (in system language) does not contain substring "Su" (case sensitive).

new Date(y,9,51) is Nov 20 in JavaScript.

# Python3, 152 bytes:

from datetime import*
t=lambda x:0if x>=date(x.year,12,25)else 1+t(x+timedelta(days=7))
f=lambda x:(s:=date(*x)).weekday()==6and(0<(j:=(5-t(s)))<5)and j


Try it online!

# Retina 0.8.2, 116 bytes

3=
;
\d+
$*_ ((_*)\2\2\2_*);((_*)\4\4\4_*)$4$3$2$1$1$1$1$1 \G_{7} -_{12}- ____ -_{11}-_{26} ^(_{7}){1,4}$|.+
$#1  Try it online! Link includes test cases. Takes input in ISO date format. Explanation: 3= ;  Separate the year from the century. \d+$*_


Convert to unary.

((_*)\2\2\2_*);((_*)\4\4\4_*)
$4$3$2$1$1$1$1$1
\G_{7}



Perform Zeller's congruence on the 25th of December of the input year.

-_{12}-
____
-_{11}-_{26}



Add this to the day of the month, adding an extra 4 for December or subtracting 26 for November 26 or later. Other months get ignored and fail to match the next stage at all.

^(_{7}){1,4}$|.+$#1


Count the number of whole weeks, but the result must be an integer between 1 and 4 inclusive.

# C (gcc), 215 202 192 bytes

#import<time.h>
i;*t;*l;f(d,m,y){5[t=calloc(9,8)]=y-1900;t[4]=m-1;t[3]=d;l=mktime(t);i=6[t=gmtime(&l)];y=t[7];t[4]=11;t[3]=25;l=mktime(t);d=7[t=gmtime(&l)]-y;m=4-d/7-!t[6];i=i|!d|m<1|m>4?0:m;}


Try it online!

Saved 13 bytes thanks to ceilingcat!!!

Inputs the day, month and year as separate parameters.
Returns which Advent Sunday it is or $$\0\$$ otherwise.

# Wolfram Language (Mathematica),  88  79 bytes

Input format should be {year, month, day}.

Ramp[4-DayCount[#,{#&@@#,12,24},s=Sunday]]Boole[DayName@#==s&&Rest@#!={12,25}]&


Try it online!

Output:

0
0
3
1
0
4


79 bytes - Thanks to @att

• 79 bytes
– att
Commented Dec 28, 2021 at 2:56

# Python 3.8,  128  116 bytes

lambda q:max(x*(date(*q)==(M:=date(q[0],11,27))+timedelta(7*x+~M.weekday()))for x in(1,2,3,4))
from datetime import*


Try it online!

# Perl 5, 144 bytes

sub{$_=join$",map{@t=gmtime$_*604800+3e5;19000100+$t[5]*1e4+$t[4]*100+$t[3]}1..6e4;pop=~/..../;/ $&$'( $&\d+)+/;$_=6-$&=~y///c/9;/^[1-4]$/?\$_:0}


Try it online!

# Scala 3, 123 120 bytes

A port of @ing's Python answer in Scala.

Saved 3 bytes thanks to @movatica

Golfed version. Attempt This Online!

(y,m,d)=>if(LocalDate.of(y,m,d).getDayOfWeek.getValue>6&&(m!=12||d!=25)){val y=(d+10.5)/7;(y.toInt%5)+(y.toInt/5)}else 0


Ungolfed version. Attempt This Online!

import java.time.LocalDate

object Main {
def main(args: Array[String]): Unit = {
println(calculateValue(2021, 12, 2))
println(calculateValue(2023, 5, 6))
println(calculateValue(2021, 12, 12))
println(calculateValue(1997, 11, 30))
println(calculateValue(2011, 12, 25))
println(calculateValue(3000, 12, 21))
}

def calculateValue(year: Int, month: Int, day: Int): Int = {
val date = LocalDate.of(year, month, day)
if (date.getDayOfWeek.getValue == 7 && !(month == 12 && day == 25)) { // Sunday is 7 in java.time.DayOfWeek
val y = (day + 10.5) / 7
(y.toInt % 5) + (y.toInt / 5)
} else {
0
}
}
}

• Commented Apr 21 at 10:25