The Work Day Countdown

17

I just had I 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 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 <- but it's not beautiful
  • No need for respecting DST

Hille

Posted 2018-10-01T11:27:24.343

Reputation: 349

9

Is there any specific reason behind this "unofficial" European input format? Our consensus is to allow flexible input whenever possible.

– Arnauld – 2018-10-01T11:36:50.360

1@Arnauld because most of the date methods I know are in a specific format and I don't know any method which will use the dd.MM.yyyy immediately -> it may make the task a bit more challenging. May there are some disadvantages for some languages, but I don't know any language which will profit out of this rule :) – Hille – 2018-10-01T11:39:42.283

1I feel like the example should output 4 since until the start of 17.12.2018 (Mon) there are only four whole weekdays (i.e. today, 10.12.2018, should not be counted as soon as we've entered it). – Jonathan Allan – 2018-10-01T11:58:42.350

@JonathanAllan but I wont to have all days left so if its the last day before the date it should be 1 and not 0 :) – Hille – 2018-10-01T12:15:07.940

@Hille if we run it today at 23:00 with an input of tomorrow do we really have 1 day?! – Jonathan Allan – 2018-10-01T12:29:10.273

So, what should be the output for Sunday / Saturday? And should public holidays be considered? – tsh – 2018-10-01T12:33:27.637

@JonathanAllan, as far as I know, does the 0 marks that it is over / the goal is reached, so I don't think that it makes sense to mark one day left as 0? Or? – Hille – 2018-10-01T13:05:00.573

@tsh as they don't count the end date is set to friday and no public holidays should not be considered as they are different in every country. – Hille – 2018-10-01T13:06:13.500

6Is there really any point in adding the "extra challenge" of a hard to process date format? That just seems unfair w.r.t. languages that have flexible date formats... – Quintec – 2018-10-01T13:25:54.523

1@Quintec it isn't as hard as you say, there are just a few extra bits and bytes for reformatting it :P – Hille – 2018-10-01T13:28:48.703

3@Hille I did not say it was "hard", it just is an unnecessary hassle, especially in code-golf...do note the link that Arnauld posted above... generally flexible input is the norm... – Quintec – 2018-10-01T13:31:26.747

@tsh holidays will depend on locale, so I wouldn't go there. – ngm – 2018-10-01T13:50:36.633

1@Quintec sry but that's the task. I don't want to have any input format so that specific code golf languages got a big advantage :) – Hille – 2018-10-01T13:57:30.850

6

By the way, you note that this is your first challenge; I invite you to use The Sandbox for refinement before posting a challenge to main! Otherwise, nice work, and I'll enjoy seeing some more from you!

– Giuseppe – 2018-10-01T16:49:47.903

Can we return false instead of 0? – Shaggy – 2018-10-01T18:40:27.623

7Not really impressed by the strict input format but other than that a good challenge. – ElPedro – 2018-10-01T19:52:17.117

@Shaggy not the beuautifullest solution but i think its ok :) – Hille – 2018-10-02T05:54:37.243

Thanks, saved me a byte. You should update the challenge to include that in the spec. – Shaggy – 2018-10-02T07:54:21.817

1A lot of people are complaining about the strict input format. I didn't think it was a problem. Sure, 50% of the characters in my solutions are about dealing with the format, but on the other hand, if I could just write DayCount[Today,#,"Weekdays"]& then I'd have nothing to golf :) And as the 05AB1E solution shows, dealing with a problem your language doesn't handle for you can be a fun challenge. But the format game is bad if it's done too often - the next time I have a date in the wrong format, I'll do the same thing - so this is something to use sparingly. – Misha Lavrov – 2018-10-03T17:08:06.747

Saturday to Sunday is 0, no doubt. But I guess that Friday -> Saturday and Sunday -> Monday are both 1. I suggest additional examples for clarification. – Titus – 2018-10-04T15:02:45.930

Oh and what about Friday to Monday? One workday or two? – Titus – 2018-10-04T16:43:07.693

"I don't know any method which will use the dd.MM.yyyy immediately" ... I know one. ;) Oh and one more question: Do we have to respect DST? – Titus – 2018-10-04T17:10:19.810

@Titus No, you don't need to respect DST and From Friday -> Sa / Su is 0 days because you do not have to work until the date and for Mo, it's 1. – Hille – 2018-10-04T18:49:08.970

Answers

18

05AB1E, 130 128 133 131 124 123 bytes

žežfžg)V0[Y`UÐ3‹12*+>13*5÷s3‹Xα©т%D4÷®т÷©4÷®·()ćsO7%2@+Y`т‰0Kθ4ÖUD2Qi\28X+ë<7%É31α}‹iY¬>0ëY1¾ǝDÅsD12‹i>1ë\1Dǝ¤>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)..

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`
   Ð          # Triplicate the month
    3‹        # Check if the month is below 3 (Jan. / Feb.),
              # resulting in 1 or 0 for truthy/falsey respectively
      12*     # Multiply this 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
 13*          # Multiplied by 13
    5÷        # Integer-divided by 5
s3‹           # Check if the month is below 3 again (resulting in 1 / 0)
   Xα         # Take the absolute difference with the year
     ©        # Store this potentially modified year in the register
      т%      # 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 >=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 < daysInCurrentMonth):
g     nextDate.day += 1;
h   Else:
i     nextDate.day = 1;
j     If(currentDate.month < 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 "00" (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:
 <          #  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 < 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`)
  >     # 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 < 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;:

>       # 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`)
  >      #  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 8) If(currentDate == parsed input-string): and 9) 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)

Kevin Cruijssen

Posted 2018-10-01T11:27:24.343

Reputation: 67 575

5You're a madman ... have an upvote. – AdmBorkBork – 2018-10-01T17:54:58.813

1Longest 05AB1E program ever? – Luis Mendo – 2018-10-01T18:31:01.907

2

@LuisMendo Close, but I'm afraid I have one 05AB1E answer myself that is even longer, and one that comes way too close.. ;) I'm sure I'll be able to golf a few bytes here an there and simplify parts of the pseudo-code implementation of the next day. Will look tomorrow morning, but just came back from sport and will go to bed soon.

– Kevin Cruijssen – 2018-10-01T21:00:20.667

11

R, 76 bytes

Please also have a look at this 72 byte R answer that is also locale-independent.

sum(!grepl("S",weekdays(seq(Sys.Date(),as.Date(scan(,""),"%d.%m.%Y"),1))))+1

Try it online!

weekdays gives text days of week, so we count the days in the sequence between today and the input that do not contain S, and add one to the result.

ngm

Posted 2018-10-01T11:27:24.343

Reputation: 3 974

11

Excel 24 Bytes

Assumes input in Cell A1

=NETWORKDAYS(NOW()+1,A1)

Uses built-in function. Unfortunately the function includes both today and the end date. OP has since clarified to not count today, so I add one to NOW so as to not count today.

To address comments on format of number, again, this is Excel standard: enter image description here

Keeta - reinstate Monica

Posted 2018-10-01T11:27:24.343

Reputation: 938

While this works with date values, it fails to take input as stated. That is (at least in the US version) 10.12.2018 is a string when held in a cell rather than a date. The obvious but long solution to correct this would be to change A1 to DATE(RIGHT(A1,4),MID(A1,4,2),LEFT(A1,2)) in your solution – Taylor Scott – 2018-10-01T19:57:44.977

unfortunately, the community has decided that languages need to be run under their default settings to be valid (the one exception that I have seen to this is language - IE, if your language supports both English and Spanish, you may readily use either, but this must be noted.) Further, OP (@hille) has not stated that format is flexible, and has in fact stated quite the opposite (see second comment on this question) – Taylor Scott – 2018-10-02T18:40:48.117

2The format is not standard, it's locale-based. Excel reads the format from the HKCU\Control Panel\International\sDecimal registry string. On a default US Windows installation that's MM/dd/yyyy. In most EU countries this would be the default. – Erik A – 2018-10-03T07:42:08.520

@luisMendo Yes, that works. I didn't see any clarification. If it had been to not count last day instead, I could have =NETWORKDAYS(NOW(),A1-1). I knew it would always be the same byte count no matter which clarification. – Keeta - reinstate Monica – 2018-10-03T16:02:28.960

Glad that works. I removed the downvote – Luis Mendo – 2018-10-03T16:28:40.403

8

Java 10, 233 232 226 bytes

import java.util.*;d->{int r=0;var s=Calendar.getInstance();s.setTime(new Date());var e=s.getInstance();for(e.setTime(new java.text.SimpleDateFormat("dd.MM.yyyy").parse(d));!s.after(e);s.add(5,1))if(s.get(7)%7>1)r++;return r;}

Date always reminds me how verbose Java really is..

NOTE: There are now two shorter Java answers (below 175 bytes), one with smart use of deprecated methods from earlier Java versions by @LukeStevens, and one using the java.time.LocalDate that's new since Java 8 by @OlivierGrégoire.

Try it online.

Explanation:

import java.util.*;            // Required import for both Calendar and Date
d->{                           // Method with String parameter and integer return-type
  int r=0;                     //  Result-integer, starting at 0
  var s=Calendar.getInstance();//  Create a Calendar instance for the start-date
  s.setTime(new Date());       //  Set the start date to today
  var e=s.getInstance();       //  Create a Calendar instance for the end-date
  for(e.setTime(               //  Set the end date to:
        new java.text.SimpleDateFormat("dd.MM.yyyy")
                               //   Create a formatter for the "dd.MM.yyyy" format
         .parse(d));           //   And parse the input-String to a Date
      !s.after(e)              //  Loop as long as we haven't reached the end date yet
      ;                        //    After every iteration:
       s.add(5,1))             //     Increase the start-date by 1 day
    if(s.get(7)%7>1)           //   If the day of the week is NOT a Saturday or Sunday:
                               //   (SUNDAY = 1, MONDAY = 2, ..., SATURDAY = 7)
      r++;                     //    Increase the result-sum by 1
  return r;}                   //  Return the result-sum

Kevin Cruijssen

Posted 2018-10-01T11:27:24.343

Reputation: 67 575

Could you do e=s.clone()? – Quintec – 2018-10-01T18:51:36.953

@Quintec Yes and no. s.clone() returns an Object and it expects a Calendar object. So I could use e=(Calendar)s.clone(), but I'm afraid that increases the byte-count instead of decreasing it. – Kevin Cruijssen – 2018-10-01T20:55:09.637

1We can also (I assume) do Calendar s=Calendar.getInstance(),e=s.getInstance(), which unfortunately ends up being exactly the same length. – Misha Lavrov – 2018-10-02T01:01:56.383

1@MishaLavrov Ah, the static C indeed isn't necessary. It was from an old part of the code where I also used C somewhere else. Been able to golf 1 byte by using var s=Calendar.getInstance();var e=s.getInstance(); so thanks. :) – Kevin Cruijssen – 2018-10-02T06:50:29.380

1150 bytes, using java.time. – Olivier Grégoire – 2018-10-02T11:35:02.037

@OlivierGrégoire The input format should be dd.MM.yyyy instead of yyyy.MM.dd. Apart from that it's a nice answer, but you can post it yourself if you want. It's too different from mine (and also too different from the other Java answer). – Kevin Cruijssen – 2018-10-02T11:41:45.813

1Done! It's very close in bytes to the other answer, but doesn't beat it yet. – Olivier Grégoire – 2018-10-02T11:58:32.733

7

JavaScript (ES6), 116 103 bytes

f=(d,n=+new Date)=>(D=new Date(n)).toJSON()<d.split`.`.reverse().join`-`&&(D.getDay()%6>0)+f(d,n+864e5)

Try it online!

How?

A JavaScript timestamp is defined as the number of milliseconds elapsed since the UNIX epoch. The current timestamp is hold in the variable \$n\$.

At each iteration, we use \$n\$ to generate a date \$D\$ (as a JavaScript object). This date is converted to ISO 8601 format with the .toJSON() method:

YYYY-MM-DDThh:mm:ss.sssZ

Since this string starts with YYYY-MM-DD, it is safe to perform a lexicographical comparison with another string in a similar format. This is why we want to convert the input string \$d\$ to YYYY-MM-DD rather than converting our computed date to the input string format DD.MM.YYYY (which cannot be sorted lexicographically):

d.split`.`.reverse().join`-`

Before each recursive call, we increment the final result if D.getDay() is neither \$0\$ (Sunday) nor \$6\$ (Saturday), i.e. if it's not congruent to \$0\$ modulo \$6\$:

(D.getDay() % 6 > 0) + f(d, n + 864e5)

We add \$86,400,000\$ milliseconds to \$n\$ to reach the next day.

Arnauld

Posted 2018-10-01T11:27:24.343

Reputation: 111 334

6

Wolfram Language (Mathematica), 64 56 bytes

DayCount[Today,""<>#~StringTake~{{4,6},3,-4},"Weekday"]&

Try it online!

DayCount[x,y,"Weekday"] counts the number of weekdays between x and y.

The inputs x and y can be many things, including a fancy DateObject like the one returned by Today, or a string in the format (unfortunately) mm.dd.yyyy.

My previous attempt tried to turn the dd.mm.yyyy input into a DateObject by telling Mathematica how to parse it; the new solution simply rearranges the string to put day and month in the order Mathematica expects.

It's worth noting that the 28-byte solution DayCount[Today,#,"Weekday"]& not only works perfectly for a month-day-year input format, but also correctly handles unambiguous day-month-year inputs such as 31.12.2018, which couldn't possibly mean "the 12th day of the 31st month". So it's correct more than 60% of the time :)

Misha Lavrov

Posted 2018-10-01T11:27:24.343

Reputation: 4 846

6

MATL, 24 bytes

46tQZt24&YO:Z':X-9XO83-z

Try it online!

I don't want to have any input format so that specific code golf languages got a big advantage

You half succeeded :-)

Explanation

46      % Push 46 (ASCII for '.')
tQ      % Duplicate, add 1: gives 47 (ASCII for '/')
Zt      % Implicit input. Replace '.' by '/' in the input string
24&YO   % Convert string with date format 24 ('dd/mm/yyyy') to serial date number.
        % This is an integer representing day starting at Jan-1-0000
:       % Inclusive range from 1 to that
Z'      % Push current date and time as a serial number. Integer part is day;
        % decimal part represents time of the day
:       % Inclusive range from 1 to that
X-      % Set difference. Gives serial numbers of days after today, up to input
9XO     % Convert each number to date format 9, which is a letter for each day
        % of the week: 'M', 'T', 'W', 'T', ' F', 'S', 'S'
83-     % Subtract 83 (ASCII for 'S')
z       % Number of nonzeros. Implicit display

Luis Mendo

Posted 2018-10-01T11:27:24.343

Reputation: 87 464

If I understood the challenge correctly, you only take one date input, and compare it to today's date. For example, 16.10.2018 would today (Monday 01-10-2018) result in 11, tomorrow in 10, etc. – Kevin Cruijssen – 2018-10-01T16:35:41.063

@KevinCruijssen Whoops. Thanks! Corrected now – Luis Mendo – 2018-10-01T16:47:03.393

1And with the same byte-count. :) Nice, +1 from me. – Kevin Cruijssen – 2018-10-01T16:52:31.633

5

Perl 6, 61 bytes

{+grep 6>*.day-of-week,Date.today^..Date.new(|[R,] m:g/\d+/)}

Try it online!

nwellnhof

Posted 2018-10-01T11:27:24.343

Reputation: 10 037

5

Java (OpenJDK 8), 174 166 165 bytes

With a bit of inspiration from Kevin's answer and a good ol' trawl through the deprecated Date API, I've managed to get a more succinct Java solution.

-8 bytes thanks to Kevin's inventive regex date parsing

-1 bytes thanks to Nevay's clever bitwise operation

import java.util.*;d->{long r=0,s=new Date().getTime(),e=Date.parse(d.replaceAll("(..).(..).","$2/$1/"));for(;s<=e;s+=864e5)r-=-new Date(s).getDay()%6>>-1;return r;}

Try it online!

Explanation

import java.util.*;                         // Required import for Date 
long r=0,                                   // Initialise result variable
     s=new Date().getTime(),                // Current date in millis
     e=Date.parse(
         d.replaceAll("(..).(..).","$2/$1/")// Use regex to convert to MM/dd/yyyy
     );                                     // Parse date arg using deprecated API
for(;s<=e;                                  // Loop while current millis are less than date arg (e.g. date is before)       
    s+=864e5)                               // Add 86400000 ms to current date (equiv of 1 day)
    r-=-new Date(s).getDay()%6>>-1;        // If day is Sunday (0) or Saturday (6) don't increment, else add 1
return r;                                   // When loop finished return result

Luke Stevens

Posted 2018-10-01T11:27:24.343

Reputation: 979

1Nice answer! Smart use of the varargs with the d=d[0].split and the deprecated .parse with default format MM/dd/yyyy format. One small mistake in your post, you have import java.text.*; instead of import java.util.*; in your code, and // Required import for both Calendar and Date in your explanation (even though you don't use Calendar). – Kevin Cruijssen – 2018-10-02T09:02:27.947

@KevinCruijssen No idea why I had java.text but fixed now! Thanks! – Luke Stevens – 2018-10-02T09:10:31.800

1

Although I liked the d=d[0].split with the varargs, changing the input to a regular String, removing d=d[0].split("\\."); and changing d[1]+"/"+d[0]+"/"+d[2] to d.replaceAll("(..).(..).","$2/$1/") saves 7 bytes.

– Kevin Cruijssen – 2018-10-02T12:05:13.903

1

And 1 more byte by changing r+=new Date(s).getDay()%6<1?0:1,s+=864e5); to s+=864e5)r+=new Date(s).getDay()%6<1?0:1;. :)

– Kevin Cruijssen – 2018-10-02T12:07:25.427

Cheers! I didn't even realise you could do that with the regex in Java – Luke Stevens – 2018-10-02T13:03:20.177

1-1 byte: r-=-new Date(s).getDay()%6>>-1; – Nevay – 2018-10-03T16:03:11.163

5

R, 72 chars

A variation on the answer provided by @ngm which avoids the grepl to save a few characters and works in non-English locales.

sum(strftime(seq(Sys.Date(),as.Date(scan(,""),"%d.%m.%Y"),1),'%u')<6)+1

Neal Fultz

Posted 2018-10-01T11:27:24.343

Reputation: 151

1Shorter and more general too. Nice answer and welcome to the asylum. – ngm – 2018-10-04T14:26:37.027

1

Welcome to PPCG! you can add a TIO link - it's easy and formats the answer for you :)

– JayCe – 2018-10-04T19:32:57.713

4

Red, 72 bytes

func[a][b: now/date s: 0 until[if b/weekday < 6[s: s + 1]a < b: b + 1]s]

Try it online!

Takes the date in format dd-mm-yyyy, for example 31-10-2018 (also works with 10-Oct-2018)

Strict input:

Red, 97 bytes

func[a][a: do replace/all a".""-"b: now/date s: 0 until[if b/weekday < 6[s: s + 1]a < b: b + 1]s]

Try it online!

Bonus:

Returns a list of the dates/weekdays of the working days up to the given date:

Red, 235 bytes

f: func [ a ] [
    b: now/date
    d: system/locale/days
    collect [ 
        until [ 
            if b/weekday < 6 [ 
                keep/only reduce [ b ":" d/(b/weekday) ]
            ]
            a < b: b + 1
        ]
    ]
]

Try it online!

Galen Ivanov

Posted 2018-10-01T11:27:24.343

Reputation: 13 815

Agh, no fair, in python I need to spend about 72 bytes processing this IO format... :P – Quintec – 2018-10-01T13:15:13.150

1Usually my Red solutions are among the longest ones, but fortunately Red deals very well with dates :) – Galen Ivanov – 2018-10-01T13:17:25.983

190 bytes to process python... i'm done, I quit until there's a more flexible input format :P – Quintec – 2018-10-01T13:20:16.987

4

JavaScript, 87 85 bytes

Returns false for 0.

s=>([d,m,y]=s.split`.`,g=_=>new Date<(x=new Date(y,~-m,d--))&&(x.getDay()%6>0)+g())()

Try it online or check the next 31 days

Shaggy

Posted 2018-10-01T11:27:24.343

Reputation: 24 623

3

JavaScript (Node.js), 168 160 139 133 bytes

35 bytes less thanks to Quintec and Kevin Cruijssen

D=>{var i=D.split('.'),n=0;for(var d=new Date();d<=new Date(i[2],i[1]-1,i[0]);d.setDate(d.getDate()+1))n+=-~d.getDay()%7>1;return n;}

Try it online!

D=>{
  var i=D.split('.'),                 // Splits the date string by .
      n=0;                            // Counter variable
  for(var d=new Date();               // For the actual date
      d<=new Date(i[2],i[1]-1,i[0]);      // As long as the date is less or equal the requested date
      d.setDate(d.getDate()+1))           // Count the date one up
    n+=-~d.getDay()%7>1;                // If the date is not a Sunday or Saturday
  return n;                           // Return the counter variable
}

Hille

Posted 2018-10-01T11:27:24.343

Reputation: 349

1158 bytes with lambda – Quintec – 2018-10-01T14:04:50.017

1139 bytes with improved if condition – Quintec – 2018-10-01T14:10:19.047

1

Since your method isn't recursive, you don't need to add the f= to the byte-count (and on TIO you can put it in the header), which is why @Quintec stated it's 139 bytes instead of 141 bytes. In addition, you can change if((d.getDay()+1)%7>1)n++; to n+=-~d.getDay()%7>1; to golf it to 133 bytes.

– Kevin Cruijssen – 2018-10-01T14:36:24.410

1Here the relevant tip why -~i is the same as (i+1) Also, if you haven't seen it yet, Tips for golfing in JavaScript and Tips for golfing in <all languages> might be interesting to read through. :) – Kevin Cruijssen – 2018-10-01T14:39:22.610

@KevinCruijssen and Quintec that's awesome, thanks – Hille – 2018-10-01T14:45:38.563

97 bytes – Shaggy – 2018-10-01T17:44:33.243

@Shaggy At this point it's worth a new answer... :P You even outgolfed the other JS answer! – Quintec – 2018-10-01T18:53:25.040

@Quintec, already posted it after some more golfing. – Shaggy – 2018-10-01T18:54:16.190

@Shaggy Ah, gotcha, didn't see it. – Quintec – 2018-10-01T18:55:33.870

1A few more tips for future reference. – Shaggy – 2018-10-02T07:47:36.860

3

Python 2, 163 156 149 147 bytes

lambda s:sum((date.today()+timedelta(x)).weekday()<5for x in range((date(*map(int,(s.split(".")[::-1])))-date.today()).days))
from datetime import*

Try it online!

-7 with thanks to @mypetlion

-7 more with thanks to @ovs

+30 due to the very restrictive input format which I only noticed just before I posted my previous code which took input as e.g. (2018,11,1) :-(

ElPedro

Posted 2018-10-01T11:27:24.343

Reputation: 5 301

2No need for this: (0,1)[t.weekday()<5]. Python booleans are a subclass of int and True, False can be used in arithmetic operations as 1,0. Replace it with c+=t.weekday()<5 to save 7 bytes. – mypetlion – 2018-10-01T15:50:51.093

1149 bytes as a lambda. – ovs – 2018-10-01T16:48:30.003

Thanks @mypetlion. I shouldn't have missed that one. – ElPedro – 2018-10-01T17:32:38.863

Thanks @ovs. Second time you have helped recently. Last time was a very impressive -30. Was trying to work out how to get this into a lambda. – ElPedro – 2018-10-01T17:37:26.077

3

Python3 & Numpy, 96 bytes

I couldn't get smaller than the boring pre-made solution...

from numpy import*
d=datetime64
lambda s:busday_count(d('today'),d(f'{s[6:]}-{s[3:5]}-{s[:2]}'))

Try it online!

Aaron

Posted 2018-10-01T11:27:24.343

Reputation: 1 213

Must get into Python 3 ;) – ElPedro – 2018-10-01T21:25:55.827

Based on your import, you are not using Python 3, but rather Python 3 with numpy. – Jonathan Frech – 2018-10-01T23:30:39.333

@JonathanFrech should that be in the title? others using python also have used a library as python has no builtin datatype for dates or times. – Aaron – 2018-10-02T13:32:18.873

1This depends on your definition of builtin -- modules like datetime are standard library modules and thus I would count them as being part of the core language. However, when one uses third-party modules like numpy, one enhances the language's capabilities and therefore I would see it as another language. – Jonathan Frech – 2018-10-02T15:57:51.693

3

Java (JDK 10), 171 bytes

s->{int c=0;for(var t=java.time.LocalDate.now();!t.parse(s.replaceAll("(..).(..).(.*)","$3-$2-$1")).equals(t);t=t.plusDays(1))c-=t.getDayOfWeek().getValue()/6-1;return c;}

Try it online!

Credits

Olivier Grégoire

Posted 2018-10-01T11:27:24.343

Reputation: 10 647

1You can change the (.*)\\.(.*)\\.(.*) to (..).(..).(.*). – Kevin Cruijssen – 2018-10-02T12:00:29.820

With your replaceAll technique his answer can be golfed by 7 bytes as well however, so yours is still slightly longer. ;) – Kevin Cruijssen – 2018-10-02T12:05:45.583

@KevinCruijssen Thanks for the regex! And no worries: I don't mind having a longer answer ;) – Olivier Grégoire – 2018-10-02T12:16:23.980

2

PowerShell, 107 99 bytes

-8 bytes thanks to mazzy

$d,$m,$y=$args-split'\.';for($a=date;$a-lt(date "$y-$m-$d");$a=$a|% *ys 1){$o+=($a|% D*k)-in1..5}$o

Try it online!

Performs a regex -split on the input $args, stores the values into $days, $months, and $years, respectively. Then, enters a for loop, initializing $a to today's date. The loop continues while $a is -lessthan our input target date. Each iteration we're adding 1 days to $a, and checking whether the current D*k (short for DayOfWeek) is in the range 1..5 (i.e., Monday to Friday). That Boolean result is accumulated into $o and once we're out of the loop that value is left on the pipeline and output is implicit.

AdmBorkBork

Posted 2018-10-01T11:27:24.343

Reputation: 41 581

100 bytes? $d,$m,$y=$args-split'\.';for($a=date;$a-lt(date "$y-$m-$d");$a=$a|% *ys 1){$o+=($a|% D*k)-in1..5};$o – mazzy – 2018-10-01T19:02:27.007

1@mazzy Indeed. Plus, the semicolon between for(...){...} and $o can be removed, so we're now below 100! – AdmBorkBork – 2018-10-01T19:11:15.363

2

Python 2, 147 143 141 140 bytes

from datetime import*
lambda e,s=date.today():sum((s+timedelta(x+1)).weekday()<5for x in range((date(*map(int,e.split(".")[::-1]))-s).days))

Try it online!

Takes a string, e, which represents the end date in the format "dd.MM.YYYY". Optionally also takes the start date, but this is expected to be a datetime.date.

The start date, s, is defaulted to today's date as a datetime.date object in order to disregard time. The end time is parsed into a datetime.datetime object then converted to a date, since datetime.date objects do not have a parse method and datetimes cannot be added to/subtracted from dates. Iterates through every day in (start, end] and adds 1 to the total if its weekday number is < 5. ([0-4] are [Mon-Fri], [5-6] are [Sat-Sun]).

Datetime parsing is the worst, you guys.

EDIT: Stole ElPedro's map(int,thing) trick to save 4 bytes.

EDIT 2: ELECTRIC BOOGALOO: Saved 2 bytes by making it an anonymous function. (Thanks Aaron!)

EDIT 3: xrange -> range. (Thanks again Aaron!)

Triggernometry

Posted 2018-10-01T11:27:24.343

Reputation: 765

1You're welcome! Nice answer :) – ElPedro – 2018-10-01T17:54:27.343

1It is convention you can leave off the f= from lambda expressions here – Aaron – 2018-10-01T18:53:52.770

1"Datetime parsing is the worst, you guys" Hahahaha feel my pain, you succeeded where I failed though :P – Quintec – 2018-10-01T18:54:42.640

@Aaron I'm never sure if that's okay with multiple functions or with import statements, thanks! – Triggernometry – 2018-10-01T18:57:33.463

1You can also use range rather than xrange it should still work just fine. – Aaron – 2018-10-01T19:12:59.127

2

PHP, 66 bytes

for($t=time();$t<strtotime($argn);)$r+=date(N,$t+=86400)<6;echo$r;

empty output for 0; insert + between echo and $r to fix.

Run as pipe with -nr or try it online.


60 bytes with unary output:

for($t=time();$t<strtotime($argn);)echo date(N,$t+=86400)<6;

Titus

Posted 2018-10-01T11:27:24.343

Reputation: 13 814

1

C (clang), 209 208 205 bytes

Compiler flags -DU=u=localtime(&b) -DW=tm_wday -DY=tm_year -DT=tm_yday (52 bytes).

#import<time.h>
i;f(char*a){long b;struct tm t,*u;time(&b);U;strptime(a,"%d.%m.%Y",&t);for(i=0;u->T^t.T|u->Y^t.Y;u->W&&u->W^6&&i++,b+=86400,U);return i;}

Try it online!

-1 byte thanks to @JonathanFrech

Logern

Posted 2018-10-01T11:27:24.343

Reputation: 845

?i++:0 -> &&++i. – Jonathan Frech – 2018-10-01T23:33:04.560

1

IBM/Lotus Notes Formula - 99 bytes

d:=i;c:=0;@While(d>@Today;@Set("c";c+@If(@Weekday(d)=1:7;0;1));@Set("d";@Adjust(d;0;0;-1;0;0;0)));c

Takes input from a date/time field i. The input format of i is set to . separated so there is no need to convert the input. Notes can take a date input with any separator as long as you tell it before what it is going to be (hope that's not cheating!). Formula is in computed numeric field o on the same form.

Interesting aside: Ever since @For and @While were introduced into the Formula language in (I think) R6 by the great Damien Katz the only use I have found for them is code golfing. I have never used them in a production app.

There is no TIO available for formula so here is a screenshot taken on 02.10.2018:

enter image description here

ElPedro

Posted 2018-10-01T11:27:24.343

Reputation: 5 301

1

PHP (with Carbon), 107 bytes

function a($d){return Carbon\Carbon::parse($d)->diffInDaysFiltered(function($e){return!$e->isWeekend();});}

Daniel

Posted 2018-10-01T11:27:24.343

Reputation: 1 808

1

Ruby, 81 bytes

->e{require'date';(Date.today...Date.strptime(e,'%d.%m.%Y')).count{|d|6>d.cwday}}

Try it online!

Idva

Posted 2018-10-01T11:27:24.343

Reputation: 97

1

K4, 40 bytes

Solution:

{+/1<.q.mod[d+!(."."/:|"."\:x)-d:.z.d]7}

Explanation:

Calculate the difference between the dates, use modulo 7 to ignore weekends, sum up.

{+/1<.q.mod[d+!(."."/:|"."\:x)-d:.z.d]7} / the solution
     .q.mod[                         ]7  / modulo with 7
                                 .z.d    / UTC date
                               d:        / save as d
                              -          / subtract from
               (             )           / do this together
                       "."\:x            / split input on "."
                      |                  / reverse
                 "."/:                   / join back with "."
                .                        / take the value
              !                          / range 0..the difference
            d+                           / add today's date to range
   1<                                    / is 1 less than the modulo (ie is this mon-fri)?
 +/                                      / sum up

Notes:

  • same byte alternative to the date parsing: "D"$,/|"."\:x

streetster

Posted 2018-10-01T11:27:24.343

Reputation: 3 635

0

q, 52 79 bytes

{x:"D"$"."sv reverse"."vs x;i:0;while[x-.z.d;$[2>x mod 7;x-:1;[i+:1;x-:1]]];:i}

in q, each date has an underlying integer value, based on how many days have passed since the start of the millenium. Applying 'mod 7' to this, you get unique values for each day of the week (0 for Saturday, 6 for Friday). So when 2 > x mod 7, don't increment the counter, to avoid counting weekends.

EDIT: Missed strict date format, editing

EDIT2: Included

Thaufeki

Posted 2018-10-01T11:27:24.343

Reputation: 421

1Best I've come up with is {sum 1<mod[d+til("D"$x 10 vs 67893401)-d:.z.d]7} for 48 bytes without resorting to K verbs. – streetster – 2018-10-04T20:03:21.240

Using the list indices is a lot more elegant than reverse, and rather than using a loop, applying mod to the list. Great answer +1 – Thaufeki – 2018-10-05T01:11:21.273