6
\$\begingroup\$

Back in 2018, there has been introduced new law in Poland to ban trading on sundays, but certain exceptions have been made (listed below). The task today is to determine, can one trade on the sunday provided by the user (according to these rules).

Rules

You can trade only if one of the following is satisfied:

  • The day is the last sunday of 1st, 4th 6th and 8th month.
  • The day is one of the two sundays preceding Christmas.
  • The day is the sunday preceding Easter

Simplifications

Obviously one can't trade on certain holidays, but you can omit the check for them in your code. The only exclusion to this rule is Easter or Christmas (for obvious reasons).

For example, if the rules above allowed trading on 6th of January and albeit in reality you can't trade due to a holiday, you don't need to take that on the account (and assume that one can trade on 6th of January).

I/O rules

You can take the date in any reasonable format - "DDMMYYYY", "MMDDYYYY" and so on. The output should be a truthy or falsy value (answering the question - can you trade on this sunday?)

You can assume the input date to always be a sunday.

Examples

A few examples:

  • You can trade on 27 January of 2019, due to rule 1.
  • You can't trade on 13 January of 2019.
  • You can't trade on 21 April of 2019 - it's Easter.
  • You can trade on 14 April of 2019, due to rule 3.
  • You can trade on 28 April of 2019, due to rule 1.
  • You can trade on 15 December of 2019, due to rule 2.
  • You can trade on 22 December of 2019, due to rule 2.

Obvious clarifications

  • You'll have to calculate the date of Easter and Christmas in the process.
  • Your program has to work correctly with any other year than 2019.
  • You MUST take on the account that you can't trade on Easter or Christmas, even if the conditions are satisfied.
  • You don't need to check for other holidays.

Scoring criterion

The shortest code (in bytes) wins.

\$\endgroup\$
7
  • 3
    \$\begingroup\$ Because it's Poland, that's why the law is complex. If they banned all sundays, citizens would simply take the politicians out on a wheelbarrow from the Parliament. \$\endgroup\$ May 17, 2020 at 13:52
  • 5
    \$\begingroup\$ Seems a complicated enough problem just to calculate easter \$\endgroup\$
    – mkst
    May 17, 2020 at 14:45
  • 1
    \$\begingroup\$ Mathematica has Default, GovernmentBond, NASDAQ, NERC, NYSE calendars for United States, but, unfortunately, only a normal-ish calendar for Poland :( \$\endgroup\$ May 17, 2020 at 15:31
  • 3
    \$\begingroup\$ streetster is correct - this is a chameleon challenge unless we can accept two dates: the date of the Sunday to check; and the date of Easter Sunday on that same year. \$\endgroup\$ May 17, 2020 at 16:39
  • 1
    \$\begingroup\$ Chameleon challenge is a challenge where one of it's parts is nearly as hard as the challenge itself. In this case, simply calculating the date of Easter is considerably easier than solving the challenge above. You've literally got a formula for this, it spans around 4 lines, what's hard in this? I can't seem to understand the problem with the challenge \$\endgroup\$ May 17, 2020 at 16:56

3 Answers 3

4
\$\begingroup\$

JavaScript (ES6),  173  172 bytes

Takes input as (year, month, day). Returns 0 or 1.

As anticipated by @streetster, computing Easter is the biggest part.

(y,m,d)=>169>>--m&(D=new Date(y,m,d+7)).getMonth()!=m|m>10&(d+3)/14|+D==+new Date(y,2,56-(c=(y%19*351-~((b=(a=y/25>>2)>>2)+a*29.32+13.54)*31.9)/33%29|0)-~(a-b+c-24-y/.8)%7)

Try it online!

How?

Last Sunday

We use the binary mask 0b10101001 (or 169 in decimal) to encode the 0-indexed months for which it's allowed to trade on the last Sunday. We make sure that m-1 is one of these months and that adding 7 days brings us to the next month.

169 >> --m & (D = new Date(y, m, d + 7)).getMonth() != m

Christmas

We simply test whether the month is December and the day is more than 10 and less than 25.

m > 10 & (d + 3) / 14

All possible cases are summarized in the following table:

 Mo Tu We Th Fr Sa | Su | Mo Tu We Th Fr Sa | Su | Mo Tu We Th Fr Sa | Su | Mo Tu We
-------------------+----+-------------------+----+-------------------+----+----------
  8  9[10]11 12 13 | 14 | 15 16 17 18 19 20 | 21 | 22 23 24[25]26 27 | 28 | 29 30 31
  7  8  9[10]11 12 | 13 | 14 15 16 17 18 19 | 20 | 21 22 23 24[25]26 | 27 | 28 29 30
  6  7  8  9[10]11 | 12 | 13 14 15 16 17 18 | 19 | 20 21 22 23 24[25]| 26 | 27 28 29
  5  6  7  8  9[10]| 11 | 12 13 14 15 16 17 | 18 | 19 20 21 22 23 24 |[25]| 26 27 28
  4  5  6  7  8  9 |[10]| 11 12 13 14 15 16 | 17 | 18 19 20 21 22 23 | 24 |[25]26 27
  3  4  5  6  7  8 |  9 |[10]11 12 13 14 15 | 16 | 17 18 19 20 21 22 | 23 | 24[25]26
  2  3  4  5  6  7 |  8 |  9[10]11 12 13 14 | 15 | 16 17 18 19 20 21 | 22 | 23 24[25]

Easter

We test whether D (computed above) is equal to Easter. The algorithm was taken from this page (function ShortGregorianEaster1). It returns a day in March which may be greater than 31, in which case Date() quietly converts into a day in April.

+D == +new Date(y, 2, some_long_and_boring_formula)
\$\endgroup\$
2
\$\begingroup\$

Python 2 + dateutil, 163 157 bytes

Possibly could be golfed some more. Even using a library function, calculating the date for Easter still takes up almost half of the code.

-6 bytes thanks to @Arnauld

from dateutil.easter import*
y,m,d=input()
e=easter(y)
print(e.month==m)*((e.day==d+7)-(e.day==d)*(m*d>99))+m/12*(d<25)*(d>10)+(m in[4,6])*d/24+(m%7==1)*d/25

Try it online!

Accepts input in the form YYYY, (M)M, (D)D. Returns 1 if trading is allowed, 0 otherwise.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ @Arnauld Thanks! I was able to use the same trick in a couple more places too \$\endgroup\$ May 18, 2020 at 17:04
1
\$\begingroup\$

05AB1E, 109 103 101 bytes

т÷©>3*4÷DV¹19%DU19*15O®8*13+25÷-30%DX11÷+29÷-23+DY-¹D4÷++7%(91O31‰R»9bS30+6ÝδαεŽ5ÂNèδ»}˜12ÐÝ+sδ»«sª²å

Input as year, day\nmonth (multi-line string).

Try it online or verify a few more test cases.

(68 bytes are used to calculate Easter Sunday.)

Explanation:

Calculate the week before Easter Sunday, using @PeterTaylor's formula in his GolfScript answer here:

т÷             # Integer-divide the (implicit) input-year by 100
  ©            # Store it in variable `®` (without popping)
>              # Increase it by 1
 3*            # Multiply it by 3
   4÷          # Integer-divide it by 4
     DV        # Store a copy in variable `Y`
¹19%           # Push the input-year modulo-19
    DU         # Store a copy in variable `X`
19*            # Multiply the year-modulo-19 by 19
   15          # Push 15
     O         # Sum the three values on the stack together:
               #  year/100*3/4 + year%19*19 + 15
®8*            # Push variable `®` and multiply it by 8
   13+         # Add 13
      25÷      # Integer-divide it by 25
         -     # Subtract it from the earlier calculated number
          30%  # Modulo-30
             D # Duplicate it
X11÷           # Push `X` integer-divided by 11
    +          # Add it to top copy
     29÷       # Integer-divide it by 29
        -      # Subtract it from the other copy
         23+   # Add 23
            D  # Duplicate it
Y-             # Subtract `Y` from the top copy
  ¹D           # Push the input-year two times
    4÷         # Integer-divide to top year by 4
      +        # Add it to the year
       +       # Add it to the earlier number
        7%     # Modulo-7
          (    # Negate it
91             # Push 91 (three purposes: it adds 97; adds an additional 1 to make the
               #  day 1-based; subtracts 7 since we want the week before Easter Sunday)
  O            # Sum the three values on the stack
  31‰          # Divmod it by 31 to extract the 1-based month and day
     »         # And join those by newlines

Calculate all the other dates that could potentially be a truthy Sunday:

9              # Push 9
 bS            # Convert it to a binary-list: [1,0,0,1]
   30+         # Add 30 to each: [31,30,30,31]
      6Ý       # Push list [0,1,2,3,4,5,6]
        δ      # Apply double-vectorized:
         α     #  Take the absolute difference
               # [[31,30,29,28,27,26,25],[30,29,28,27,26,25,24],[30,29,28,27,26,25,24],[31,30,29,28,27,26,25]]
ε              # Map each to:
 Ž5Â           #  Push compressed integer 1468
    Nè         #  Index the map-index into it
      δ»       #  And join it to each individual day with a newline delimiter
}˜             # After the map: flatten the list
  12Ð          # Push 12 three times to the stack
     Ý         # Pop one, and push list [0,1,2,3,4,5,6,7,8,9,10,11,12]
      +        # Add each to 12: [12,13,14,15,16,17,18,19,20,21,22,23,24]
       s       # Swap so the third 12 is at the top of the stack
        δ»     # Join it to each individual day with a newline delimiter
          «    # And merge these to the earlier flattened list

Merge it together to a single list:

sª             # Add the earlier calculated Easter Sunday - 7 to the list

I.e. for the year 2019, we now have the following dates that are potentially a truthy Sunday:

["31\n1","30\n1","29\n1","28\n1","27\n1","26\n1","25\n1", # January 31 to 25
 "30\n4","29\n4","28\n4","27\n4","26\n4","25\n4","24\n4", # April 30 to 24
 "30\n6","29\n6","28\n6","27\n6","26\n6","25\n6","24\n6", # June 30 to 24
 "31\n8","30\n8","29\n8","28\n8","27\n8","26\n8","25\n8", # August 31 to 25
 "12\n12","13\n12","14\n12","15\n12","16\n12","17\n12","18\n12","19\n12","20\n12","21\n12","22\n12","23\n12","24\n12",
                                                          # December 12 to 24
 "24\n3"]                                                 # Sunday week before Easter

And we check if the second input is in this list to complete the program:

  ²å           # And check if the second input-string is in this list
               # (after which the result is output implicitly)

See this 05AB1E tip of mine (section How to compress large integers?) to understand why Ž5Â is 1468.

\$\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.