14
\$\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\$
  • 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 '18 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 '18 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 '18 at 21:11
  • 1
    \$\begingroup\$ Yes the code has to accept multiple lines. \$\endgroup\$ – Anush Jul 27 '18 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 '18 at 21:16

11 Answers 11

7
\$\begingroup\$

MATL, 28 bytes

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

Try it online!

\$\endgroup\$
  • 1
    \$\begingroup\$ This is very impressive! \$\endgroup\$ – Anush Jul 27 '18 at 21:53
  • \$\begingroup\$ Shouldn't the output be in this format "XXhr YYmin"? \$\endgroup\$ – ibrahim mahrir Jul 27 '18 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 '18 at 23:29
  • 1
    \$\begingroup\$ Ah, I see! I'm going to edit my answer to shorten it out. Thanks! \$\endgroup\$ – ibrahim mahrir Jul 27 '18 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\$
  • 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 '18 at 20:23
  • \$\begingroup\$ @DJMcMayhem Thank you! I was trying to think of a way to simplify those... \$\endgroup\$ – Ryan Jul 27 '18 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 '18 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 '18 at 20:33
  • \$\begingroup\$ @Mr.Xcoder Thanks! \$\endgroup\$ – Ryan Jul 27 '18 at 20:39
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\$
  • \$\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 '18 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\$
  • \$\begingroup\$ Yes. Thanks. First time I see Mod[x, 1] used. \$\endgroup\$ – DavidC Jul 28 '18 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\$ – user202729 Jul 29 '18 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 '18 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\$
  • \$\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\$ – ibrahim mahrir Jul 27 '18 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\$ – ibrahim mahrir Jul 27 '18 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 '18 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\$ – ibrahim mahrir Jul 28 '18 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\$ – O.O.Balance Jul 28 '18 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
    \$\begingroup\$ This is also way more legible than my attempt! \$\endgroup\$ – Ryan Jul 29 '18 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\$
  • \$\begingroup\$ Wow! This is very surprising :) \$\endgroup\$ – Anush Jul 28 '18 at 8:07
  • \$\begingroup\$ @Anush Yes, Red (and of course Rebol) has nice time datatype. \$\endgroup\$ – Galen Ivanov Jul 28 '18 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\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.