Bash Printf %T Option

Starting with version 4.2 of the popular shell, bash has had the ability to output date-time strings similar to the date manipulation and formatting functionality provided by the printf %T in ksh93, albeit with seriously limited functionality.

From the current bash documentation:


Causes printf to output the date-time string resulting from using datefmt as a 
format string for strftime(3). The corresponding argument is an integer representing 
the number of seconds since the epoch. Two special argument values may be used: -1 
represents the current time, and -2 represents the time the shell was invoked. If no 
argument is specified, conversion behaves as if -1 had been given. This is an exception 
to the usual printf behavior.

Here is an example of each of these options:

$ printf '%(%F %T)T\n' 1597162852
2020-08-11 16:20:52
$ printf '%(%F %T)T\n' -1
2020-08-11 16:24:33
$ printf '%(%F %T)T\n' -2
2020-08-10 04:38:39

Compare and contract this functionality with that of printf %T in ksh93:

    %T    Treat string as a date/time string and format it. The T can be
          preceded by (dformat), where dformat is a date format. The accepted
          date formats are as follows:
            %     % character
            a     abbreviated weekday name
            A     full weekday name
            b     abbreviated month name
            B     full month name
            c     ctime(3) style date without the trailing newline
            C     2-digit century
            d     day of month number
            D     date as mm/dd/yy
            e     blank padded day of month number
            f     print a date with the format '%Y.%m.%d-%H:%M:%S'
            F     %ISO 8601:2000 standard date format; equivalent to Y-%m-%d
            g     ls(1) -l recent date with hh:mm
            G     ls(1) -l distant date with yyyy
            h     abbreviated month name
            H     24-hour clock hour, zero-padded
            i     international date(1) date with time zone type name
            I     12-hour clock hour, zero-padded
            j     1-offset Julian date
            J     0-offset Julian date
            k     24-hour clock hour, blank-padded
            K     all numeric date; equivalent to %Y-%m-%d+%H:%M:%S; %_[EO]K
                  for space separator, %OK adds .%N, %EK adds %.N%z, %_EK adds
                  .%N %z
            l     12-hour clock hour, blank-padded
            L     locale default date format
            m     month number
            M     minutes
            n     newline character
            N     nanoseconds 000000000-999999999
            p     meridian (e.g., AM or PM)
            q     quarter of the year
            Q     <del>recent>del>distant<del>: <del> is 
                  a unique delimiter character; recent format for recent dates, 
                  distant format otherwise
            r     12-hour time as hh:mm:ss meridian
            R     24-hour time as hh:mm
            s     number of seconds since the epoch; .prec preceding s appends
                  prec nanosecond digits, 9 if prec is omitted
            S     seconds 00-60
            t     tab character
            T     24-hour time as hh:mm:ss
            u     weekday number 1(Monday)-7
            U     week number with Sunday as the first day
            V     ISO week number (i18n is fun)
            w     weekday number 0(Sunday)-6
            W     week number with Monday as the first day
            x     locale date style that includes month, day and year
            X     locale time style that includes hours and minutes
            y     2-digit year (you'll be sorry)
            Y     4-digit year
            z     time zone SHHMM west of GMT offset where S is + or -, use pad
                  _ for SHH:MM
            Z     time zone name
                  set (default or +) or clear (-) flag for the remainder of
                  format, or for the remainder of the process if == is
                  specified. flag may be:
                    l     enable leap second adjustments
                    n     convert %S as %S.%N
                    u     UTC time zone
            #     equivalent to %s
                  use alternate format if a default format override has not
                  been specified, e.g., ls(1) uses "%?%l"; export
                  TM_OPTIONS="format='override'" to override the default

As you can see, there is a rich range if date manipulation functionality available in ksh93 compared to the bash shell. BTW, see this post for multiple examples of how to use the printf %T functionality within ksh93.

Here is a simple example of using the %T functionality in bash to retrieve and format the system date:

$ printf "%(%m-%d-%Y)T\n"

Here is an example which prints out the numbers of seconds since the Unix Epoch, followed by a trivial example which prints out a date based on the number of seconds since the Unix Epoch. The third example is a trivial example of date arithmetic.

$ printf '%(%s)T\n'
$ printf '%(%F)T\n' $(date +%s)
$ printf '%(%F)T\n' $(( $(date +%s) - 120000 ))

The bash shell’s printf supports a very useful option, i.e. -v

The -v option causes the output to be assigned to the variable var rather than being printed to the standard output.

Here is an example of how to use this option to assign a date to a variable:

$ printf '%(%F %T)T\n'
2020-08-28 17:52:56
$ printf -v DATESTR '%(%F %T)T\n'
$ echo $DATESTR
2020-08-28 17:53:11

Version 5 of bash supports two special date-related shell variables:


Each time this parameter is referenced, it expands to the number of seconds 
since the Unix Epoch as a floating point value with micro-second granularity
(see the documentation for the C library function time for the definition of 
Epoch). Assignments to EPOCHREALTIME are ignored. If EPOCHREALTIME is unset, 
it loses its special properties, even if it is subsequently reset.


Each time this parameter is referenced, it expands to the number of seconds 
since the Unix Epoch (see the documentation for the C library function time 
for the definition of Epoch). Assignments to EPOCHSECONDS are ignored. If 
EPOCHSECONDS is unset, it loses its special properties, even if it is 
subsequently reset.

Here is an example which uses the EPOCHREALTIME shell variable:

$ printf "%.3f\n" $EPOCHREALTIME

The second command in the above example displays the time in milliseconds since the Unix Epoch as a single lightweight atomic call to an internal bash variable with no rounding issues.

Finally, here is an example which demonstrates the extremely limited functionality of printf %T in the current version (5.0.17) of the bash shell.

$ ksh93
ksh93 $ printf '%(%s)T\n' "2015-09-08 11:07:35"
ksh93 $ exit
$ printf '%(%s)T\n' "2015-09-08 11:07:35"
bash: printf: 2015-09-08 11:07:35: invalid number

Well, that is all for now. Hopefully printf %T date functionality will be enhanced in future releases of the bash shell.

Note: Updated August 2020.

Comments are closed.