Worthwhile task shaving

Revision as of 22:14, 7 February 2022 by Petelomax (talk | contribs) (added "over five years", missing from task description)

Recreate https://xkcd.com/1205/ which shows a (humorous) table of how long you can work on making a routine task more efficient before spending more time than saved, for various s(h)avings against how often the task is run (over the course of five years).

Worthwhile task shaving is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

There are of course several possible interpretations of "day" and "week" in this context. The Phix implementation assumes 8 hour days and 5 day weeks might be more realistic, whereas it seems the original author worked with 24 hour days and 7 day weeks, and, tbh, my interest is piqued to see what built-in facilities other languages might have for handling such non-standard terms, if any. Extra kudos awarded for getting into the mind of the original author and reproducing their results exactly (see talk page), or drumming up non-trivial (but still elegant) and potentially actually useful routines. This task can be made as trivial or as convoluted as you please, and should aim more for a little playfulness than rigid scientific accuracy.

Phix

with javascript_semantics
constant SEC = 1,
         MIN = 60,
         HOUR = 60*MIN,
         DAY = 8*HOUR,      -- (allow some sleepage)
         WEEK = 5*DAY,      -- (omit weekends)
         MONTH = 4*WEEK,
         YEAR = 12*MONTH,   -- (as 48 weeks/omit holidays)
         shavings = {1,5,30,MIN,5*MIN,30*MIN,HOUR,6*HOUR,DAY},
         frequencies = {{50,DAY},{5,DAY},{1,DAY},{1,WEEK},{1,MONTH},{1,YEAR}},
         roundto = {SEC, MIN, HOUR, DAY, WEEK, MONTH, YEAR},
         ts = {"sec", "min", "hour", "day", "week", "month", "year"}

function duration(atom a)
    string es
    for rdx=1 to length(roundto) do
        atom t = trunc(a/roundto[rdx])
        if rdx>1 and t<1 then exit end if
        es = sprintf("%d %s%s",{t,ts[rdx],iff(t=1?"":"s")})
    end for
    return es
end function

printf(1,"               50/day       5/day       daily      weekly     monthly      yearly\n")
for s=1 to length(shavings) do
    integer si = shavings[s]
    string line = sprintf("%10s ",duration(si))
    for f=1 to length(frequencies) do
        integer {per,slot} = frequencies[f]
        if si*per > slot then
            line &= sprintf("%10s  ","n/a")
        else
            atom shaving = (5*YEAR/slot * per) * si
            line &= sprintf("%10s  ",duration(shaving))
        end if
    end for
    printf(1,"%s\n",line)
end for
Output:

One outlier here is 1hr 5/day ==> 3 years vs original 10 months: as per notes above for 5/8ths the cutoff is indeed 3 years.
Note that the standard builtins such as elapsed() have no facilities for non-standard terms such as 8 hour working days.

               50/day       5/day       daily      weekly     monthly      yearly
     1 sec     2 days      1 hour     20 mins      4 mins       1 min      5 secs
    5 secs    2 weeks       1 day      1 hour     20 mins      5 mins     25 secs
   30 secs   3 months      1 week       1 day     2 hours     30 mins      2 mins
     1 min   6 months     2 weeks      2 days     4 hours      1 hour      5 mins
    5 mins    2 years    3 months     2 weeks      2 days     5 hours     25 mins
   30 mins        n/a      1 year    3 months     3 weeks      3 days     2 hours
    1 hour        n/a     3 years    7 months     1 month      1 week     5 hours
   6 hours        n/a         n/a     3 years    9 months    2 months      3 days
     1 day        n/a         n/a     5 years      1 year    3 months      1 week

Raku

Translation of: Wren

<lang perl6># 20220207 Raku programming solution

my \shaved = [1, 5, 30, 60, 300, 1800, 3600, 21600, 86400]; # time shaved off in seconds my \columns = [ "1 SECOND", "5 SECONDS", "30 SECONDS", "1 MINUTE", "5 MINUTES",

               "30 MINUTES", "1 HOUR", "6 HOURS", "1 DAY" ];

my \diy = 365.25; my \minute = 60; my \hour = minute * 60; my \day = hour * 24; my \week = day * 7; my \month = day * diy / 12; my \year = day * diy; my \freq = [50 * diy, 5 * diy, diy, diy/7, 12, 1]; # frequency per year my \mult = 5; # multiplier for table

sub fmtTime (\t, \interval) { printf "%-12s ", t.floor~" "~interval~(t == 1 ?? "" !! "S") }

say ' ' x 34~"HOW OFTEN YOU DO THE TASK"; printf("%-12s | %-12s %-12s %-12s %-12s %-12s %-12s\n",

  ["SHAVED OFF", "50/DAY", "5/DAY", "DAILY", "WEEKLY", "MONTHLY", "YEARLY"]);

say '-' x 93;

for ^9 -> \y {

  printf "%-12s | ", columns[y];
  for ^6 -> \x {
     given my \t = freq[x] * shaved[y] * mult {
        when t < minute  { fmtTime t,        "SECOND" } 
        when t < hour    { fmtTime t/minute, "MINUTE" } 
        when t < day     { fmtTime t/hour,   "HOUR"   } 
        when t < 14*day  { fmtTime t/day,    "DAY"    } 
        when t < 9*week  { fmtTime t/week,   "WEEK"   }
        when t < year    { fmtTime t/month,  "MONTH"  }
        default          { print   '   N/A       '    }
     }
  }
  print "\n"

}</lang>

Output:
                                  HOW OFTEN YOU DO THE TASK
SHAVED OFF   | 50/DAY       5/DAY        DAILY        WEEKLY       MONTHLY      YEARLY
---------------------------------------------------------------------------------------------
1 SECOND     | 1 DAYS       2 HOURS      30 MINUTES   4 MINUTES    1 MINUTE     5 SECONDS
5 SECONDS    | 5 DAYS       12 HOURS     2 HOURS      21 MINUTES   5 MINUTES    25 SECONDS
30 SECONDS   | 4 WEEKS      3 DAYS       15 HOURS     2 HOURS      30 MINUTES   2 MINUTES
1 MINUTE     | 2 MONTHS     6 DAYS       1 DAYS       4 HOURS      1 HOUR       5 MINUTES
5 MINUTES    | 10 MONTHS    4 WEEKS      6 DAYS       21 HOURS     5 HOURS      25 MINUTES
30 MINUTES   |    N/A       6 MONTHS     5 WEEKS      5 DAYS       1 DAYS       2 HOURS
1 HOUR       |    N/A          N/A       2 MONTHS     10 DAYS      2 DAYS       5 HOURS
6 HOURS      |    N/A          N/A          N/A       2 MONTHS     2 WEEKS      1 DAYS
1 DAY        |    N/A          N/A          N/A       8 MONTHS     8 WEEKS      5 DAYS


Wren

Library: Wren-fmt

This is quite close to the original table but no cigar. <lang ecmascript>import "./fmt" for Fmt

var shaved = [1, 5, 30, 60, 300, 1800, 3600, 21600, 86400] // time shaved off in seconds var columns = ["1 SECOND", "5 SECONDS", "30 SECONDS", "1 MINUTE", "5 MINUTES",

              "30 MINUTES", "1 HOUR", "6 HOURS", "1 DAY"]

var diy = 365.25 var minute = 60 var hour = minute * 60 var day = hour * 24 var week = day * 7 var month = day * diy / 12 var year = day * diy

var freq = [50 * diy, 5 * diy, diy, diy/7, 12, 1] // frequency per year var mult = 5 // multiplier for table

var fmtTime = Fn.new { |t, interval|

  t = t.floor
  var pl = (t == 1) ? "" : "S"
  Fmt.write("$-12s ", t.toString + " " + interval + pl)

}

Fmt.print("$93m", "HOW OFTEN YOU DO THE TASK") Fmt.lprint("$-12s | $-12s $-12s $-12s $-12s $-12s $-12s", ["SHAVED OFF", "50/DAY", "5/DAY", "DAILY", "WEEKLY", "MONTHLY", "YEARLY"]) System.print("-" * 93) for (y in 0..8) {

   Fmt.write("$-12s | ", columns[y])
   for (x in 0..5) {
       var t = freq[x] * shaved[y] * mult
       if (t < minute) {
            fmtTime.call(t, "SECOND")
       } else if (t < hour) {
            fmtTime.call(t/minute, "MINUTE")
       } else if (t < day) {
            fmtTime.call(t/hour, "HOUR")
       } else if (t < 14 * day) {
            fmtTime.call(t/day, "DAY")
       } else if (t < 9 * week) {
            fmtTime.call(t/week, "WEEK")
       } else if (t < year) {
            fmtTime.call(t/month, "MONTH")
       } else {
            System.write(" " * 13)
       }
   }
   System.print()

}</lang>

Output:
                                  HOW OFTEN YOU DO THE TASK                                  
SHAVED OFF   | 50/DAY       5/DAY        DAILY        WEEKLY       MONTHLY      YEARLY      
---------------------------------------------------------------------------------------------
1 SECOND     | 1 DAY        2 HOURS      30 MINUTES   4 MINUTES    1 MINUTE     5 SECONDS    
5 SECONDS    | 5 DAYS       12 HOURS     2 HOURS      21 MINUTES   5 MINUTES    25 SECONDS   
30 SECONDS   | 4 WEEKS      3 DAYS       15 HOURS     2 HOURS      30 MINUTES   2 MINUTES    
1 MINUTE     | 2 MONTHS     6 DAYS       1 DAY        4 HOURS      1 HOUR       5 MINUTES    
5 MINUTES    | 10 MONTHS    4 WEEKS      6 DAYS       21 HOURS     5 HOURS      25 MINUTES   
30 MINUTES   |              6 MONTHS     5 WEEKS      5 DAYS       1 DAY        2 HOURS      
1 HOUR       |                           2 MONTHS     10 DAYS      2 DAYS       5 HOURS      
6 HOURS      |                                        2 MONTHS     2 WEEKS      1 DAY        
1 DAY        |                                        8 MONTHS     8 WEEKS      5 DAYS