14
\$\begingroup\$

This is the inverse of "Encode the date in Christmas Eve format."

Write a program that takes as input the string Christmas, possibly followed by Eve between 1 and 365 times, and outputs the date encoded in YYYY-MM-DD format, or any format from which the year, month, and date can be easily obtained. Assume that the "Christmas" being referred to is the next Christmas, or today, if today is Christmas. Christmas is December 25.

Your program may also take the current date as input in the same format used for output, if there is no way to get it in the language you use.

Remember to take leap years into account.

Examples if run on or before Christmas 2023:

Input Output
Christmas 2023-12-25
Christmas Eve 2023-12-24
Christmas Eve Eve 2023-12-23
Christmas Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve 2023-11-15
Christmas Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve Eve 2022-12-26
\$\endgroup\$
10
  • 1
    \$\begingroup\$ Is YYYY-MM-DD format strict, or could a submission use e.g. [YYYY, MM, DD] or [DD, MM, YYYY]? \$\endgroup\$
    – noodle man
    Nov 16, 2023 at 4:16
  • 2
    \$\begingroup\$ Maybe you'd better include a sentence about which day is Christmas in your post. \$\endgroup\$
    – tsh
    Nov 16, 2023 at 5:16
  • 9
    \$\begingroup\$ Obligatory xkcd: xkcd.com/2089 \$\endgroup\$
    – pigrammer
    Nov 16, 2023 at 14:04
  • 3
    \$\begingroup\$ @Somebody I think tsh is trying to say that not everybody knows when Christmas is, it could fade out of existence in the future, and the post is supposed to be self-contained if possible. \$\endgroup\$
    – pigrammer
    Nov 16, 2023 at 14:09
  • 3
    \$\begingroup\$ @Somebody Not necessarily. Most Christians celebrate Christmas on 25-Dec, but some celebrate it in January. \$\endgroup\$
    – Xcali
    Nov 16, 2023 at 19:06

22 Answers 22

5
\$\begingroup\$

Excel, 35 33 bytes

"26/12"-ROWS(TEXTSPLIT(A1,," "))

Input in cell A1.

\$\endgroup\$
2
  • \$\begingroup\$ I think this will only work when the spreadsheet locale has dates in the d/M format. In the United States locale, you'll need M/d — replace "26/12" with "12/26". \$\endgroup\$ Nov 16, 2023 at 19:52
  • 6
    \$\begingroup\$ Doesn't look like this gets the next Christmas correctly when the current date is between 26 and 31 December? \$\endgroup\$ Nov 16, 2023 at 23:12
5
\$\begingroup\$

shell + coreutils, 78 76 bytes

d=date\ 
$d-d$(((`$d+%s`>=`$d+%s -d12/26`)+`$d+%Y`))-12-25-$((${#1}/4-2))day

Attempt This Online!

Edit: the previous version outputs (incorrectly) the previous Christmas \$n\$-th Eve when the current date is between December 26th and 31st.

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

PowerShell, 35 56 55 bytes

($c=date 12/26)|% *ars((date)-ge$c)|% *ys(-$args.Count)

Try it online!

+21: Fixed to get the next Christmas eve, including when called between 12/26 and 12/31, thanks to @i-t-delinquent.
-1: Setting/outputting $c, thanks to @julian

Returns DateTime objects.
Nothing remarkable; gets a date object for the 26th of December, adds a year if past the 25th, and subtracts the argument count as days.
(date) -ge $c will return a boolean, which will be evaluated as 0/1 when passed to AddYears, which expects an integer.

Disclaimer: Don't use 'date' in your day-to-day scripts; this is fit for golfing only. PowerShell will first search through all available commands, and if it doesn't find one named "date", it will prepend "Get-" and try again. Very slow, and will fail if a command line program date.exe exists somewhere in the path.

Ungolfed (method call using ForEach-Object; golfs better):

$c = Get-Date 12/26
$c | ForEach-Object -MemberName AddYears ((Get-Date) -ge $c) | ForEach-Object -MemberName AddDays (-$args.Count)

Ungolfed alternative (usual method call):

$c = Get-Date 12/26
$c.AddYears((Get-Date) -ge $c).AddDays(-$args.Count)
\$\endgroup\$
3
  • 1
    \$\begingroup\$ Wouldn't this fail as it is year specific? I.e running this in 2024 would produce negative results to Christmas since it's still look at 2023 and not 2024 \$\endgroup\$ Nov 16, 2023 at 10:41
  • \$\begingroup\$ @i-t-delinquent Should be fixed, taking into account the time from 12/26 to 12/31 as well. \$\endgroup\$
    – user314159
    Nov 16, 2023 at 14:02
  • \$\begingroup\$ You can save one byte by using $c when you assign it: Try it online! \$\endgroup\$
    – Julian
    Nov 16, 2023 at 22:14
3
\$\begingroup\$

JavaScript (Node.js), 79 bytes

s=>new Date(/c 2[6-9]|c 3/.test(t=new Date)+t.getFullYear(),11,109-s.length>>2)

Try it online!

73 bytes if take today as input.

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

Google Sheets / Microsoft Excel, 30 67 58 50 39 bytes

=(year(now()+6)&"-12-26")-(len(A1)-5)/4

Put the input in cell A1 and the formula in C1.

The formula outputs a numeric dateserial value. The question specifies "any format from which the year, month, and date can be easily obtained". To obtain those date fields, format the formula cell as Format > Number > Date or similar.

The question also specifies "next Christmas". When the current moment is within 26 to 31 December, the formula looks at Christmas next year, and outputs a date counting down from that Christmas date. Otherwise, it looks at Christmas in the current year.

The first part of the formula obtains a string in the ISO8601 format yyyy-MM-dd which is a valid date format in any locale. The string gets coerced to a dateserial while subtracting the second part (the number of Eves plus one.)

You can include formatting in the formula at a cost of 9 bytes (Google Sheets):

=to_date((year(now()+6)&"-12-26")-(len(A1)-5)/4)

...or at a cost of 17 bytes (Microsoft Excel):

=text((year(now()+6)&"-12-26")-(len(A1)-5)/4,"M/d/yyyy")

input expected output (as Date)
Christmas 2023-12-25 12/25/2023
Christmas Eve 2023-12-24 12/24/2023
Christmas Eve Eve 2023-12-23 12/23/2023
Christmas Eve Eve Eve... (40 times in total) 2023-11-15 11/15/2023
Christmas Eve Eve Eve... (364 times in total) 2022-12-26 12/26/2022
\$\endgroup\$
3
  • \$\begingroup\$ Do you need the close parens? I thought it puts them there for you, but I could be mistaken. \$\endgroup\$
    – Bbrk24
    Nov 16, 2023 at 18:40
  • 2
    \$\begingroup\$ You're correct — you can leave the closing quote and parens out when entering the formula, and let the formula editor fill them in for you, "saving" you three bytes. But the working formula still has those three characters, regardless of whether they were entered manually or by the formula editor, so my thinking is that the bytes reported in the answer must still include them. Is there a meta consensus about the matter? \$\endgroup\$ Nov 16, 2023 at 19:37
  • 1
    \$\begingroup\$ I hadn't checked meta. There's this question and the highest-voted answer suggests that the close parens must be included. \$\endgroup\$
    – Bbrk24
    Nov 16, 2023 at 21:09
2
\$\begingroup\$

GAWK, 74 65 64 bytes

$0=mktime(strftime("%Y",systime()+720^2)" 12 26 0 0 0")-86400*NF

Try it online!

  • -9 bytes, reassign $0, as epoch time will be >1 will print the line. And replaced the make time to one day later to account for the first field.
  • -1 byte, replaced 518400 with its root squared 720^2

This will print the epoch time of the date you asked for. From which you can easily obtain any date format.

\$\endgroup\$
2
\$\begingroup\$

JavaScript (Node.js), 68 bytes

s=>new(D=Date)(new D(+new D+5184e5).getFullYear(),9,353-s.length>>2)

Try it online!

From tsh's

-3B from Arnauld

\$\endgroup\$
4
  • \$\begingroup\$ 68 bytes \$\endgroup\$
    – Arnauld
    Nov 16, 2023 at 15:17
  • \$\begingroup\$ +newnew would seem to work \$\endgroup\$ Nov 17, 2023 at 10:11
  • \$\begingroup\$ @doubleunary No, it doesn't. new Date+n gives a string representation of the date concatenated with n, which is parsed back as the original date. \$\endgroup\$
    – Arnauld
    Nov 17, 2023 at 13:02
  • \$\begingroup\$ @Arnauld Thanks, I see it now. \$\endgroup\$ Nov 17, 2023 at 14:20
2
\$\begingroup\$

Python, 136 125 121 94 bytes

Returns a datetime object.

lambda x:d((d.today()+t(6)).year,12,25)-t(len(x)/4-2)
from datetime import*
d=date
t=timedelta
\$\endgroup\$
12
  • \$\begingroup\$ On ATO I'm getting name 'date' is not defined, is this a bug or an ATO issue? ATO \$\endgroup\$
    – noodle man
    Nov 16, 2023 at 4:18
  • \$\begingroup\$ The default argument is evaluated before the import. \$\endgroup\$ Nov 16, 2023 at 4:24
  • 1
    \$\begingroup\$ So do I move the import up? Does that make me add bytes? \$\endgroup\$ Nov 16, 2023 at 4:28
  • 1
    \$\begingroup\$ I think you could take off two bytes be searching for a space instead of "Eve"? \$\endgroup\$
    – Someone
    Nov 16, 2023 at 5:08
  • 1
    \$\begingroup\$ Here’s a version at 94 bytes: tio.run/#%23Ncg7CsMwDADQ3acwmaQ2San7GQqZSm/… \$\endgroup\$ Nov 16, 2023 at 20:26
2
\$\begingroup\$

Bash + GNU date, 48 43 38 bytes

date -d`date -d6day +%Y`1226-$#day +%F

We count the number of arguments and subtract that from Boxing Day (26 December).

If today is after Christmas, we need to start from next Boxing Day, so we look ahead six days from today to find the appropriate year to use.

Thanks to Nahuel Fouilleul for suggesting we read standard input rather than command arguments, saving 5 bytes.

Thanks to Neil for suggesting we let the shell do the splitting and counting.

Online version

\$\endgroup\$
2
  • 1
    \$\begingroup\$ -5 bytes taking from standard input \$\endgroup\$ Nov 17, 2023 at 12:47
  • 1
    \$\begingroup\$ ... or you could just use the shell variable for the number of arguments: date -d`date -d6day +%Y`1226-$#day +%F - Try it online! \$\endgroup\$
    – Neil
    Nov 18, 2023 at 0:54
2
\$\begingroup\$

Julia, 72 bytes

using Dates
~s=tonext(==((12,26))∘monthday,today())-Day(sum(<('D'),s))

Attempt This Online!

Based on the Julia solution to the inverse problem

  • -2 bytes thanks to MarcMush: replace sum(==(' '),s) with count(' ',s)
  • -1 byte thanks to MarcMush: replace count(' ',s)+1 with sum(<('D'),s)
\$\endgroup\$
4
  • 1
    \$\begingroup\$ with Julia 1.2: sum(<('!'),s) or 1.7: count(' ',s) \$\endgroup\$
    – MarcMush
    Nov 16, 2023 at 23:09
  • 1
    \$\begingroup\$ since +1 is needed, sum(<('D'),s) is shorter (without +1) \$\endgroup\$
    – MarcMush
    Nov 17, 2023 at 16:14
  • \$\begingroup\$ @AZTECCO this won't work if today is Christmas, that's why we search for the 26th \$\endgroup\$
    – MarcMush
    Nov 19, 2023 at 10:56
  • \$\begingroup\$ @MarcMush ok I see \$\endgroup\$
    – AZTECCO
    Nov 19, 2023 at 13:11
2
\$\begingroup\$

R, 67 65 bytes

\(x)as.Date(ISOdate(substr(Sys.Date()+6,1,4),12,25))-nchar(x)/4+3

Attempt This Online!

A function taking a string and returning a date.

  • Thanks to @pajonk for saving two bytes
\$\endgroup\$
1
  • 1
    \$\begingroup\$ -2 bytes using ISOdate, probably fiddling with different datetime functions may decrease byte count even more. \$\endgroup\$
    – pajonk
    Nov 19, 2023 at 12:10
1
\$\begingroup\$

PowerShell, 61 bytes

(Get-Date '25/12').AddDays(-($c-split"( )"-match"^\s").count)

Try it online!

$c would need to be declared with the "Christmas eve" string in the same environment. Would output in the format of:

23 December 2023 00:00:00

FYI doesn't seem to run in the browser but runs fine in ISE and PowerShell console.

\$\endgroup\$
2
  • 2
    \$\begingroup\$ Doesn't account for the "critical" time from 12/26 to 12/31, where the next Christmas is next year. \$\endgroup\$
    – user314159
    Nov 16, 2023 at 12:37
  • 1
    \$\begingroup\$ You can't assume that $c is defined externally. Those bytes count towards your score. \$\endgroup\$
    – Dingus
    Nov 17, 2023 at 12:04
1
\$\begingroup\$

Go, 108 bytes

import(."time";."strings")
func f(s string)Time{return Date(Now().Year(),12,25-Count(s," Eve"),0,0,0,0,UTC)}

Attempt This Online!

Returns a Time.

\$\endgroup\$
1
\$\begingroup\$

Jelly, 84 bytes

ċ⁶“£ṠạƙƓḢỤṢ]Ẉ¬z=æ¦ŀḥØo?3€ñḥqṅẹḂḟ⁽ḟ“œ4»j “ÇyṪ⁸ȷ6Ė|6¤ƤY¢ḷ/q³ȦþỵMñ§.ṣs)~ṛßẠ»Ḳ¤ṣḢ}¹jʋƒŒV

Try it online!

A monadic link taking a Jelly string and printing a date to STDOUT. Jelly lacks date handling, so this builds and executes a Python expression that looks like this:

print(__import__("datetime").date((__import__("datetime").date.today()+__import__("datetime").timedelta(7)).year,12,25)-__import__("datetime").timedelta(x))

where x is the count of spaces in the input. Most of the Jelly code is compressed strings. These are used to shorten the code along with some simple substitutions of repetitive code (__import__("datetime")., date and timedelta(). __import__() is used because Jelly doesn’t import the datetime module itself.

\$\endgroup\$
1
\$\begingroup\$

Scala, 98 bytes

Golfed version. Try it online!

x=>java.time.LocalDate.of(java.time.LocalDate.now.plusDays(6).getYear,12,25).minusDays(x.size/4-2)

Ungolfed version. Try it online!

import java.time.{LocalDate, Period}

object Main {
  def main(args: Array[String]): Unit = {
    println(f("Christmas Eve Eve Eve").toString)
  }

  def f(x: String): LocalDate = {
    val d = LocalDate.now().plusDays(6)
    val christmas = LocalDate.of(d.getYear, 12, 25)
    val daysDiff = x.length / 4 - 2
    christmas.minusDays(daysDiff)
  }
}
\$\endgroup\$
1
\$\begingroup\$

Charcoal, 65 bytes

≔”8±AHF@ε✂hλ”θ≔≕⁺θ.resolutionη⁻▷θ⟦I…⭆¹⁺▷⁺θ.today⟦⟧×⁷η⁴⁺²χ²⁵⟧×№S η

Try it online! Link is to verbose version of code. Based on @NickKennedy's Jelly answer. Explanation:

≔”8±AHF@ε✂hλ”θ

Get the compressed string datetime.date, which prefixes all of the necessary functions.

≔≕⁺θ.resolutionη

Get the result of datetime.date.resolution, which is another way of saying datetime.timedelta(1), but golfier because it reuses the string datetime.date.

⁻▷θ⟦I…⭆¹⁺▷⁺θ.today⟦⟧×⁷η⁴⁺²χ²⁵⟧×№S η

Take today's date, add on 7 days, cast to string so that the year can be extracted (Charcoal can't call instance methods), create Christmas Day in that year, then subtract a day for each space in the input string.

\$\endgroup\$
1
\$\begingroup\$

05AB1E, 103 36 bytes

ð¢žg’IO.ÃÍ Dâì.‚±(~D[ÿ-12-25],-ÿ)’.E

Outputs the date in yyyy-mm-dd format with automatically trailing "\nok".

Try it online or verify all test cases.

Explanation:

ð¢       # Count the amount of spaces in the (implicit) input-string
  žg     # Push the current year
    ’IO.ÃÍ Dâì.‚±(~D[ÿ-12-25],-ÿ)’
         # Push dictionary string "IO.puts Date.add(~D[ÿ-12-25],-ÿ)",
         # where the first `ÿ` is filled with the pushed year
         # and the second `ÿ` is filled with the amount of spaces of the input
     .E  # Evaluate it as Elixir:
IO.puts           % Print
~D[y-12-25]       % Christmas Day of the given year `y` as Date-object
Date.add(...,-n)  % After we went back in time the given `n` amount of days

See this 05AB1E tip of mine (section How to use the dictionary?) to understand why ’IO.ÃÍ Dâì.‚±(~D[ÿ-12-25],-ÿ)’ is "IO.puts Date.add(~D[ÿ-12-25],-ÿ)".

\$\endgroup\$
1
\$\begingroup\$

Elixir, 110 bytes

fn(s)->Date.add(Date.new(Date.utc_today.year,12,25)|>elem(1),-(s|>String.graphemes|>Enum.count(& &1==" ")))end

Only my second or third Elixir answer, so can definitely be golfed.

Try it online.

Explanation:

fn(s)->                    % Function with string argument and Date return-type
  Date.add(                %  Go back in time by adding a negative amount of days:
    Date.new(              %   Create a new {:ok,Date}-tuple:
      Date.utc_today.year, %    Using the current year
      12,25)               %    And Christmas Day
    |>elem(1),             %   Extract the Date from the ok-tuple
    -(                     %   And go back the following amount of days:
      s|>String.graphemes  %    Convert the input-string to a list of unicode characters
       |>Enum.count(& &1==" ")))end
                           %    And then count the amount of space characters among them
\$\endgroup\$
1
\$\begingroup\$

Ruby, 80 73 bytes

f=->s,a=Date.today{a.to_s=~/12-25/?a-(s.count'v'):f[s,a+1]}
require"date"

Try it online!

Instead of using date range I've switched to recursion.

a.to_s=~/12-25/? If current date matches /25-12/ then
a-(s.count'v') return that day minus how many 'v' in input
:f[s,a+1] else try next day

\$\endgroup\$
1
\$\begingroup\$

Lua, 108 bytes

d=os.date a=86400_,n=(...):gsub(' ',0)t=os.time()while d('%d%m',t)~='2512'do t=t+a end print(d('%x',-n*a+t))

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Perl 5 -MPOSIX, 71 bytes

sub f{strftime"%Y%m%d",1..3,25-$_[0]=~s/E//g,11,(gmtime 518400+pop)[5]}

Try it online!

sub f{
  strftime "%Y%m%d",       #return date as eight digits YYYYMMDD
    1..3,                  #three args for sec, min, hour, values dont matter
    25-$_[0]=~s/E//g,      #day of month, 25th minus the number of E's ("Eve"s)
                           #strftime deals with overflow into negative numbers
                           #in previous months and years potentially
    11,                    #11 = December with 0=the first month January
    (gmtime 518400+pop)[5] #output year found from given date pop'ed from @_ the
                           #input args plus 6 days (518400 sec) to account for
                           #the last days of the year after 25th Dec that should
                           #focus on Christmas the next year
  }
\$\endgroup\$
1
\$\begingroup\$

APL (Dyalog Unicode), with date and days dfns, 43 bytes

{n(⊃(n←date days)0 0 6+3↑⎕TS),12,27-⌊4÷⍨≢⍵}

Try it online!

\$\endgroup\$

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.