-2

how can i convert "System uptime: 2 days, 9 hours, 16 minutes, 5 seconds" to a bash date?

I want to compare this date with another one.

Thx in advance.

calabash
  • 115
  • 1
  • 7
  • Durations are different to dates. How would you represent the above? – kvantour Oct 15 '19 at 14:41
  • the idea was to run the script and store the date value. then run it a second time, store date value and compare them. – calabash Oct 15 '19 at 14:55
  • Durations are different to dates and you cannot convert them. What would such a date represent? What would be the time 0? What does it mean if my command ran for a duration of "1989-12-10T01:23:56". Do you keep track of leap years, or do you just say a year is 365.242 190 402 SI days. It's a bit hard to understand what you want. – kvantour Oct 15 '19 at 14:56
  • If you just want to compare, it is better just to convert your uptime in seconds. – kvantour Oct 15 '19 at 14:58
  • Does this answer your question? [Convert string to date in bash](https://stackoverflow.com/questions/11144408/convert-string-to-date-in-bash) – miken32 Jan 12 '20 at 23:07

3 Answers3

1

Assuming that the message will always include all the date components at fixed places, Unix timestamp (seconds past epoch) can be calculated using.

# Set t from command, or file.
t="System uptime: 2 days, 9 hours, 16 minutes, 5 seconds"
# Split into words
read -a p <<< "$t"
# Uptime in seconds
uptime=$((p[2]*24*60*60+p[4]*60*60+p[6]*60+p[8]))
now=$(date '+%s')
up_ts=$((now-uptime))
echo "Timestamp: $up_ts"
# Convert to human readable date.
up_date=$(date +'%Y-%m-%d %H:%M:%S' -d "@$up_ts")
echo "Date: $up_date"

You can also use bash built-in date formatting on the 'up_ts'.

If the format of the uptime message depends on the values (e.g., days is not included if uptime < 1 day), additional parsing will be needed.

dash-o
  • 13,723
  • 1
  • 10
  • 37
  • i already found it in the read command: -a ANAME The words are assigned to sequential indexes of the array variable ANAME, starting at 0. – calabash Oct 15 '19 at 15:15
  • A few notes: `weeks` will show up after 7 days, and any component that is `0` is not printed at all. – Sean Bright Oct 15 '19 at 22:53
  • This method might fail when System uptime does not list `days` if the command did not run that long, or if we get the extra field "weeks" – kvantour Oct 16 '19 at 09:01
1

Here you find a robust way that will convert your duration into the total number of seconds. This is robust as it does not need to have all the quantities listed. I.e. the output can be any of the following:

 System uptime: 16 minutes, 2 seconds
 System uptime: 12 days, 3 seconds
 System uptime: 15minutes,12hours
  1. Create a file convert.awk which contains

    BEGIN { a["seconds"]=1; a["minutes"]=60
            a["hours"]=3600; a["days"]=86400;
            a["weeks"]=7*86400 }
    { tmp=tolower($0) }
    { while (match(tmp,/[0-9]+[^a-z]*[a-z]+/)) {
        u=substr(tmp,RSTART,RLENGTH); q=u+0; gsub(/[^a-z]/,"",u)
        t+=q*a[u]
        tmp=substr(tmp,RSTART+RLENGTH)
      }
      print t
    }
    
  2. Run the following command:

    $ echo "System uptime: 2 days, 9 hours, 16 minutes, 5 seconds" | awk -f convert.awk
    206165
    $ echo "System uptime: 2 weeks, 9 days, 16 minutes, 5 seconds" | awk -f convert.awk
    1988165
    

How does this work:

When we read a line, eg.

tmp="system uptime: 16 minutes, 2 seconds"

The match command will search for any substring which starts with numbers and ends with a character string. match will automatically set the variables RSTART and RLENGTH to the position of the found substring and the length of it. This way, the command u=substr(tmp,RSTART,RLENGTH) will set

u="16 minutes"

You can now just do an arhtmetic operation on this, to extract the first number. This works with awk as it will convert any string starting with numbers into a number by ignoring anything after it. So q=u+0 creates

q=16

Finally, we remove anything which is not a character from u leading to

u="minutes"

The next step we redefine tmp by removing whatever we already processed.

tmp=", 2 seconds"

and start the process all over.

kvantour
  • 25,269
  • 4
  • 47
  • 72
-1

Note that the uptime command gets the data from /proc/uptime

So one approach is to get the first field value which is the total elapsed time in seconds and feed it to date command:-

here is an example:-

$ cat /proc/uptime
8743161.15 7738916.50

$ date -d'-8743161.15 seconds'
Sat Jul  6 06:00:37 EDT 2019
Yoda
  • 435
  • 2
  • 7