9
\$\begingroup\$

I work a standard nine to five. Monday through Friday. I take a half hour for lunch from 12:30 to 13:00.

Write me a program which, when run, calculates the percentage of the working week that I have completed at the current moment.

Rules

  • Only count time actually spent working. I am punctual and do not work over lunch.
  • No input. You may obtain information like current time/date however is convenient.
  • The working week is considered complete from end-of-day Friday to midnight between Sunday and Monday.
  • Timezone is the local timezone.
  • Output should be a decimal number, eg 66.25498, percentage symbol optional.
  • The program should be reasonably future-proof. It should be able to cope with leap years.
  • Output resolution should be a second or better. I like to watch the kettle boil.
  • Code golf. Shortest code wins.
asked Aug 16, 2012 at 15:45
\$\endgroup\$
7
  • 1
    \$\begingroup\$ What's your time zone? System local? GMT? Oh, and is that midnight between Saturday and Sunday or Sunday and Monday? \$\endgroup\$ Commented Aug 16, 2012 at 15:50
  • \$\begingroup\$ I updated the rules. Local time, and the Sunday/Monday midnight. \$\endgroup\$ Commented Aug 16, 2012 at 15:55
  • \$\begingroup\$ Are you earning wages during lunch break? \$\endgroup\$ Commented Aug 16, 2012 at 20:07
  • \$\begingroup\$ I don't think that would make a difference? \$\endgroup\$ Commented Aug 16, 2012 at 20:48
  • \$\begingroup\$ if you are at lunch, you are not working, therefore, I guessed at a 37.5 hour work week \$\endgroup\$ Commented Aug 16, 2012 at 20:51

9 Answers 9

5
\$\begingroup\$

Python 3, 132

from datetime import*
t=datetime.now().timetuple()
m=max(0,t[3]*2+t[4]/30-18)
print(20*min(5,(t[6]+min(15,m-min(8,max(7,m))+7)/15)))

The resolution is one minute, or 2/45 of a percent. That's more than enough IMO.

answered Aug 16, 2012 at 18:26
\$\endgroup\$
5
\$\begingroup\$

Excel, (削除) 132 (削除ここまで), (削除) 129 (削除ここまで), (削除) 123 (削除ここまで),(削除) 119 (削除ここまで), 117

paste into A2:A4

=NOW()
=A2-INT(A2)-.375
=(WEEKDAY(A2,3)*7.5+IF(A3<0,0,IF(A3>TIME(8,0,0),7.5,(A3-IF(A3>.1875,TIME(0,30,0),0))*24)))/37.5

format the cell A4 as % to get the correct format

40 hour workweek-Paid lunch:

(削除) 88 (削除ここまで), 81

=NOW()
=A1-INT(A1)-.375
=(WEEKDAY(A1,3)*8+IF(A2<0,0,IF(A2>TIME(8,0,0),8,A2*24)))/40
answered Aug 16, 2012 at 20:35
\$\endgroup\$
4
  • \$\begingroup\$ The first does not appear to work when NOW() is a time after 5PM. \$\endgroup\$ Commented Aug 21, 2012 at 21:15
  • \$\begingroup\$ augh - a *24 in the wrong position..... \$\endgroup\$ Commented Aug 21, 2012 at 21:18
  • \$\begingroup\$ :-) BTW, good job besting me at my VBA approach using formulas instead. Now I'm nitpicking... Your update added a char (0) that isn't necessary! \$\endgroup\$ Commented Aug 21, 2012 at 21:19
  • \$\begingroup\$ my excuse is I haven't been at work after 5:00 for quite a while :D \$\endgroup\$ Commented Aug 21, 2012 at 21:21
4
\$\begingroup\$

Q, (削除) 111 (削除ここまで) 102

0|100*("i"$(27000000*((.z.d)mod 7)-2)+{0|((17:00:00&x)-09:00:00)-0|00:30:00&x-12:30:00}.z.t)%135000000
answered Aug 16, 2012 at 19:47
\$\endgroup\$
2
\$\begingroup\$

Perl, 124 chars

OK, simple first solution to set the par:

say(($p=((($s,$m,$h,@t)=localtime)[6]+6)%7*20+(($h+=$m/60+$s/3600-9)<0?0:$h<3.5?$h:$h<4?3.5:$h<8?$h-.5:7.5)*8/3)<100?$p:100)

Run with perl -M5.010 to enable the Perl 5.10+ say feature. Resolution is one second; if one minute resolution is acceptable, the +$s/3600 part can be deleted for a total length of 116 chars.

This solution uses localtime to get the day of week and the time of day, so it should work regardless of year changes, leap days or any other calendar peculiarities, at least as long as the seven day week cycle doesn't change. DST changes during the workday would slightly confuse it, but those basically never happen anyway, presumably precisely because that would lead to way too much confusion.

(For testing convenience, note that localtime accepts a Unix timestamp as an optional argument.)

answered Aug 16, 2012 at 16:30
\$\endgroup\$
2
\$\begingroup\$

Mathematica (削除) 169 168 212 214 211 218 210 (削除ここまで) 190 chars

Long-winded, by code golf Standards.

The following takes into account working weeks crossing month or year boundaries, as well as leap years. It reckons time worked according to hours and minutes.

I couldn't think of a way to avoid spelling out the days of the week. Mathematica returns day of week as a 3 character string, which has to be converted to a number.

h = Plus @@ {#1, #2/60, #3/3600} & @@ Take[DateList[], -3]; 100*Min[37.5, (StringTake[DateString[], 3] /. {"Mon" -> 0, "Tue" -> 1, "Wed" -> 2 , "Thu" -> 3, "Fri" -> 4, _ -> 5})*7.5 + Which[h < 12.5, Max[0, h - 9], h < 13, 4, True, 4 + Min[h - 13, 4]]]/37.5

De-golfed

(* d returns {year, mo, day, h, m, s} *)
d = DateList[]
(* finished Days: hours worked *)
f = (StringTake[DateString[], 3] /. {"Mon" -> 0, "Tue" -> 1, "Wed" -> 2 , "Thu" -> 3, "Fri" -> 4, _ -> 5})*7.5
(* time of day in hours *)
h = Plus @@ {#1, #2/60} & @@ Take[d, -3]
(* today: hours Worked. It also computes hours for Sat and Sunday but does not use 
them in the final tabulation, which has a maximum of 37.5. *)
t = Which[h < 12.5, Max[0, h - 9], h < 13, 4, _, 4 + Min[h - 13, 4]]
(* hours Worked in week *)
tot = Min[37.5, f + t]
(* % of working week completed *)
100*tot/37.5

work week

answered Aug 16, 2012 at 20:45
\$\endgroup\$
2
\$\begingroup\$

VBA 141

Formatted to run from the immediate window. Thanks to Sean Cheshire for pointing out a 10-char improvement!

n=(Now-Int(Now))*24:a=(Weekday(Now,3)*7.5+IIf(n>17,7.5,IIf(n>9,IIf(n<12.5,n,IIf‌​(n>13,n-.5,n))-9,0)))/37.5:MsgBox Format(IIf(a>1,1,a),".0%")
answered Aug 17, 2012 at 20:41
\$\endgroup\$
2
  • \$\begingroup\$ use n=n*24, and it can be reduced more. my fight with it produced this: n=(Now-Int(Now))*24:a=(Weekday(Now,3)*7.5+IIf(n>17,7.5,IIf(n>9,IIf(n<12.5,n,IIf(n>13,n-.5,n))-9,0)))/37.5:MsgBox Format(IIf(a>1,1,a),".0%") @ 139 \$\endgroup\$ Commented Aug 22, 2012 at 17:03
  • \$\begingroup\$ @SeanCheshire Excellent point! My method had some left-over syntax from an earlier version that used n, so it couldn't be modified. \$\endgroup\$ Commented Aug 22, 2012 at 17:10
1
\$\begingroup\$

R, 115 chars

---------1---------2---------3---------4---------5---------6---------7---------8---------9---------0---------1---------2
T=as.POSIXlt(Sys.time()-86400);z=T$h+T$mi/60-9;D=function(x,M)min(M,max(0,x));D(((D(z,8)-D(z-3.5,.5))/7.5+T$w)/5,1)

Here is a one-week simulation:

week.frac <- function(t) {
 T <- as.POSIXlt(t-86400)
 z <- T$h+T$mi/60-9
 D <- function(x,M)min(M,max(0,x))
 D(((D(z,8)-D(z-3.5,.5))/7.5+T$w)/5,1)
}
time <- seq(from = as.POSIXlt(as.Date("2012-08-20")),
 to = as.POSIXlt(as.Date("2012-08-27")),
 by = "min")
week.completion <- sapply(time, week.frac)
plot(time, week.completion, type = "l")

week completion for current week

answered Aug 23, 2012 at 4:12
\$\endgroup\$
1
\$\begingroup\$

Ruby, (削除) 191 (削除ここまで) (削除) 116,115 (削除ここまで) 113

The logic is stolen from Fraxtils Python solution.

t=Time.now
d=t.wday
m=[0,t.hour*2+t.min/3e1-18].max
p d<1?100:20*[5,(d-1+[15,m-[8,[7,m].max].min+7].min/15)].min

If you want to test the code with the unit test, you need this 143 character solution:

class Time 
def r
m=[0,hour*2+min/3e1-18].max
d=wday
d<1?100:20*[5,(d-1+[15,m-[8,[7,m].max].min+7].min/15)].min
end 
end
p Time.now.r

Not the shortest and most efficient code, but with a unit test ;)

The 191 characters include the newlines (I could make it a one-liner, just replace each newline with a ;).

class Time
def r
i=0
d{|t|i+=t.w}
i/1350.0
end
def d
t=dup
yield t-=1 until t.strftime('%w%T')=='109:00:00'
end
def w
h=hour
wday<1||wday>5||h<9||h>16||h==12&&min>29?0:1
end
end
p Time.now.r

And the testcode:

require 'test/unit'
class MyTest < Test::Unit::TestCase
 def test_mo
 assert_equal( 20, Time.new(2012,8,13,20).r) #monday
 end
 def test_tue
 assert_equal( 40, Time.new(2012,8,14,20).r) #tuesday
 end
 def test_wed_morning
 assert_equal( 40, Time.new(2012,8,15,7).r)
 end
 def test_wed
 assert_equal( 60, Time.new(2012,8,15,20).r)
 end
 def test_thu
 assert_equal( 80, Time.new(2012,8,16,20).r)
 end
 def test_fri
 assert_equal(100, Time.new(2012,8,17,20).r)
 end
 def test_sat
 assert_equal(100, Time.new(2012,8,18,20).r)
 end
 def test_sun
 assert_equal(100, Time.new(2012,8,19,20).r)
 end
 def test_middle
 assert_equal(50, Time.new(2012,8,15,13,15).r)
 end
end
answered Aug 25, 2012 at 21:17
\$\endgroup\$
0
\$\begingroup\$

Python 2 130 chars

from datetime import*
t=datetime.now().timetuple();
m=min
a=max
n=t[3]+t[4]/60.0
print m(17,a(9,n))-9-(a(0,m(.5,n-12.5)))+7.5*m(t[6],4)

Meh third attempt is weak sauce but I think I've gotten the logic right.

\$\endgroup\$
12
  • 1
    \$\begingroup\$ This doesn't work. At a quick glance of the output, there are no long periods of time where the percentage remains the same, which should be the case between each day's 5:00 PM to the following day's 9:00 AM, as well as each 12:30-1:00 PM interval. It also outputs negative numbers and numbers greater than 100 at times. \$\endgroup\$ Commented Aug 17, 2012 at 17:34
  • \$\begingroup\$ Oh, shame on me. You're absolutely right. Mulligan. \$\endgroup\$ Commented Aug 17, 2012 at 17:39
  • \$\begingroup\$ @Fraxtil I think I've edged you out by a hair \$\endgroup\$ Commented Aug 17, 2012 at 21:25
  • \$\begingroup\$ This appears to have a range of 0 to 37.5. It does pause during the appropriate intervals, though. \$\endgroup\$ Commented Aug 18, 2012 at 6:24
  • \$\begingroup\$ Oh I had it set to print out the number of hours for debugging. I forgot to change it over to % for answer. I'm guessing I won't be able to do that in 2 characters so I guess you got me after all \$\endgroup\$ Commented Aug 20, 2012 at 14:06

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.