The Work Day Countdown I just had a genius idea for making the work-life easier - a countdown to a specific date which only counts workdays.



The basic task is to create a countdown to a specific date which only includes the workdays in the countdown.

As workday counts Monday, Tuesday, Wednesday, Thursday and Friday.

The Input should be a specific date in the "unofficial" European standard format dd.MM.yyyy and must be today or a day in the future.

The Output should only be the number of days left.

As it's code-golf the shortest code wins.



Test case:

  Today    |   Input    | Output
10.12.2018 | 17.12.2018 |    5
02.10.2018 | 16.10.2018 |   10




If I missed a few things in the question, please forgive me - it's my first question :)

EDIT:


You can use false as output instead of 0 &lt;- but it's not beautiful
No need for respecting DST
05AB1E, 130 128 133 131 124 123 122 121 bytes
žežfžg)V0[Y`UD3‹©12*+&gt;₂*T÷®Xα©т%D4÷®т÷©4÷®·()ćsO7%2@+Y`т‰0Kθ4ÖUD2Qi\28X+ë&lt;7%É31α}‹iY¬&gt;0ëY1¾ǝDÅsD12‹i&gt;1ë\1Dǝ¤&gt;2}}ǝVYI'.¡Q#

I'm out of my mind..
For the golfing language 05AB1E it doesn't matter at all whether the input is with . or -. However, 05AB1E doesn't have any builtins for Date objects or calculations. The only builtin regarding dates it has is today's year/month/day/hours/minutes/seconds/microseconds.
So because of that, almost all of the code you see are manual calculations to go to the next day, and calculating the day of the week.
+5 bytes due to a part I forgot in Zeller's formula (year-1 for months January and February)..
-1 byte thanks to @Grimmy, by changing \$\left\lfloor{\frac{13(m+1)}{5}}\right\rfloor\$ to \$\left\lfloor{\frac{26(m+1)}{10}}\right\rfloor\$ in the code, since 05AB1E has single-byte builtins for both 26 and 10 (being ₂ and T respectively), as opposed to the 3 bytes of 13 and 5.
Try it online or Try it online with an emulated self-specified date of 'today'.
Explanation:
Wall of text incoming.
In general, the code follows the following pseudo-code:
1   Date currentDate = today;
2   Integer counter = 0;
3   Start an infinite loop:
4*    If(currentDate is NOT a Saturday and currentDate is NOT a Sunday):
5       Counter += 1;
6*    currentDate += 1; // Set currentDate to the next day in line
7     If(currentDate == parsed input-string):
8       Stop the infinite loop, and output the counter

1) Date currentDate = today; is this part of the 05AB1E program:

že          # Push today's day
  žf        # Push today's month
    žg      # Push today's year
      )     # Wrap them into a single list
       V    # Pop and store this list in variable `Y`


2) Integer counter = 0; and 3) Start an infinite loop: are straight-forward in the 05AB1E program:

0     # Push 0 to the stack
 [    # Start an infinite loop


4) If(currentDate is NOT a Saturday and currentDate is NOT a Sunday): is the first hard part with manual calculations. 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 in the day of the week \$h\$, where 0 = Saturday, 1 = Sunday, ..., 6 = Friday.
Source: Zeller's congruence
We can see this in this part of the 05AB1E program:

Y             # Push variable `Y`
 `            # 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

&gt;             # Month + 1
 ₂*           # Multiplied by 26
   T÷         # Integer-divided by 10
®             # Push month&lt;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
)             # Wrap the entire stack into a list
 ć            # Extract the head (the counter variable that was also on the stack)
  s           # Swap so the calculated values above are as list at the top
   O          # Take the sum of this entire list
    7%        # And then take modulo-7 to complete the formula,
              # resulting in 0 for Saturday, 1 for Sunday, and [2, 6] for [Monday, Friday]

2@            # Check if the day is greater than or equal to 2 (so a working day)


5) Counter += 1; is straight-forward again:

     # The &gt;=2 check with `2@` results in either 1 for truthy and 0 for falsey
+    # So just adding it to the counter variable is enough


6) currentDate += 1; // Set currentDate to the next day in line is again more complex, because we have to do it manually. So this will be expanded to the following pseudo-code:
a   Integer isLeapYear = ...;
b   Integer daysInCurrentMonth = currentDate.month == 2 ?
c                                 28 + isLeapYear
d                                :
e                                 31 - (currentDate.month - 1) % 7 % 2;
f   If(currentDate.day &lt; daysInCurrentMonth):
g     nextDate.day += 1;
h   Else:
i     nextDate.day = 1;
j     If(currentDate.month &lt; 12):
k       nextDate.month += 1;
l     Else:
m       nextDate.month = 1;
n       nextDate.year += 1;

Sources:
Algorithm for determining if a year is a leap year. (EDIT: No longer relevant, since I use an alternative method to check leap years which saved 7 bytes.)
Algorithm for determining the number of days in a month.
6a) Integer isLeapYear = ...; is done like this in the 05AB1E program:

Y             # Push variable `Y`
 `            # Push the days, month and year to the stack
  т‰          # Divmod the year by 100
    0K        # Remove all items &quot;00&quot; (or 0 when the year is below 100)
      θ       # Pop the list, and leave the last item
       4Ö     # Check if this number is visible by 4
         U    # Pop and save the result in variable `X`

Also used in this 05AB1E answer of mine, so there some example years are added to illustrate the steps.

6b) currentDate.month == 2 ? and 6c) 28 + isLeapYear are done like this:

D            # Duplicate the month that is now the top of the stack
 2Q          # Check if it's equal to 2
   i         # And if it is:
    \        #  Remove the duplicated month from the top of the stack
     28X+    #  Add 28 and variable `X` (the isLeapYear) together


6d) : and 6e) 31 - (currentDate.month - 1) % 7 % 2; are done like this:

ë           # Else:
 &lt;          #  Month - 1
  7%        #  Modulo-7
    É       #  Is odd (shortcut for %2)
     31     #  Push 31
       α    #  Absolute difference between both
}           # Close the if-else


6f) If(currentDate.day &lt; daysInCurrentMonth): is done like this:

‹     # Check if the day that is still on the stack is smaller than the value calculated
 i    # And if it is:


6g) nextDate.day += 1; is done like this:

Y       # Push variable `Y`
 ¬      # Push its head, the days (without popping the list `Y`)
  &gt;     # Day + 1
   0    # Push index 0

        # (This part is done after the if-else clauses to save bytes)
}}      # Close the if-else clauses
  ǝ     # Insert the day + 1 at index 0 in the list `Y`
   V    # Pop and store the updated list in variable `Y` again


6h) Else: and 6i) nextDate.day = 1; are then done like this:

ë        # Else:
 Y       #  Push variable `Y`
  1      #  Push a 1
   ¾     #  Push index 0
    ǝ    #  Insert 1 at index 0 (days part) in the list `Y`


6j) If(currentDate.month &lt; 12)::

D           # Duplicate the list `Y`
 Ås         # Pop and push its middle (the month)
   D12‹     # Check if the month is below 12
       i    # And if it is:


6k) nextDate.month += 1;:

&gt;       # Month + 1
 1      # Push index 1

        # (This part is done after the if-else clauses to save bytes)
}}      # Close the if-else clauses
  ǝ     # Insert the month + 1 at index 1 in the list `Y`
   V    # Pop and store the updated list in variable `Y` again


6l) Else:, 6m) nextDate.month = 1; and 6n) nextDate.year += 1; are then done like this:

ë        # Else:
 \       #  Delete the top item on the stack (the duplicated month)
  1      #  Push 1
   D     #  Push index 1 (with a Duplicate)
    ǝ    #  Insert 1 at index 1 (month part) in the list `Y`

 ¤       #  Push its tail, the year (without popping the list `Y`)
  &gt;      #  Year + 1
   2     #  Index 2

         # (This part is done after the if-else clauses to save bytes)
}}       # Close the if-else clauses
  ǝ      # Insert the year + 1 at index 2 in the list `Y`
   V     # Pop and store the updated list in variable `Y` again


And finally at 7) If(currentDate == parsed input-string): and 8) Stop the infinite loop, and output the counter:

Y          # Push variable `Y`
 I         # Push the input
  '.¡     '# Split it on dots
     Q     # Check if the two lists are equal
      #    # And if they are equal: stop the infinite loop
           # (And output the top of the stack (the counter) implicitly)