Differences between revisions 1 and 13 (spanning 12 versions)
Revision 1 as of 2007-05-03 00:05:33
Size: 2745
Editor: redondos
Comment:
Revision 13 as of 2016-04-11 01:31:15
Size: 4213
Editor: mattcen
Comment: Add GNU date @ syntax
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
[[Anchor(faq70)]]
== How do I convert Unix (epoch) timestamps to human-readable values? ==
<<Anchor(faq70)>>
== How do I convert Unix (epoch) times to human-readable values? ==
The only sane way to handle time values within a program is to convert them into a linear scale. You can't store "January 17, 2005 at 5:37 PM" in a variable and expect to do anything with it....
Line 4: Line 5:
The only sane way to handle time values within a program is to convert them into a linear scale. You can't store "January 17, 2005 at 5:37 PM" in a variable and expect to do anything with it. Therefore, any competent program is going to use time stamps with semantics such as "the number of seconds since point X". These are called ''epoch'' timestamps. If the epoch is January 1, 1970 at midnight UTC, then it's also called a "Unix timestamp", because this is how Unix stores all times (such as file modification times). Therefore, any competent program is going to use time stamps with semantics such as "the number of seconds since point X". These are called ''epoch'' timestamps. If the epoch is January 1, 1970 at midnight UTC, then it's also called a "Unix timestamp", because this is how Unix stores all times (such as file modification times).
Line 6: Line 7:
Standard Unix, unfortunately, has ''no'' tools to work with Unix timestamps. (Ironic, eh?) GNU date, and later BSD date, has a {{{%s}}} extension to generate output in Unix timestamp format: The closest tool to deal with Unix timestamps in Standard Unix, is only the command {{{date}}}. (Ironic, eh?) GNU {{{date}}}, and later BSD date, has a {{{%s}}} extension to generate output in Unix timestamp format:
Line 9: Line 10:
    date +%s # Prints the current time in Unix format, e.g. 1164128484    # GNU/BSD date
date +%s    # Prints the current time in Unix format, e.g. 1164128484
   date -u +%s # Seconds from Epoch AT UTC. This clears local Daytime savings or local time corrections.
Line 15: Line 18:
   start=$(date +%s)    # POSIX shell, with GNU/BSD date
start=$(date -u +%s)
Line 17: Line 21:
   end=$(date +%s)
   echo "Operation took $((end - start)) seconds."
   end=$(date -u +%s)
   echo "Operation took $(($end - $start)) seconds."
Line 21: Line 25:
Now, to convert those Unix timestamps back into human-readable values, one needs to use an external tool. One method is to trick GNU {{{date}}} using: Now, to convert those Unix timestamps back into human-readable values, we need to use {{{date}}} in a special way. The GNU date could perform simple adition and substraction :
Line 23: Line 27:
   date -d "1970-01-01 UTC + 1164128484 seconds"
   # Prints "Tue Nov 21 12:01:24 EST 2006" in the US/Eastern time zone.
   # GNU date
   date -u -d "1970-01-01" +"%s seconds" # Prints "0 seconds"
   date -u -d "1970-01-01" +"%D %T" # Prints "01/01/70 00:00:00"

   date -u -d "1970-01-01 14415 sec" +"%D %T"
   date -u -d @14415 +"%D %T" # Alternative notation
               # Prints "01/01/70 04:00:15", or 4 hours and 15 seconds ahead.
   date -u -d "1970-01-01 14415 sec - 3605 sec" +"%D %T"
               # Prints "01/01/70 03:00:10", that is, 4 hours 15 seconds ahead and 2 hours 5 seconds back.
Line 27: Line 38:
Reading the source code('''!!''') of GNU {{{date}}}'s date parser reveals that it accepts Unix timestamps prefixed with '@', so: So, we can do in just one command (provided start and end vars are values in seconds):
Line 29: Line 40:
   $ date -d "@1164128484"
   # Prints "Tue Nov 21 18:01:24 CET 2006" in the central European time zone
   # Assuming start is "1418347200" and end is "1418350815" (for example):
   date -u -d "1970-01-01 $end sec - $start sec" +"%T"
   # Prints the time difference in the usual (human readable) time format:
   01:00:15
   # the output format could be easily adjusted as needed.
Line 33: Line 47:
However, this undocumented feature only appears to work in extremely ''new'' versions of GNU {{{date}}}. Note that this works only for less than 24 hours. Bigger time spans will require some external math.
Line 35: Line 49:
If you don't have GNU {{{date}}} available, an external language such as Perl can be used:
If you don't have GNU {{{date}}} available, you can use Perl:
Line 58: Line 73:

A convenient way of calculating seconds elapsed since 'YYYY MM DD HH MM SS' is to use awk.

{{{
   echo "2008 02 27 18 50 23" | awk '{print systime() - mktime($0)}'
   # This uses systime() to return the current time in epoch format
   # It then performs mktime() on the input string to return the epoch time of the input string
}}}

To make this more human readable, GNU awk (gawk) can be used:
The format string is similar to date, and is specifed exactly here at http://www.gnu.org/software/gawk/manual/gawk.html#Time-Functions

{{{
   echo "YYYY MM DD HH MM SS" | gawk '{print strftime("%M Minutes, %S Seconds",systime() - mktime($0))}'
   # The gawk-specific strftime() function converts the difference into a human readable format
}}}

How do I convert Unix (epoch) times to human-readable values?

The only sane way to handle time values within a program is to convert them into a linear scale. You can't store "January 17, 2005 at 5:37 PM" in a variable and expect to do anything with it....

Therefore, any competent program is going to use time stamps with semantics such as "the number of seconds since point X". These are called epoch timestamps. If the epoch is January 1, 1970 at midnight UTC, then it's also called a "Unix timestamp", because this is how Unix stores all times (such as file modification times).

The closest tool to deal with Unix timestamps in Standard Unix, is only the command date. (Ironic, eh?) GNU date, and later BSD date, has a %s extension to generate output in Unix timestamp format:

   # GNU/BSD date
   date +%s       # Prints the current time in Unix format, e.g. 1164128484
   date -u +%s    # Seconds from Epoch AT UTC. This clears local Daytime savings or local time corrections.

This is commonly used in scripts when one requires the interval between two events:

   # POSIX shell, with GNU/BSD date
   start=$(date -u +%s)
   ...
   end=$(date -u +%s)
   echo "Operation took $(($end - $start)) seconds."

Now, to convert those Unix timestamps back into human-readable values, we need to use date in a special way. The GNU date could perform simple adition and substraction :

   # GNU date
   date -u -d "1970-01-01" +"%s seconds"      # Prints "0 seconds"
   date -u -d "1970-01-01" +"%D %T"           # Prints "01/01/70 00:00:00"

   date -u -d "1970-01-01 14415 sec" +"%D %T"
   date -u -d @14415 +"%D %T"   # Alternative notation
               # Prints "01/01/70 04:00:15", or 4 hours and 15 seconds ahead.
   date -u -d "1970-01-01 14415 sec - 3605 sec" +"%D %T"
               # Prints "01/01/70 03:00:10", that is, 4 hours 15 seconds ahead and 2 hours 5 seconds back.

So, we can do in just one command (provided start and end vars are values in seconds):

   # Assuming start is "1418347200" and end is "1418350815" (for example):
   date -u -d "1970-01-01 $end sec - $start sec" +"%T"
   # Prints the time difference in the usual (human readable) time format:
   01:00:15
   # the output format could be easily adjusted as needed.

Note that this works only for less than 24 hours. Bigger time spans will require some external math.

If you don't have GNU date available, you can use Perl:

   perl -le "print scalar localtime 1164128484"
   # Prints "Tue Nov 21 12:01:24 2006"

I used double quotes in these examples so that the time constant could be replaced with a variable reference. See the documentation for date(1) and Perl for details on changing the output format.

Newer versions of Tcl (such as 8.5) have very good support of date and clock functions. See the tclsh man page for usage details. For example:

   echo 'puts [clock format [clock scan "today"]]' | tclsh
   # Prints today's date (the format can be adjusted with parameters to "clock format").
   
   echo 'puts [clock format [clock scan "fortnight"]]' | tclsh
   # Prints the date two weeks from now.
   
   echo 'puts [clock format [clock scan "5 years + 6 months ago"]]' | tclsh
   # Five and a half years ago, compensating for leap days and daylight savings time.

A convenient way of calculating seconds elapsed since 'YYYY MM DD HH MM SS' is to use awk.

   echo "2008 02 27 18 50 23" | awk '{print systime() - mktime($0)}'
   # This uses systime() to return the current time in epoch format
   # It then performs mktime() on the input string to return the epoch time of the input string

To make this more human readable, GNU awk (gawk) can be used: The format string is similar to date, and is specifed exactly here at http://www.gnu.org/software/gawk/manual/gawk.html#Time-Functions

   echo "YYYY MM DD HH MM SS" | gawk '{print strftime("%M Minutes, %S Seconds",systime() - mktime($0))}'
   # The gawk-specific strftime() function converts the difference into a human readable format

BashFAQ/070 (last edited 2018-04-02 12:49:27 by GreyCat)