15
\$\begingroup\$

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!

\$\endgroup\$
2
  • \$\begingroup\$ May we take input as 3 integers instead of a collection? \$\endgroup\$
    – chunes
    Commented Dec 27, 2021 at 18:21
  • \$\begingroup\$ @chunes yes, 'll add that in \$\endgroup\$
    – math scat
    Commented Dec 27, 2021 at 18:32

11 Answers 11

7
+50
\$\begingroup\$

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.

Screenshot

\$\endgroup\$
4
  • \$\begingroup\$ Wow. Another spreadsheet fan. \$\endgroup\$
    – math scat
    Commented Dec 29, 2021 at 17:31
  • 2
    \$\begingroup\$ I'm just realising now that THIS IS SO UNDERRATED. Excel beat Mathematica!!! \$\endgroup\$
    – math scat
    Commented Dec 30, 2021 at 7:55
  • 2
    \$\begingroup\$ 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 \$\endgroup\$ Commented Jan 5, 2022 at 17:54
  • 1
    \$\begingroup\$ @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. \$\endgroup\$ Commented Jan 5, 2022 at 18:39
6
\$\begingroup\$

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:

enter image description here

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
\$\endgroup\$
6
\$\begingroup\$

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!

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

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.

\$\endgroup\$
4
\$\begingroup\$

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!

\$\endgroup\$
0
4
\$\begingroup\$

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.

\$\endgroup\$
4
\$\begingroup\$

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.

\$\endgroup\$
0
4
\$\begingroup\$

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

\$\endgroup\$
1
  • 1
    \$\begingroup\$ 79 bytes \$\endgroup\$
    – att
    Commented Dec 28, 2021 at 2:56
3
\$\begingroup\$

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!

\$\endgroup\$
3
\$\begingroup\$

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!

\$\endgroup\$
3
\$\begingroup\$

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
    }
  }
}
\$\endgroup\$
1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.