0

This is a follow-up question to a previous question regarding a bash script I wrote to help me more accurately keep track of my vices. I'm now trying to modify the script to display all non-zero units:

It's been 2 weeks, 1 day and 5 hours since you last bought a deck.

To that end here are the relevant parts of the script I have so far:

last_bought=$(cat "$lb_file") # file contains time in epoch seconds
...
now=$(date -u +%s)
elapsed="$((now-last_bought))"
W=$((elapsed/60/60/24/7))
D=$((elapsed/60/60/24))
H=$((elapsed/60/60%24))
if [[ $W -le 0 && $D -le 0 && $H -gt 0 ]]; then string="$H hours"
elif [[ $W -le 0 && $D -gt 0 && $H -gt 0 ]]; then string="$D days and $H hours"
elif [[ $W -gt 0 && $D -gt 0 && $H -le 0 ]]; then string="$W weeks and $D days"
elif [[ $W -gt 0 && $D -le 0 && $H -gt 0 ]]; then string="$W weeks and $H hours"
elif [[ $W -gt 0 && $D -gt 0 && $H -gt 0 ]]; then string="$W weeks, $D days and $H hours"
fi

This works perfectly for hours and days (running the script with an hours value of -b 50 shows 2 days and 2 hours). However, when an hour value is entered into the script that is at least one week, both the $W and $D variables are populated. This means that for a value of -b 168 (1 week in hours), the output will be:

It's been 1 weeks and 7 days since you last bought a deck.

How can I fix this, preferably while also implementing singular periods of time like so:

It's been 1 week and 1 hour since you last bought a deck.

I'm also aware that I'm probably checking my logic in a very crude way, so if there's a smarter/more common way to do so I'd appreciate being enlightened, and

Hashim Aziz
  • 13,835

3 Answers3

1
now=$(date +%s)
last_bought=$(date -d '-1 week -3 days -6 hours -34 minutes' +%s)

elapsed=$(( (now - last_bought) / 3600))     # truncate to hours
((hrs   = elapsed % 24, elapsed /= 24))
((days  = elapsed % 7))
((weeks = elapsed / 7))
echo "$weeks weeks, $days days, $hrs hours"
1 weeks, 3 days, 6 hours
Hashim Aziz
  • 13,835
glenn jackman
  • 27,524
0

At first glance, I think the problem is that you are evaluating W,D,H using the full elapsed time.

After each evaluation, you should decrement elapsed by that amount.

The case where day and hour appears to work without decrementing is most likely because H is evaluated using modulo 24.

Also bear in mind that date operations are more complex because of leap years, months, daylight savings, calendar rollover etc. etc.

From the snippet and apparent use, the math it is probably good enough though.

Yorik
  • 4,988
0

After a lot of trial and error and looking up the documentation for bash's very confusing variable operators (=/, =* and the like), I managed to adapt Glenn's answer enough to get it to work for me:

now=$(date +%s)
last_bought=$(date -u +%s)
elapsed=$(((now-last_bought) / 3600))
H=$((elapsed % 24))
D=$(( ( elapsed /= 24 ) % 7))
W=$((elapsed / 7))
echo "$H weeks, $D days, $H hours"

I'm still not entirely sure I understand how the variable operators work, but either way the code now seems to be working as I wanted.

Hashim Aziz
  • 13,835