Jump to content

Worthwhile task shaving

From Rosetta Code
Task
Worthwhile task shaving
You are encouraged to solve this task according to the task description, using any language you may know.

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).

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.


ALGOL 68

Translation of: Wren
BEGIN # xkcd 1205, translated from the Wren sample #
    []INT    shaved  = ( 1, 5, 30, 60, 300, 1800, 3600, 21600, 86400 );
                                                            # time shaved off in seconds #
    []STRING titles  = ( "1 SECOND", "5 SECONDS", "30 SECONDS", "1 MINUTE", "5 MINUTES"
                       , "30 MINUTES", "1 HOUR", "6 HOURS", "1 DAY"
                       );
    REAL diy    = 365.25;
    INT  minute = 60;
    INT  hour   = minute * 60;
    INT  day    = hour * 24;
    INT  week   = day * 7;
    REAL month  = day * diy / 12;
    REAL year   = day * diy;

    []REAL freq = ( 50 * diy, 5 * diy, diy, diy/7, 12, 1 ); # frequency per year #
    INT    mult = 5;                                        # multiplier for table #

    PROC pad right = ( STRING s, INT w )STRING:
         IF INT len = ( UPB s - LWB s ) + 1; len >= w THEN s ELSE s + ( ( w - len ) * " " ) FI;
    PROC center = ( STRING s, INT w )STRING:
         IF INT len = ( UPB s - LWB s ) + 1; len >= w THEN s ELSE ( ( ( w - len ) OVER 2 ) * " " ) + s FI;

    PROC fmt time = ( REAL tf, STRING interval )VOID:
         BEGIN
            INT t  = ENTIER tf;
            print( ( pad right( whole( t, 0 ) + " " + interval + IF t = 1 THEN "" ELSE "S" FI, 13 ) ) )
         END # fmt time # ;

    print( ( center( "HOW OFTEN YOU DO THE TASK", 93 ), newline ) );
    print( ( pad right( "SHAVED OFF", 12 ), " | "
           , pad right( "50/DAY",     13 ), pad right( "5/DAY",   13 ), pad right( "DAILY",  13 )
           , pad right( "WEEKLY",     13 ), pad right( "MONTHLY", 13 ), pad right( "YEARLY", 13 )
           , newline
           )
         );
    print( ( "-" * 93, newline ) );
    FOR y FROM LWB titles TO UPB titles DO
        print( ( pad right( titles[ y ], 12 ), " | " ) );
        FOR x FROM LWB freq TO UPB freq DO
            REAL t = freq[ x ] * shaved[ y ] * mult;
            IF   t < minute THEN
                 fmt time( t,          "SECOND" )
            ELIF t < hour THEN
                 fmt time( t / minute, "MINUTE" )
            ELIF t < day THEN
                 fmt time( t / hour,   "HOUR"   )
            ELIF t < 14 * day THEN
                 fmt time( t / day,    "DAY"    )
            ELIF t < 9 * week THEN
                 fmt time( t / week,   "WEEK"   )
            ELIF t < year THEN
                 fmt time( t / month,  "MONTH"  )
            ELSE
                 print( ( " " * 13 ) )
            FI
        OD;
        print( ( newline ) )
    OD
END
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

C++

#include <cstdint>
#include <iomanip>
#include <iostream>
#include <string>
#include <vector>

void display_time(const uint64_t& time, const std::string& interval) {
	const std::string time_string = std::to_string(time);
	const std::string plural = ( time == 1 ) ? "" : "S";
	std::cout << std::left << std::setw(12) << time_string + " " + interval + plural;
}

int main() {
	const uint32_t days_in_year = 365;
	const uint32_t minute = 60;
	const uint32_t hour = 60 * 60;
	const uint32_t day = 24 * hour;
	const uint32_t week = 7 * day;
	const uint32_t year = days_in_year * day;
	const uint32_t month = year / 12;

	const std::vector<uint32_t> yearly_usage_frequencies = {
		50 * days_in_year, 5 * days_in_year, days_in_year, days_in_year / 7, 12, 1 };

	const std::vector<uint32_t> shaved_times_in_seconds =
        { 1, 5, 30, 60, 300, 1'800, 3'600, 21'600, 86'400 };
	const std::vector<std::string> row_names = { "1 SECOND", "5 SECONDS", "30 SECONDS", "1 MINUTE",
										         "5 MINUTES", "30 MINUTES", "1 HOUR", "6 HOURS", "1 DAY" };

	std::cout << std::string(31, ' ') + "HOW OFTEN YOU DO THE TASK" + "\n\n";
	const std::vector<std::string> column_names =
	    { "SHAVED OFF   | ", "50 / DAY", "5 / DAY", "DAILY", "WEEKLY", "MONTHLY", "YEARLY" };
	for ( const std::string& column_name : column_names ) {
		std::cout << std::left << std::setw(12) << column_name;
	}
	std::cout << "\n" + std::string(87, '-') + "\n";

	const uint64_t number_of_years = 5;
	for ( uint32_t y = 0; y < 9; ++y ) {
		 std::cout << std::left << std::setw(12) << row_names[y] << " | ";
		 for ( const uint32_t& frequency : yearly_usage_frequencies ) {
			 const uint32_t time = frequency * shaved_times_in_seconds[y] * number_of_years;
			 if ( time < minute ) {
				 display_time(time, "SECOND");
			 } else if ( time < hour ) {
				 display_time(time / minute, "MINUTE");
			 } else if ( time < day ) {
				 display_time(time / hour, "HOUR");
			 } else if ( time < 14 * day ) {
				 display_time(time / day, "DAY");
			 } else if ( time < 9 * week ) {
				 display_time(time / week, "WEEK");
			 } else if ( time < year ) {
				 display_time(time / month, "MONTH");
			 } else {
				 std::cout << std::string(12, ' ');
			 }
		 }
		 std::cout << "\n";
	}
}
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      

FreeBASIC

Translation of: Wren
'Rosetta Code problem: https://rosettacode.org/wiki/Worthwhile_task_shaving
'by Jjuanhdez, 02/2023

Dim As Integer shaved(0 To 8) = {1, 5, 30, 60, 300, 1800, 3600, 21600, 86400}
Dim As String columns(0 To 8) = {" 1 SECOND", " 5 SECONDS", "30 SECONDS", _
" 1 MINUTE", " 5 MINUTES", "30 MINUTES", " 1 HOUR", " 6 HOURS", " 1 DAY"}
Dim As Single diy = 365.25
Dim As Integer minuto = 60
Dim As Integer hora = minuto * 60
Dim As Integer dia = hora * 24
Dim As Integer semana = dia * 7
Dim As Integer mes = dia * diy \ 12
Dim As Integer anno = dia * diy

Dim As Integer freq(0 To 5) = {50 * diy, 5 * diy, diy, diy\7, 12, 1}
Dim As Integer y, x, t, mult = 5

Sub fmtTime(t As Single, interval As String)
    t = Int(t + .5)
    Dim As String pl = Iif(t = 1, "", "S")
    Print Using " ## \       \"; t; interval & pl;
End Sub

Print Spc(34); "HOW OFTEN YOU DO THE TASK"
Print " SHAVED OFF   | 50/DAY        5/DAY       DAILY        WEEKLY       MONTHLY      YEARLY"
Print String (92, "-")
For y = 0 To Ubound(columns)
    Print Using "\        \    |"; columns(y);
    For x = 0 To Ubound(freq)
        t = freq(x) * shaved(y) * mult
        If (t < minuto) Then
            fmtTime (t, "SECOND")
        Elseif (t < hora) Then
            fmtTime (t/minuto, "MINUTE")
        Elseif (t < dia) Then
            fmtTime (t/hora, "HOUR")
        Elseif (t < 14 * dia) Then
            fmtTime (t/dia, "DAY")
        Elseif (t < 9 * semana) Then
            fmtTime (t/semana, "WEEK")
        Elseif (t < anno) Then
            fmtTime (t/mes, "MONTH")
        Else
            Print String (13, " ");
        End If
    Next
    Print
Next
Output:
                                  HOW OFTEN YOU DO THE TASK
 SHAVED OFF   | 50/DAY        5/DAY       DAILY        WEEKLY       MONTHLY      YEARLY
--------------------------------------------------------------------------------------------
 1 SECOND     |  1 DAY        3 HOURS     30 MINUTES    4 MINUTES    1 MINUTE     5 SECONDS
 5 SECONDS    |  5 DAYS      13 HOURS      3 HOURS     22 MINUTES    5 MINUTES   25 SECONDS
30 SECONDS    |  5 WEEKS      3 DAYS      15 HOURS      2 HOURS     30 MINUTES    3 MINUTES
 1 MINUTE     |  2 MONTHS     6 DAYS       1 DAY        4 HOURS      1 HOUR       5 MINUTES
 5 MINUTES    | 10 MONTHS     5 WEEKS      6 DAYS      22 HOURS      5 HOURS     25 MINUTES
30 MINUTES    |               6 MONTHS     5 WEEKS      5 DAYS       1 DAY        3 HOURS
 1 HOUR       |                            2 MONTHS    11 DAYS       3 DAYS       5 HOURS
 6 HOURS      |                                         2 MONTHS     2 WEEKS      1 DAY
 1 DAY        |                                         9 MONTHS     9 WEEKS      5 DAYS

Java

import java.util.List;

public final class WorthwhileTaskShaving {

	public static void main(String[] args) {
		final int daysInYear = 365;
		final int minute = 60;
		final int hour = 60 * 60;
		final int day = 24 * hour;
		final int week = 7 * day;
		final int year = daysInYear * day;
		final int month = year / 12;		
		
		List<Integer> yearlyUsagefrequencies =
			List.of( 50 * daysInYear, 5 * daysInYear, daysInYear, daysInYear / 7, 12, 1 ); 
		
		List<Integer> shavedTimesInSeconds = List.of( 1, 5, 30, 60, 300, 1_800, 3_600, 21_600, 86_400 );
		List<String> rowNames = List.of( "1 SECOND", "5 SECONDS", "30 SECONDS", "1 MINUTE",
									     "5 MINUTES", "30 MINUTES", "1 HOUR", "6 HOURS", "1 DAY" );
		
		System.out.println(" ".repeat(31) + "HOW OFTEN YOU DO THE TASK" + System.lineSeparator());
		List<String> columnNames = 
			List.of( "SHAVED OFF   | ", "50 / DAY", "5 / DAY", "DAILY", "WEEKLY", "MONTHLY", "YEARLY" );
		columnNames.forEach( columnName -> System.out.print(String.format("%-12s", columnName)) );
		System.out.println(System.lineSeparator() + "-".repeat(87));
		
		final long numberOfYears = 5;
		for ( int y = 0; y < 9; y++ ) {
			System.out.print(String.format("%-12s%s", rowNames.get(y), " | "));
		    for ( int frequency : yearlyUsagefrequencies ) {
		    	final long time = frequency * shavedTimesInSeconds.get(y) * numberOfYears;
		        if ( time < minute ) {
		            displayTime(time, "SECOND");
		        } else if ( time < hour ) {
		            displayTime(time / minute, "MINUTE");
		        } else if ( time < day ) {
		            displayTime(time / hour, "HOUR");
		        } else if ( time < 14 * day ) {
		            displayTime(time / day, "DAY");
		        } else if ( time < 9 * week ) {
		            displayTime(time / week, "WEEK");
		        } else if ( time < year ) {
		            displayTime(time / month, "MONTH");
		        } else {
		            System.out.print(" ".repeat(12));
		        }
		    }
		    System.out.println(); 
		}
	}
	
	private static void displayTime(long time, String interval) {		
	    String timeString = String.valueOf(time);
	    String plural = ( time == 1 ) ? "" : "S";	
	    System.out.print(String.format("%-12s", timeString + " " + interval + plural));
	}

}
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      

jq

Adapted from Wren

Works with jq, the C implementation of jq

Works with gojq, the Go implementation of jq

Works with jaq, the Rust implementation of jq

### Formatting

def lpad($len): tostring | ($len - length) as $l | (" " * $l) + .;
def rpad($len): tostring | ($len - length) as $l | . + (" " * $l);

def center($width):
  tostring
  | (($width-length)/2|floor) * " " + . | rpad($width);

### Task Shaving

def shaved: # time shaved off in seconds
  [1, 5, 30, 60, 300, 1800, 3600, 21600, 86400];

def columns:
  ["1 SECOND", "5 SECONDS", "30 SECONDS", "1 MINUTE", "5 MINUTES",
   "30 MINUTES", "1 HOUR", "6 HOURS", "1 DAY"];

def parameters:
  { diy: 365.25, minute: 60}
   | .hour = .minute * 60
   | .day = .hour * 24
   | .week = .day * 7
   | .month = .day * .diy / 12
   | .year = .day * .diy
   | .freq = [50 * .diy, 5 * .diy, .diy, .diy/7, 12, 1] # frequency per year
   | .mult = 5 # multiplier for table
;

# Total field width is 13
def fmtTime($interval):
  if . == 0 then 13*" "
  else floor
  | (if . == 1 then " " else "S" end) as $pl
  | "\(lpad(2)) \($interval + $pl | rpad(10))"
  end;

# Format one row
def row:
  map(lpad(13)) | "\(.[0]) | \(.[1:]|join(""))";

"*** HOW OFTEN YOU DO THE TASK ***" | center(90),
(["SHAVED OFF", "50/DAY", "5/DAY", "DAILY", "WEEKLY", "MONTHLY", "YEARLY"]
 | map(center(13)) | row),
("-" * 90),
(parameters as $p
 | range(0;9) as $y
 | [columns[$y],
    (range(0; 6) as $x
        | ($p.freq[$x] * shaved[$y] * $p.mult)
        | if   . < $p.minute   then .           | fmtTime("SECOND")
          elif . < $p.hour     then ./$p.minute | fmtTime("MINUTE")
          elif . < $p.day      then ./$p.hour   | fmtTime("HOUR")
          elif . < 14 * $p.day then ./$p.day    | fmtTime("DAY")
          elif . < 9 * $p.week then ./$p.week   | fmtTime("WEEK")
          elif . < $p.year     then ./$p.month  | fmtTime("MONTH")
          else 0 | fmtTime("")
          end) ] | row)
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      

Julia

Translation of: Perl
shaved  = [1, 5, 30, 60, 300, 1800, 3600, 21600, 86400]
columns = [" 1 Second", " 5 Seconds", "30 Seconds", " 1 Minute", " 5 Minutes", "30 Minutes", " 1 Hour", " 6 Hours", " 1 Day"]
diy, minute, hour, day, week = 365.25, 60, 60 * 60, 60 * 60 * 24, 60 * 60 * 24 * 7
month, year = day * diy / 12, day * diy
freq = [50 * diy, 5 * diy, diy, diy / 7, 12, 1]

fmt(t, interval) = rpad(lpad(Int(round(t)), 3) * " $interval" * (t > 1 ? "s" : ""), 15)

println(' '^34, "How Often You Do the Task\n")
foreach(s -> print(rpad(s, 15)), ["Shaved-off  |", " 50/Day", " 5/Day", " Daily", " Weekly", " Monthly", " Yearly"])
println("\n", '-'^100)

for y in 1:9
   row = lpad(columns[y] * " | ", 14)
   for x in 1:6
      t = freq[x] * shaved[y] * 5
      row *= t < minute ? fmt(t, "Second") : t < hour ? fmt(t / minute, "Minute") : t < day ? fmt(t / hour,   "Hour") :
         t < day * 14 ? fmt(t / day, "Day") : t < week * 9 ? fmt(t / week, "Week") : t < year ? fmt(t / month, "Month") : "   n/a         "
   end
   println(row)
end
Output:
                                  How Often You Do the Task

Shaved-off  |   50/Day         5/Day          Daily          Weekly         Monthly        Yearly
----------------------------------------------------------------------------------------------------
   1 Second |   1 Days         3 Hours       30 Minutes      4 Minutes      1 Minute       5 Seconds
  5 Seconds |   5 Days        13 Hours        3 Hours       22 Minutes      5 Minutes     25 Seconds
 30 Seconds |   5 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       5 Weeks        6 Days        22 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      11 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           9 Months       9 Weeks        5 Days

Nim

Translation of: Wren
import std/[strformat, strutils]

const Shaved = [float 1, 5, 30, 60, 300, 1800, 3600, 21600, 86400]  # Time shaved off in seconds.
const Columns = ["1 SECOND", "5 SECONDS", "30 SECONDS", "1 MINUTE", "5 MINUTES",
                 "30 MINUTES", "1 HOUR", "6 HOURS", "1 DAY"]
const
  Diy = 365.25
  Minute = 60
  Hour = Minute * 60
  Day = Hour * 24
  Week = Day * 7
  Month = Day * Diy / 12
  Year = Day * Diy

const Freqs = [50 * Diy, 5 * Diy, Diy, Diy / 7, 12, 1]  # Frequency per year.
const Mult = 5    # Multiplier for table.

proc fmtTime(t: float; interval: string): string =
  let t = t.int
  let pl = if t == 1: "" else: "S"
  result = &"{$t & ' ' & interval & pl:<12} "

echo &"""{"HOW OFTEN YOU DO THE TASK":^93}"""
stdout.write &"""{"SHAVED OFF":<12} |"""
for text in ["50/DAY", "5/DAY", "DAILY", "WEEKLY", "MONTHLY", "YEARLY"]:
  stdout.write &" {text:<12}"
echo()
echo repeat('-', 93)
for y in 0..8:
  stdout.write &"{Columns[y]:<12} | "
  for x in 0..5:
    let t = Freqs[x] * Shaved[y] * Mult
    stdout.write if t < Minute:
                   fmtTime(t, "SECOND")
                 elif t < Hour:
                   fmtTime(t / Minute, "MINUTE")
                 elif t < Day:
                   fmtTime(t / Hour, "HOUR")
                 elif t < 14 * Day:
                   fmtTime(t / Day, "DAY")
                 elif t < 9 * Week:
                   fmtTime(t / Week, "WEEK")
                 elif t < Year:
                   fmtTime(t / Month, "MONTH")
                 else:
                   repeat(' ', 13)
  echo()
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   

Perl

use strict;
use warnings;
use feature <say switch>;
no warnings 'experimental::smartmatch';

use constant CW => '%-11s'; # set column width

#            (     scale  -->    seconds   )  (minutes) (     scale -->  hours )
my @shaved = map { 60 * $_ } 1/60, 1/12, 1/2, 1, 5, 30, map { 60 * $_ } 1, 6, 24;
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 @freq    = ((map { $diy * $_ } 50, 5, 1, 1/7), 12, 1);
my $week    = 7 * (my $day = 24 * (my $hour = 60 * (my $minute = 60)));
my $month   = (my $year = $day * $diy) / 12;
my $mult    = 5;

sub fmt { my($t, $interval) = @_; sprintf CW.' ', (sprintf '%2d', int $t) . ' ' . $interval . ($t > 1 and 's') }

say ' ' x 34 . 'How Often You Do the Task';                                              say '';
say sprintf  CW.' | '.(' '.CW)x6, <Shaved-off 50/Day 5/Day Daily Weekly Monthly Yearly>; say '';

for my $y (0..8) {
   my $row = sprintf CW.' | ', $columns[$y];
   for my $x (0..5) {
      given ($freq[$x] * $shaved[$y] * $mult) {
         when ($_ < $minute) { $row .= fmt $_,         "Second" }
         when ($_ < $hour  ) { $row .= fmt $_/$minute, "Minute" }
         when ($_ < $day   ) { $row .= fmt $_/$hour,   "Hour"   }
         when ($_ < 14*$day) { $row .= fmt $_/$day,    "Day"    }
         when ($_ < 9*$week) { $row .= fmt $_/$week,   "Week"   }
         when ($_ < $year  ) { $row .= fmt $_/$month,  "Month"  }
         default             { $row .= ' ' . sprintf CW, ' '    }
      }
   }
   say $row;
}
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  |              6 Months    5 Weeks     5 Days      1 Days      2 Hours
 1 Hour     |                          2 Months   10 Days      2 Days      5 Hours
 6 Hours    |                                      2 Months    2 Weeks     1 Days
 1 Day      |                                      8 Months    8 Weeks     5 Days

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,"""
-------------  How long can you work on making a routine task more  -------------
-------------  efficient before spending more time than you saved?  -------------
------------------------------  (across five years)  ----------------------------
----------+----------------------------------------------------------------------
Shave off |  ------------------- How Often You Do The Task ----------------------
task time |    50/day       5/day       daily      weekly     monthly      yearly
----------+-----------+-----------+-----------+-----------+-----------+----------
""")
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.

-------------  How long can you work on making a routine task more  -------------
-------------  efficient before spending more time than you saved?  -------------
------------------------------  (across five years)  ----------------------------
----------+----------------------------------------------------------------------
Shave off |  ------------------- How Often You Do The Task ----------------------
task time |    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

Python

Translation of: Julia
row_names = [
    " 1 Second",
    " 5 Seconds",
    "30 Seconds",
    " 1 Minute",
    " 5 Minutes",
    "30 Minutes",
    " 1 Hour",
    " 6 Hours",
    " 1 Day",
]

row_values_in_seconds = [1, 5, 30, 60, 300, 1800, 3600, 21600, 86400]
days_in_a_year = 365.25

seconds_in_minute = 60
seconds_in_hour = seconds_in_minute * 60
seconds_in_day = seconds_in_hour * 24
seconds_in_week = seconds_in_day * 7
seconds_in_year = seconds_in_day * days_in_a_year
seconds_in_month = seconds_in_year / 12

column_names = [
    "Shaved-off |",
    " 50/Day",
    " 5/Day",
    " Daily",
    " Weekly",
    " Monthly",
    " Yearly",
]

# column values
shaves_per_year = [
    50 * days_in_a_year,
    5 * days_in_a_year,
    days_in_a_year,
    days_in_a_year / 7,
    12,
    1,
]


def get_shave_string(amount_of_interval_in, interval_in) -> str:
    plural_string = ""
    if int(amount_of_interval_in) > 1:
        plural_string = "s"

    result = f"{int(amount_of_interval_in)} {interval_in}{plural_string}"
    padded_result = result.ljust(3).rjust(15)

    return padded_result


if __name__ == "__main__":
    print(" " * 34, "How Often You Do the Task\n")

    for column_name in column_names:
        print(str(column_name).rjust(14), end=" ")
    print()
    print("-" * 104)

    for row_number, row_name in enumerate(row_names):
        row = f"{row_name} |".rjust(14)

        for column_value in range(6):
            t = shaves_per_year[column_value] * row_values_in_seconds[row_number] * 5
            if t < seconds_in_minute:
                amount_of_interval, interval = t, "Second"
            elif t < seconds_in_hour:
                amount_of_interval, interval = t / seconds_in_minute, "Minute"
            elif t < seconds_in_day:
                amount_of_interval, interval = t / seconds_in_hour, "Hour"
            elif t < seconds_in_week * 2:
                amount_of_interval, interval = t / seconds_in_day, "Day"
            elif t < seconds_in_month * 2:
                amount_of_interval, interval = t / seconds_in_week, "Week"
            elif t < seconds_in_year:
                amount_of_interval, interval = t / seconds_in_month, "Month"
            else:
                row += "n/a".ljust(3).rjust(15)
                continue
            row += get_shave_string(amount_of_interval, interval)
        print(row)
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 |            n/a       6 Months        5 Weeks         5 Days          1 Day        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 Day
       1 Day |            n/a            n/a            n/a       8 Months        8 Weeks         5 Days

Raku

Translation of: Wren
# 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"
}
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

V (Vlang)

Translation of: Wren
import math
const (
    shaved = [1, 5, 30, 60, 300, 1800, 3600, 21600, 86400] // time shaved off in seconds
    columns = ["1 SECOND", "5 SECONDS", "30 SECONDS", "1 MINUTE", "5 MINUTES",
                   "30 MINUTES", "1 HOUR", "6 HOURS", "1 DAY"]
    diy = 365.25
    minute = 60
    hour = minute * 60
    day = hour * 24
    week = day * 7
    month = day * diy / 12
    year = day * diy
    freq = [50 * diy, 5 * diy, diy, diy/7, 12, 1] // frequency per year
    mult = 5 // multiplier for table
)

fn fmt_time(t f64, interval string) {
    f := int(math.floor(t))
    mut s := interval
    if f>1 {
        s = '${interval}S'
    }
    print(' ${f:-2} ${s:-9}')
}

fn main(){
    title := 'HOW OFTEN YOU DO THE TASK'
    println("${title:58}")
    println('SHAVED OFF   | 50/DAY       5/DAY        DAILY        WEEKLY       MONTHLY      YEARLY')
    println([]string{init:'-',len:93}.join(''))
    for y in 0..columns.len {
    print('${columns[y]:-12} |')
    for x in 0..6 {
       t := freq[x] * shaved[y] * mult
       if t < minute {
            fmt_time(t, "SECOND")
       } else if t < hour {
            fmt_time(t/minute, "MINUTE")
       } else if t < day {
            fmt_time(t/hour, "HOUR")
       } else if t < 14 * day {
            fmt_time(t/day, "DAY")
       } else if t < 9 * week {
            fmt_time(t/week, "WEEK")
       } else if t < year {
            fmt_time(t/month, "MONTH")
       } else {
            print('             ')
       }
    }
    println('')
    }
}
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  

Wren

Library: Wren-fmt

This is quite close to the original table but no cigar.

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()
}
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       

Yabasic

Translation of: Phix
// Rosetta Code problem: http://rosettacode.org/wiki/Worthwhile_task_shaving
// by Galileo, 02/2022

SEC = 1 : MINU = 60 : HOUR = 60 * MINU
DAY = 8 * HOUR : WEEK = 5 * DAY : MONTH = 4 * WEEK : YEAR = 12 * MONTH   // (as 48 weeks/omit holidays)
dim shavings$(1) : ls = token("1, 5, 30, MINU, 5 * MINU, 30 * MINU, HOUR, 6 * HOUR, DAY", shavings$(), ",")
dim frequencies$(1) : lf = token("50, DAY, 5, DAY, 1, DAY, 1, WEEK, 1, MONTH, 1, YEAR", frequencies$(), ",")
dim roundto$(1) : lr = token("SEC, MINU, HOUR, DAY, WEEK, MONTH, YEAR", roundto$(), ",")
dim ts$(1) : lt = token("sec, min, hour, day, week, month, year", ts$(),  ",")

sub format$(line$, n)
    return right$("                                                                                           " + line$, n)
end sub

sub duration$(a)
    local es$, rdx, t
    
    for rdx = 1 to lr
        t = int(a/eval(roundto$(rdx)))
        if rdx > 1 and t < 1 break
        es$ = str$(t) + " " + ts$(rdx) : if t > 1 es$ = es$ + "s" : es$ = es$
    next
    
    return es$
end sub

print "                50/day       5/day       daily      weekly     monthly      yearly\n"

for s = 1 to ls
    si = eval(shavings$(s))
    line$ = format$(duration$(si), 10) + "  "
    for f = 1 to lf step 2
        per = eval(frequencies$(f)) : slot = eval(frequencies$(f + 1))
        if si * per > slot then
            line$ = line$ + format$("n/a", 10) + "  "
        else
            shaving = (5 * YEAR / slot * per) * si
            line$ = line$ + format$(duration$(shaving), 10) + "  "
        end if
    next
    print line$
next
Output:
                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
---Program done, press RETURN---
Cookies help us deliver our services. By using our services, you agree to our use of cookies.