0

I have a subscription to a LTE service that expires the same day each month. For example, if I paid the first time on the 8th of Feb, it will expire on the 8th of Mar, Apr, etc., so it is not a 28 days based subscription, but the distance between two occurrences is variable.

Now, I need to write a shell script in order to calculate the distance (in days, or maybe days + hours) from today to the next recurring deadline, taking in account that each month is different.

I am thinking to use cal command, but I do not know how to do it. I need to place the result in a variable (inside a bash script that is already done but working with fixed 28 days subscription), in order to recalculate the remaining bandwidth and trim it accordingly.

jww
  • 97,681
  • 90
  • 411
  • 885
berti
  • 11
  • 1
    This website is intended for software developers. Show your code and describe what didn't work. – Cyrus Nov 16 '19 at 14:50
  • Does this answer your question? [How to find the difference in days between two dates?](https://stackoverflow.com/questions/4946785/how-to-find-the-difference-in-days-between-two-dates) – Romeo Ninov Nov 16 '19 at 15:00
  • If today is November 8, do you want the output to be zero or 30? – glenn jackman Nov 16 '19 at 16:07

4 Answers4

0

Note that $days_diff will be an integer (i.e. no decimals)

days_diff=$(( (`date -d $B +%s` - `date -d "00:00" +%s`) / (24*3600) ))
Ahmed Tounsi
  • 1,482
  • 1
  • 14
  • 24
0

Thanks to glenn! your solution seems good. In the meantime, I also found this way:

#!/bin/bash

_day_today=$(date +%d)
_recur_day=8
_days_in_month=$(cal | grep -E -v '[A-Za-z]' | wc -w)

if [ "$_recur_day" -gt "$_day_today" ]
then
  substraction=$((_recur_day-_day_today))
else
  substraction=$((_recur_day+_days_in_month-_day_today))
fi

echo "$_days_in_month"
echo "$substraction" 

However, now I realized that this in not enough: I also need to know how to calculate how many days elapsed from last occurrence, and to do this I need to know how many days were in the previous month. How do I check how many days in previous month?

Cyrus
  • 84,225
  • 14
  • 89
  • 153
berti
  • 11
-1

With bash version 4.3, the builtin printf can format a datetime. Still need GNU date to parse a timestamp though. Here, I'm using %j to get the day of the year: that makes it easy to get the days remaining.

days_remaining() {
    local day month year doy renew_day=8
    read day month year doy < <(printf '%(%-d %-m %Y %j)T\n' -1)
    if ((day >= renew_day)) && ((++month > 12)); then
        month=1
        ((year++))
    fi
    echo $(( $(date -d "$year-$month-$renew_day" '+%j') - doy ))
}

echo "There are $(days_remaining) days until next renewal" 

Today, the 16th of November, it's 22 days remaining. If today is November 8, it will output 30 days.


Here's another implementation that does not require any external tools:

days_remaining() {
    local timestamp days renew_day=8
    for ((
        timestamp=$(printf '%(%s)T' -1), days = 0; 
        $(printf '%(%-d)T' $timestamp) != renew_day;
        days++, timestamp += 86400
    )); do :; done
    echo $days
}

If today is November 8, it will output 0 days.


And the days since the last renewal:

days_since() {
    local timestamp days renew_day=8
    for ((
        timestamp=$(printf '%(%s)T' -1) - 86400, days=1;
        $(printf '%(%-d)T' $timestamp) != renew_day;
        days++, timestamp -= 86400
    )); do :; done
    echo $days
}

or combine them:

dom() { printf '%(%-d)T' "$1"; }
days() {
    local now=$(printf '%(%s)T' -1)
    local renew_day=8
    local used=1 left=0 ts
    for ((ts = now - 86400; $(dom $ts) != renew_day; used++, ts -= 86400)); do :; done
    for ((ts = now;         $(dom $ts) != renew_day; left++, ts += 86400)); do :; done
    echo "$used $left"
}

Today, that function outputs 8 22
If the renew_day is 16, it will output 31 0

glenn jackman
  • 238,783
  • 38
  • 220
  • 352
-1

Will require some tweaking to adjust for desired output when today is the day of, or day before, expiry.

expiry=8

# get expiry this month and next month, in format: YYYY-MM-DD
exp_this_month=$(date +%Y-%m-$expiry)
exp_next_month=$(date --date="$exp_this_month +1 month" +%Y-%m-%d)

# get these dates in seconds
exp_this_month_sec=$(date --date="$exp_this_month" +%s)
exp_next_month_sec=$(date --date="$exp_next_month" +%s)

# calculate offset to next expiry, by subtracting
# the seconds-representation of dates
today=$(date +%s)

if [ $today -lt $exp_this_month_sec ] ; then
    echo $(( ( $exp_this_month_sec - $today ) / (24*3600) ))
else
    echo $(( ( $exp_next_month_sec - $today ) / (24*3600) ))
fi
Darren Smith
  • 2,261
  • 16
  • 16