15
\$\begingroup\$

Time sheets

In a work place you often have to complete time sheets. This task is write code to help this.

Input

Two times in a slightly non- standard 12 hour clock signifying the start and end of the day separated by a space. A third number represents the number of minutes taken for lunch. For example

9:14 5:12 30

This means you started work at 9:14am, finished work at 5:12pm and took 30 minutes for lunch.

You can assume that

  • Any time in the first column is from 00:00 (midnight) up to but not including 1pm and any time in the second column is 1pm at the earliest up until 11:59pm.
  • The lunch break is no longer than the working day!

The input format must be as in the examples given.

Task

Your code should read in a file (or standard input) of these triples, and for each one output how long you worked. This output should indicate the number of hours. For the example above this is:

7hr and 58min minus 30 minutes which is 7hr 28min.

Output

Your output must specify the (whole) number of hours and minutes and must not list more than 59 minutes. That is you can't output 2hr 123min. Apart from that, your code can output in any easily human read format that is convenient for you.

Examples

10:00 1:00 30    --> 2hr 30min
12:59 1:00 0     --> 0hr 1min
00:00 11:59 0    --> 23hr 59min
10:00 2:03 123   --> 2hr 0min 
\$\endgroup\$
11
  • 3
    \$\begingroup\$ I don't see how the strict input format (: delimited times on the 12 hour clock) adds anything to this challenge. \$\endgroup\$
    – Shaggy
    Jul 27, 2018 at 20:28
  • 3
    \$\begingroup\$ @Shaggy Parsing the input format was most of the challenge for me at least, because you can't assume character positions since hours could be either one or two characters... \$\endgroup\$
    – Ryan
    Jul 27, 2018 at 20:38
  • \$\begingroup\$ Does the code have to read several lines? Or is it enough if it reads one line? \$\endgroup\$
    – Luis Mendo
    Jul 27, 2018 at 21:11
  • 1
    \$\begingroup\$ Yes the code has to accept multiple lines. \$\endgroup\$
    – user9207
    Jul 27, 2018 at 21:35
  • 5
    \$\begingroup\$ @mbomb007 You can downvote, but not liking the input format is not a reason to VTC. \$\endgroup\$
    – Okx
    Jul 28, 2018 at 21:16

11 Answers 11

7
\$\begingroup\$

MATL, 28 bytes

`jYb0&)YOd.5+wgU13L/- 15XODT

Try it online!

\$\endgroup\$
4
  • 1
    \$\begingroup\$ This is very impressive! \$\endgroup\$
    – user9207
    Jul 27, 2018 at 21:53
  • \$\begingroup\$ Shouldn't the output be in this format "XXhr YYmin"? \$\endgroup\$ Jul 27, 2018 at 23:26
  • \$\begingroup\$ @ibrahimmahrir The challenge says your code can output in any easily human read format that is convenient for you \$\endgroup\$
    – Luis Mendo
    Jul 27, 2018 at 23:29
  • 1
    \$\begingroup\$ Ah, I see! I'm going to edit my answer to shorten it out. Thanks! \$\endgroup\$ Jul 27, 2018 at 23:33
5
\$\begingroup\$

Retina 0.8.2, 83 bytes

\d+
$*
 (1+:)
 12$*1$1
+`1:
:60$*
(1*) :\1(1*)(1*) \2
$3
:(1{60})*(1*)
$#1hr $.2min

Try it online! Link includes test cases. Explanation:

\d+
$*

Convert the input to unary.

 (1+:)
 12$*1$1

Add 12 hours to the stop time.

+`1:
:60$*

Multiply the hours by 60 and add to the minutes.

(1*) :\1(1*)(1*) \2
$3

Subtract the start time and break time from the stop time.

:(1{60})*(1*)
$#1hr $.2min

Divmod by 60. (Save 5 bytes for a more boring output format.)

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

Perl 5 -pl, 80 74 71 bytes

/:(\d+) (\d+):(\d+) /;$m=720+($2-$`)*60+$3-$1-$';$_=($m/60|0).":".$m%60

Try it online!

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

Python 3, 161 bytes

I know this won't even be close to smallest, but it does read in a file:

for l in open('t'):
    l=l[:-1].split(':')
    m=-int(l[0])*60+int(l[1][:2])+(int(l[1][3:])*60+720+int(l[2][:2])-int(l[2][2:]))
    print(f'{m//60}hr {m-(m//60*60)}min')

I'm feeling the irony of pausing my timesheet to do this...

Python 2.7, 133 bytes

Thanks for the suggestions in the comments! Switching to python 2.7 saves a few more bytes because it defaults to integer division:

for l in open('t'):i,h,l=int,60,l[:-1].split(':');m=-i(l[0])*h+i(l[1][:2])+(i(l[1][3:])*h+720+i(l[2][:2])-i(l[2][2:]));print m/h,m%60

The same approach with python3 is 135 bytes because of the print statement and defaulting to float division:

for l in open('t'):i,h,l=int,60,l[:-1].split(':');m=-i(l[0])*h+i(l[1][:2])+(i(l[1][3:])*h+720+i(l[2][:2])-i(l[2][2:]));print(m//h,m%60)
\$\endgroup\$
5
  • 1
    \$\begingroup\$ You could save 4 bytes by putting i=int at the beginning and changing the third line to m=-i(l[0])*60+i(l[1][:2])+(i(l[1][3:])*60+720+i(l[2][:2])-i(l[2][2:])) \$\endgroup\$
    – DJMcMayhem
    Jul 27, 2018 at 20:23
  • \$\begingroup\$ @DJMcMayhem Thank you! I was trying to think of a way to simplify those... \$\endgroup\$
    – Ryan
    Jul 27, 2018 at 20:25
  • 2
    \$\begingroup\$ Very nice first answer, welcome to Programming Puzzles & Code Golf! To help golfing a little, you may be able to take input from STDIN, use map(int,l[:-1].split(':')) and drop the multiple conversions to int, collapse everything to a one-liner by replacing the indentation with ; etc. to save a couple of bytes. Additionally, you can visit Tips for golfing in Python for some more neat tricks other users discovered during their golfer lives :). \$\endgroup\$
    – Mr. Xcoder
    Jul 27, 2018 at 20:27
  • 1
    \$\begingroup\$ Additionally, the OP seems to be less restrictive about the output format, so I think print(m,m%60) would suffice. (Also note the use of m%60 in place of m-(m//60*60)) \$\endgroup\$
    – Mr. Xcoder
    Jul 27, 2018 at 20:33
  • \$\begingroup\$ You can remove most of the indentation and just use one space per line as well. \$\endgroup\$ Jul 28, 2018 at 21:11
4
\$\begingroup\$

C, 105 bytes

a,b,c,d,e;f(){for(;scanf("%d:%d%d:%d%d",&a,&b,&c,&d,&e);)a=(12+c-a)*60+d-b-e,printf("%d:%d ",a/60,a%60);}

Completely straightforward. Try it online here.

Ungolfed:

a, b, c, d, e; // start hours, minutes; end hours, minutes; break - all implicitly int
f() { // function - return type is implicitly int (unused)
    for(; scanf("%d:%d%d:%d%d", &a, &b, &c, &d, &e) ;) // until EOF is hit, read line by line
        a = (12 + c - a) * 60 + d - b - e, printf("%d:%d,", a / 60, a % 60); // calculate the minutes and store, then output separated: "h m"
}
\$\endgroup\$
1
  • \$\begingroup\$ Suggest a,b,c,d;f(e) instead of a,b,c,d,e;f() and ;printf("%d:%d ",a/60,a%60))a=(12+c-a)*60+d-b-e;} instead of ;)a=(12+c-a)*60+d-b-e,printf("%d:%d ",a/60,a%60); \$\endgroup\$
    – ceilingcat
    Oct 25, 2018 at 21:37
4
\$\begingroup\$

Wolfram Language 125 119 111 bytes

i=Interpreter;j=IntegerPart;Row@{j[t=(i["Time"][#2<>"pm"]-i["Time"][#])[[1]]-#3/60],"hr ",j[60Mod[t,1]],"min"}&

8 bytes saved thanks to user 202729

Example

Abbreviations are not used here, to make it easier to follow the logic.

Row[{IntegerPart[
 t = (Interpreter["Time"][#2 <> "pm"] - 
      Interpreter["Time"][#])[[1]] - #3/60], "hr ",
IntegerPart[60 Mod[t,1]], "min"}] &["9:00", "4:12", 20]

6hr 51min

Interpreter["Time"][#2 <> "pm"] interprets as a time the second parameter followed by "pm", namely, in this case, "4:12pm", returning a TimeObject corresponding to 4:12 pm.

-Interpreter["Time"][# <> "am"])[[1]] - #3/60]. #3 is the third parameter, namely 20min. The minus sign subtracts the lunch hour interval from the end of shift time. It returns the adjusted end of shift time, that is, the end of shift that would apply had the person not taken a lunch break.

Interpreter["Time"][#] interprets as a time the first parameter, in this case, "9:00", returning a TimeObject corresponding to 9:00 am.

Subtracting the shift start from the adjusted end of shift time yields t, the time interval expressed in hours. IntegerPart[t] returns the number of complete hours worked. IntegerPart[60 Mod[t,1]], "min"}] returns the additional minutes worked.

\$\endgroup\$
3
  • \$\begingroup\$ Yes. Thanks. First time I see Mod[x, 1] used. \$\endgroup\$
    – DavidC
    Jul 28, 2018 at 23:36
  • \$\begingroup\$ Taken from this (deleted) tips. / Actually mod 1 behaves differently from fractional part for negative number. / Can Floor be used for IntegerPart? \$\endgroup\$
    – DELETE_ME
    Jul 29, 2018 at 0:06
  • \$\begingroup\$ Floor returns a, to me, inexplicable result of -6hr 52min for the sample values I used. I need to look into this to understand why a negative value for hours (and apparently minutes) was produced. \$\endgroup\$
    – DavidC
    Jul 30, 2018 at 11:06
3
\$\begingroup\$

JavaScript, 83 bytes 76 bytes

s=>(r=s.match(/\d+/g),r=(r[2]-r[0]+12)*60-r[4]-r[1]+ +r[3],(r/60|0)+':'+r%60)

Just got rid of the inner funtion from below solution (What was I thinking?). Changed the output format as well.

Try it online!


OLD: JavaScript, 112 bytes 111 bytes 110 bytes

s=>(t=(h,m,a)=>(a?12+h:h)*60+m,r=s.match(/\d+/g),r=t(+r[2],r[3]-r[4],1)-t(r[0],+r[1]),`${r/60|0}hr ${r%60}min`)

Explanation:

Inside the main function, we start by defining another that will help us calculate the minutes of a giving time, adding 12 hours to the hours parameter if the third parameter is truthy:

(hours, minutes, addTwelve) =>
    (addTwelve? hours + 12: hours) * 60 + minutes

Next, we split the string by either ' ' or ':' match the numbers inside the string resulting in an array of all the numbers in the string.

Then we calculate the difference of end time and start time and substracting lunch time using the function defined previously (converting the strings to numbers when needed).

Finally we produce the result string: hours are the integer part of r/60 and minutes are r%60.

Try it online!

\$\endgroup\$
11
  • \$\begingroup\$ @Jakob I'm a new codegolf user. I still don't know how things work around here including the TIO. Also I've asked in this comment how would I approach this using javascript but no one responded. \$\endgroup\$ Jul 27, 2018 at 22:38
  • \$\begingroup\$ @Jakob TIO fixed. And I'm not using NodeJS, I'm using the browser's console. NodeJS was added by TIO. \$\endgroup\$ Jul 27, 2018 at 22:57
  • \$\begingroup\$ Still not sure the input method is legal (this question is unfortunately restrictive), but we may need a more experienced JS golfer to chime in. But also note that programs need to support multiple days of input data--unfortunately that wasn't made very clear in the description. \$\endgroup\$
    – Jakob
    Jul 28, 2018 at 0:59
  • \$\begingroup\$ @Jakob If more days should be used as input I could just make the function accept an array and use map: a=>a.map(...). It will add 5 bytes to my answer. But I'm still waiting for OP (or anyone) response to my comment. \$\endgroup\$ Jul 28, 2018 at 1:05
  • \$\begingroup\$ Since pure JavaScript does not have access to standard input or files, I suggest you go with the default method of using a GUI prompt: codegolf.meta.stackexchange.com/a/2459/79343 \$\endgroup\$ Jul 28, 2018 at 1:48
3
\$\begingroup\$

Python 2, 100 bytes

for I in open('x'):x,y,z,w,l=map(int,I.replace(':',' ').split());d=60*(12+z-x)+w-y-l;print d/60,d%60

Try it online!

Full program that reads multiple lines from a text file, as directed by OP. A function that just parses a single line would save an addition al 10 bytes.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ This is also way more legible than my attempt! \$\endgroup\$
    – Ryan
    Jul 29, 2018 at 15:26
3
\$\begingroup\$

Java 10, 194 191 bytes

u->{var s=new java.util.Scanner(System.in).useDelimiter("\\D");for(int i,a[]=new int[5];;i=(12+a[2]-a[0])*60+a[3]-a[1]-a[4],System.out.println(i/60+":"+i%60))for(i=0;i<5;)a[i++]=s.nextInt();}

I/O is painful in Java. Terminates abnormally when there is no next line of input to read. Try it online here.

Ungolfed:

u -> { // lambda taking a dummy input – we're not using it, but it saves a byte
var s = new java.util.Scanner(System.in).useDelimiter("\\D"); // we use this to read integers from standard input; the delimiter is any character that is not part of an integer
for(int i, a[] = new int[5]; ; // infinite loop; i will be used to loop through each line and to store the result in minutes between lines; a will hold the inputs
    i = (12 + a[2] - a[0]) * 60 + a[3] - a[1] - a[4], // after each line, calculate the result in minutes ...
    System.out.println(i / 60 + ":" + i % 60)) // ... and output the result in hours:minutes, followed by a newline
    for(i = 0; i < 5; ) // read the five integers on the current line ...
        a[i++] = s.nextInt(); // ... into the array
}
\$\endgroup\$
2
\$\begingroup\$

Red, 35 bytes

func[s e l][e + 12:0 - s -(l * 60)]

Try it online!

Note: The output is in the format hh:mm:ss

\$\endgroup\$
2
  • \$\begingroup\$ Wow! This is very surprising :) \$\endgroup\$
    – user9207
    Jul 28, 2018 at 8:07
  • \$\begingroup\$ @Anush Yes, Red (and of course Rebol) has nice time datatype. \$\endgroup\$ Jul 28, 2018 at 8:20
2
\$\begingroup\$

R, 97 bytes

s=matrix(strtoi(unlist(strsplit(scan(,""),':'))),5,,T)%*%c(-60,-1,60,1,-1);paste(12+s%/%60,s%%60)

Try it online!

For each line returns "hours minutes"

  • -16 bytes thanks to JayCe !
\$\endgroup\$
2

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.