11
\$\begingroup\$

Create a function that accepts a list of dates (unsorted with possible duplicates) and returns the days of the week in one of the following formats:

  • A format similar to MTWTFSS or SMTWTFS (i.e. beginning with Monday or Sunday), with non-days replaced by an underscore _, illustrated below.
  • WEEKDAY if all the dates are between Monday to Friday (i.e. Monday, Tuesday, Wednesday, Thursday and Friday must all be present, no other days)
  • WEEKEND if all the dates are on Saturday or Sunday (i.e. Saturday and Sunday must both be present, no other days)
  • ALLWEEK if all the dates are on all days of the week!

Assume the list of dates to be in your language's date data type (e.g. List<LocalDate> for Java), else the ISO date string "YYYY-MM-DD". Addition: After looking at 05AB1E's entry, I'm now also inclined to accept 'the most convenient representation', but please explain clearly why this would be used in lieu of the original rules. I just don't want to open the flood gates here...

If it helps, you can further assume that all dates are within an arbitrary calendar non-leap-year.

Examples:

Input Output (starting Monday) Output (starting Sunday)
["2021-06-21"] M______ _M_____
["2021-06-21", "2021-06-28"] M______ _M_____
["2021-06-22", "2021-06-22"] _T_____ __T____
["2021-06-23", "2021-07-16"] __W_F__ ___W_F_
["2021-06-27", "2021-07-02", "2021-05-01"] ____FSS S____FS
["2021-06-21", "2021-06-22", "2021-06-23", "2021-06-24", "2021-06-25"] WEEKDAY WEEKDAY
["2021-06-27", "2021-06-26", "2021-06-27"] WEEKEND WEEKEND
["2021-06-21", "2021-06-23", "2021-06-22", "2021-06-26", "2021-06-25", "2021-06-24", "2021-06-27"] ALLWEEK ALLWEEK

Winning Criteria: Shortest code wins.

\$\endgroup\$
15
  • \$\begingroup\$ can we take an array of Date objects in javascript. or is it necessary to take input as string \$\endgroup\$
    – user100752
    Commented Jul 1, 2021 at 12:26
  • \$\begingroup\$ @AndrewTheCodegolfer added... \$\endgroup\$
    – h.j.k.
    Commented Jul 1, 2021 at 12:26
  • \$\begingroup\$ @EliteDaMyth eh sure, just mention it in your answer what the function input type is, I've quickly added a Java example. \$\endgroup\$
    – h.j.k.
    Commented Jul 1, 2021 at 12:26
  • 1
    \$\begingroup\$ Can we output in lowercase? \$\endgroup\$
    – Shaggy
    Commented Jul 1, 2021 at 13:09
  • 1
    \$\begingroup\$ @KevinCruijssen after some deliberation, I've decided to make an exception. :) Have clarified this on my question too... \$\endgroup\$
    – h.j.k.
    Commented Jul 1, 2021 at 17:00

7 Answers 7

8
\$\begingroup\$

05AB1E, 93 92 bytes

'_7×sε`UD3‹©12*+>₂*T÷®Xα©т%D4÷®т÷©4÷®·(O7%}D.•1Î㦕©sèsǝÀÐáÐÙ'sQi'œÙ뮦¦Qi’…‚Ž’ëQi’€Ÿ…Â’]u

Inputs in the format [dd,mm,yyyy]; output format starts at Sunday (SMTWTFS).

Try it online or verify all test cases.

Explanation:

Since 05AB1E has no Date builtins, we'll have to calculate the Day of the Week manually.

The general formula to do this is:

$${\displaystyle h=\left(q+\left\lfloor{\frac{13(m+1)}{5}}\right\rfloor+K+\left\lfloor{\frac{K}{4}}\right\rfloor+\left\lfloor{\frac{J}{4}}\right\rfloor-2J\right){\bmod{7}}}$$

Where for the months March through December:

  • \$q\$ is the \$day\$ of the month ([1, 31])
  • \$m\$ is the 1-indexed \$month\$ ([3, 12])
  • \$K\$ is the year of the century (\$year \bmod 100\$)
  • \$J\$ is the 0-indexed century (\$\left\lfloor {\frac {year}{100}}\right\rfloor\$)

And for the months January and February:

  • \$q\$ is the \$day\$ of the month ([1, 31])
  • \$m\$ is the 1-indexed \$month + 12\$ ([13, 14])
  • \$K\$ is the year of the century for the previous year (\$(year - 1) \bmod 100\$)
  • \$J\$ is the 0-indexed century for the previous year (\$\left\lfloor {\frac {year-1}{100}}\right\rfloor\$)

Resulting in the day of the week \$h\$, where 0 = Saturday, 1 = Sunday, ..., 6 = Friday.
Source: Zeller's congruence

The implementation of this formula in the code below is:

`UD3‹©12*+>₂*T÷®Xα©т%D4÷®т÷©4÷®·(O7%
'_7×        '# Push string "_______"
s            # Swap to get the (implicit) input-list
 ε           # Map over each date:
             #  Determine its day of the week:
  `          #   Push the day, month, and year to the stack
   U         #   Pop and save the year in variable `X`
    D        #   Duplicate the month
     3‹      #   Check if the month is below 3 (Jan. / Feb.),
             #   resulting in 1 or 0 for truthy/falsey respectively
       ©     #   Store this in variable `®` (without popping)
        12*  #   Multiply it by 12 (either 0 or 12)
           + #   And add it to the month
             #   (This first part was to make Jan. / Feb. 13 and 14)
  >          #   Month + 1
   ₂*        #   Multiplied by 26
     T÷      #   Integer-divided by 10
  ®          #   Push month<3 from variable `®` again
   Xα        #   Take the absolute difference with the year
     ©       #   Store this potentially modified year as new `®` (without popping)
      т%     #   mYear modulo-100
  D4÷        #   mYear modulo-100, integer-divided by 4
  ®т÷©4÷     #   mYear integer-divided by 100, and then integer-divided by 4
  ®·(        #   mYear integer-divided by 100, doubled, and then made negative
  O          #   Take the sum of all values on the stack
   7%        #   And then take modulo-7 to complete the formula, resulting in 0 for
             #   Saturday, 1 for Sunday, and [2, 6] for [Monday, Friday]
}D           # After the map: duplicate the list of integers
  .•1Î㦕   # Push compressed string "ssmtwtf"
          ©  # Store it in variable `®` (without popping)
  s          # Swap so the duplicated list of integers is at the top
   è         # Index each into this string
    s        # Swap so the list of integers is at the top again
     ǝ       # Insert the characters at these indices inside the "_______" string
      À      # Rotate it once towards the left
Ð            # Triplicate this result
 á           # Only leave the letters of the top copy
  Ð          # Triplicate that as well
   „ssQi    '# Pop one copy, and if it's equal to "ss":
      'œÙ   '#  Push dictionary string "weekend"
    뮦¦Qi   # Else-if it's equal to `®` minus its first two characters ("mtwtf"):
      ’…‚Ž’ #  Push dictionary string "weekday"
    ëQi      # Else-if the string remained the same after only leaving letters:
      ’€Ÿ…Â’ #  Push dictionary string "allweek"
    ]        # Close all if-else statements
     u       # Uppercase the result
             # (after which this is output implicitly)

See this 05AB1E tip of mine (sections How to use the dictionary? and How to compress strings not part of the dictionary?) to understand why .•1Î㦕 is "ssmtwtf"; 'œÙ is "weekend"; ’…‚Ž’ is "weekday"; and ’€Ÿ…Â’ is "allweek".

\$\endgroup\$
0
5
\$\begingroup\$

JavaScript (ES6), 119 bytes

Expects a list of Date objects. Uses the SMTWTFS format.

a=>a.map(d=>a|=1<<d.getDay())|a-127?a-62?a-65?'SMTWTFS'.replace(/./g,(c,i)=>a>>i&1?c:'_'):'WEEKEND':'WEEKDAY':'ALLWEEK'

Try it online!

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

Japt, 71 bytes

Not happy with this first pass; need to try a few different approaches to see if I can get it down any smaller. Outputs in lowercase, pending confirmation. +3 bytes for the unnecessary requirement of uppercase output.

£ÐX eÃÍâ
`³ekÜü³ekÀAa¥³ekmtwtfs`qi o£øY ?X:'_ÃfÏg[Ue5õ)60¥U¬Ô7¥UÊ1]ÃÎu

Try it - includes all test cases

\$\endgroup\$
2
  • \$\begingroup\$ The string encoding with s is very nice. Since you can take a list of native dates as an input, you could move £ÐX to the header to shave off 4 bytes. \$\endgroup\$
    – Etheryte
    Commented Jul 1, 2021 at 15:21
  • \$\begingroup\$ I had contemplated that, @Etheryte, but it felt like cheating to me to workaround the fact that Japt can't natively handle date objects as input. Also, the first line would then become me Íâ and I'd need a V in from of the ø in the last map so it would only save 2 bytes. \$\endgroup\$
    – Shaggy
    Commented Jul 1, 2021 at 15:26
3
\$\begingroup\$

Python 3, 223 216 204 200 190 186 bytes

Straight forward implementation with datetime functions, no fancy string compression.

Saved some bytes exploiting a dict for the special cases.

-4 bytes thanx to Kateba

from datetime import*
m='MTWTFSS'
def f(x,y='_'*7):
 for z in x:i=date.fromisoformat(z).weekday();y=y[:i]+m[i]+y[i+1:]
 return{y:y,m:'ALLWEEK','MTWTF__':'WEEKDAY','_____SS':'WEEKEND'}[y]

Try it online!

\$\endgroup\$
1
  • 2
    \$\begingroup\$ -4 bytes \$\endgroup\$
    – Kateba
    Commented Jul 2, 2021 at 11:08
2
\$\begingroup\$

Perl 5, 155 bytes

$o="_"x7;join("",map{strftime"%F%w%A",0,0,0,$_,0,0}0..6e4)=~/$_(.)(.)/,substr$o,$1,1,$2for@F;$_={_MTWTF_,WEEKDAY,S_____S,WEEKEND,SMTWTFS,ALLWEEK}->{$o}||$o

Try it online!

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

PHP, 133 132 bytes

for($w=SMTWTFS,$r=_______;$d=$argv[++$i];)$r[$j=$d->format(w)]=$w[$j];echo$r==$w?ALLWEEK:$r==_MTWTF_?WEEKDAY:$r==S_____S?WEEKEND:$r;

Try it online!

Uses the script arguments array converted to DateTime objects (1-indexed), uses the SMTWTFS format.

First version with the dict exploit like in movatica's answer, but still looking how to shorten it.

EDIT: saved 1 byte with ternary operators

\$\endgroup\$
5
  • \$\begingroup\$ Save some bytes by doing $d=$argv[++$i]->format(w), and no need to create $j. \$\endgroup\$ Commented Jul 2, 2021 at 14:47
  • \$\begingroup\$ @GuillermoPhillips I tried things like this, unfortunately it doesn't work, first because the index is falsey for sunday ("0") and that would stop the loop, second because when it reaches the end of the array, ->format throws an error on NULL and there's no input.. I'm still searching \$\endgroup\$
    – Kaddath
    Commented Jul 2, 2021 at 15:14
  • \$\begingroup\$ *output (not input) \$\endgroup\$
    – Kaddath
    Commented Jul 2, 2021 at 15:35
  • \$\begingroup\$ Understood - now I've actually tried it! It's a shame. I notice that ALLWEEK, WEEKEND and WEEKDAY are all seven characters. Thinking about how to run with that, hmm. \$\endgroup\$ Commented Jul 2, 2021 at 15:49
  • \$\begingroup\$ @GuillermoPhillips yeah, but actually that was a disadvantage when I tried to golf the code, because 7 is short, so all solutions I thought of ended longer than having the litteral strings in there \$\endgroup\$
    – Kaddath
    Commented Jul 2, 2021 at 16:02
1
\$\begingroup\$

Ruby, 125 bytes

f=->l{i=0;l.map{|d|i|=2**d.wday};{i=>(0..6).map{|a|i[a]>0?'SMTWTFS'[a]:?_}*'',62=>'WEEKDAY',65=>"WEEKEND",127=>"ALLWEEK"}[i]}

Try it online!

Takes a list of Dates and outputs in the SMTWTFS format. Abuses Ruby's integer subscriptions to get a (sort of) boolean array.

I copied the dict exploit of the python answer, it works well :)

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