Dec 2, 2011

3 Advanced usages of Linux ‘date’ command

In Linux shell, ‘date’ is a basic command to show current date, like:
$ date
Sat Jan  8 15:34:16 CST 2011
$

From the result, it shows more than just date, and also time and time zone. It’s different from what DOS does, which use two command to get/set date and time. However the ‘date’ command can do much more than this, let’s first check the usage.
Standard version:
$ date --help
Usage: date [OPTION]... [+FORMAT]
  or:  date [-u|--utc|--universal] [MMDDhhmm[[CC]YY][.ss]]
Display the current time in the given FORMAT, or set the system date.
...[skipped]
busybox version:

# date --help
BusyBox v1.11.1 (2010-12-23 19:34:38 CST) multi-call binary

Usage: date [OPTION]... [+FMT] [TIME]
Display time (using +FMT), or set time
...[skipped]


The busybox version has less functions than standard version (of course!), however the following scenarios are supported on both versions.

    1. Show current date/time in a specific format

If the ‘date’ command is followed by a plus sign (+) and immediately the specific format string, it can be sued to determine the date/time output format. Here is all the supported format for ‘date’ command.

FORMAT controls the output.  The only valid option for the second form
specifies Coordinated Universal Time.  Interpreted sequences are:

  %%   a literal %
  %a   locale's abbreviated weekday name (e.g., Sun)
  %A   locale's full weekday name (e.g., Sunday)
  %b   locale's abbreviated month name (e.g., Jan)
  %B   locale's full month name (e.g., January)
  %c   locale's date and time (e.g., Thu Mar  3 23:05:25 2005)
  %C   century; like %Y, except omit last two digits (e.g., 21)
  %d   day of month (e.g, 01)
  %D   date; same as %m/%d/%y
  %e   day of month, space padded; same as %_d
  %F   full date; same as %Y-%m-%d
  %g   last two digits of year of ISO week number (see %G)
  %G   year of ISO week number (see %V); normally useful only with %V
  %h   same as %b
  %H   hour (00..23)
  %I   hour (01..12)
  %j   day of year (001..366)
  %k   hour ( 0..23)
  %l   hour ( 1..12)
  %m   month (01..12)
  %M   minute (00..59)
  %n   a newline
  %N   nanoseconds (000000000..999999999)
  %p   locale's equivalent of either AM or PM; blank if not known
  %P   like %p, but lower case
  %r   locale's 12-hour clock time (e.g., 11:11:04 PM)
  %R   24-hour hour and minute; same as %H:%M
  %s   seconds since 1970-01-01 00:00:00 UTC
  %S   second (00..60)
  %t   a tab
  %T   time; same as %H:%M:%S
  %u   day of week (1..7); 1 is Monday
  %U   week number of year, with Sunday as first day of week (00..53)
  %V   ISO week number, with Monday as first day of week (01..53)
  %w   day of week (0..6); 0 is Sunday
  %W   week number of year, with Monday as first day of week (00..53)
  %x   locale's date representation (e.g., 12/31/99)
  %X   locale's time representation (e.g., 23:13:48)
  %y   last two digits of year (00..99)
  %Y   year
  %z   +hhmm numeric timezone (e.g., -0400)
  %:z  +hh:mm numeric timezone (e.g., -04:00)
  %::z  +hh:mm:ss numeric time zone (e.g., -04:00:00)
  %:::z  numeric time zone with : to necessary precision (e.g., -04, +05:30)

  %Z   alphabetic time zone abbreviation (e.g., EDT)

By default, date pads numeric fields with zeroes.
The following optional flags may follow `%':

  -  (hyphen) do not pad the field
  _  (underscore) pad with spaces
  0  (zero) pad with zeros
  ^  use upper case if possible
  #  use opposite case if possible


It looks a very long table, it’s mandatory to meet any requests. Among these usage, the red color part are not supported by busybox version.
Let’s discover the format by presenting some examples:
$ date
Sat Jan  8 16:32:05 CST 2011
$ date +%x
01/08/2011
$ date %X
date: invalid date `%X' #you’ll get such prompt when missing ‘+’$ date +%X
04:32:22 PM
$ date +%a
Sat
$ date +%A
Saturday
$ date +%D
01/08/11
$ date +%F
2011-01-08
$

If you want a more complicated output (like including a single quote (‘) in your output, you’ll need the double quote (“) to enclose your format string. Here is the example:
$ date +"Hello world. It's: %Y/%m/%d %H:%M:%S"
Hello world. It's: 2011/01/08 16:37:34
$

Yet there is a very special format, normally used when writing a shell script. It’s “%s”, it will show the elapsed time in seconds since January first 1970 (1970/1/1). If you holds two different time with above seconds, then substrate these two number will get the elapsed time (We’ll talk about this later in details). Here is the output of “%s”:
$ date +%s
1294476056
$


    2. Set system time

First of all, one thing you should know: Only root has the permission to set system time. Any other users trying to do this will get a error message “Operation not permitted”, and system time keep unchanged:
$ date 01020101
date: cannot set date: Operation not permitted
Sun Jan  2 01:01:00 CST 2011
$

Normally we don’t do this in a PC Linux, maybe you’ll use NTP client to synchronize with NTP server to get a precision time. Sometimes we’ll set system time in a embedded device, so let’s check the command syntax on busybox:
# date --help
    ...[skipped]
Recognized formats for TIME:
        hh:mm[:ss]
        [YYYY.]MM.DD-hh:mm[:ss]
        YYYY-MM-DD hh:mm[:ss]
        MMDDhhmm[[YY]YY][.ss]
#

busybox provide 4 main formats to set system time, for each format you can yet skipped some parts. Frankly speaking, it’s kind of lousy. So the practical exercise is knowing how to get the help and follow it.Here are some examples:
1. Set system time to 5:35
# date
Mon Jan 10 07:03:27 UTC 2011
# date 5:35
Mon Jan 10 05:35:00 UTC 2011
#

2. Set system date/time to May 8th 0:00
# date
Mon Jan 10 05:36:32 UTC 2011
# date 05080000
Sun May  8 00:00:00 UTC 2011
#

3. Set date/time to 2011 Jan 11st 8:00 PM
# date
Mon Jan 10 05:36:32 UTC 2011
# date 2011.01.11-20:00
Tue Jan 11 20:00:00 UTC 2011
#
As the 3 examples show, you can set just time, or date without year but with time, or a complete setting on year, month, day and time.

    3. Calculate elapsed time

Sometimes we’ll use shell script to do a test or monitor something on the system. It’s good to know how much time has been elapsed.
Utilize “date +%s” mentioned above, and a little calculation, we can generate a shell function to calculate elapsed time. Here is an example:
$ cat elap.bash
#!/bin/bash
function elapsed_time()
{
    s_time=$1
    e_time=$2
    elap_s=$((e_time-s_time))
    ss=$((elap_s%60))
    mm=$(((elap_s/60)%60))
    hh=$((elaps/3600))
    printf "%i:%02i:%02i" $hh $mm $ss
}
begin_time=`date "+%s"`
for i in {1..3};
do
    now_time=`date "+%s"`
    elap_time=`elapsed_time $begin_time $now_time`
    echo "elapsed time=$elap_time"
    sleep 1
done

The function “elapsed_time” reads two arguments generated by “date +%s”, they present two different time point. After a simple calculation, hh, mm and ss, represent elapsed hours, minutes and seconds respectively. Finally the formatted output function “printf” is used to generate the output. One thing to know: this is a simple example, so it doesn’t cover the “day” concept, modify it yourself if you need it.
This simple script will call “elapsed_time” function every second, and print elapsed time.
Here is the execution result:
$ source elap.bash
elapsed time=0:00:00
elapsed time=0:00:01
elapsed time=0:00:02
$

    Summary

Although ‘date’ is a very common command that we usually used, it may also reach a useful function.

No comments:

Post a Comment