622

I am trying to create a timestamp variable in a shell script to make the logging a little easier. I want to create the variable at the beginning of the script and have it print out the current time whenever I issue echo $timestamp. It proving to be more difficult then I thought. Here are some things I've tried:

timestamp="(date +"%T")" echo prints out (date +"%T")

timestamp="$(date +"%T")" echo prints the time when the variable was initialized.

Other things I've tried are just slight variations that didn't work any better. Does anyone know how to accomplish what I'm trying to do?

1
  • kerfile entrypoint
    – Felix
    Commented Jul 1, 2022 at 14:03

18 Answers 18

805

If you want to get unix timestamp, then you need to use:

timestamp=$(date +%s)

%T will give you just the time; same as %H:%M:%S (via http://www.cyberciti.biz/faq/linux-unix-formatting-dates-for-display/)

5
  • 7
    But this variable will just hold the value of the time when the variable was initiated, am I right?
    – lindhe
    Commented Aug 14, 2014 at 23:04
  • 21
    I guess this is getting a lot of upvotes because it answers the title of the question, but it is not answering the question body : D OP wanted to get a different timestamp every time, whereas this will store one for the whole script.
    – fedorqui
    Commented Apr 21, 2016 at 6:23
  • 3
    I came here looking for this exactly. I.e. the proper format string to get a unix timestamp from date. However, I also upvoted the "correct" answer. I wasn't looking for that, but it's a better answer to the original question and it's also really useful to me. Commented Mar 22, 2019 at 17:24
  • Worked fine me after prepending 'shell` timestamp=$(shell date +%s) Commented Mar 8, 2021 at 8:15
  • @fedorqui so what hinders op to just re-initialize the variable each time?
    – clockw0rk
    Commented Aug 9, 2022 at 10:57
435

In order to get the current timestamp and not the time of when a fixed variable is defined, the trick is to use a function and not a variable:

#!/bin/bash

# Define a timestamp function
timestamp() {
  date +"%T" # current time
}

# do something...
timestamp # print timestamp
# do something else...
timestamp # print another timestamp
# continue...

If you don't like the format given by the %T specifier you can combine the other time conversion specifiers accepted by date. For GNU date, you can find the complete list of these specifiers in the official documentation here: https://www.gnu.org/software/coreutils/manual/html_node/Time-conversion-specifiers.html#Time-conversion-specifiers

9
  • 34
    Depending on how you intend to use this, you'll still need to use command substitution: echo "$(timestamp): something happened".
    – chepner
    Commented Jun 12, 2013 at 13:16
  • 7
    As for formatting, here is a cut-and-dried set of most frequent formats: zxq9.com/archives/795
    – zxq9
    Commented Nov 8, 2014 at 16:38
  • 256
    For me, I wanted date +"%Y-%m-%d_%H-%M-%S" Commented Dec 31, 2014 at 17:57
  • 4
    for some reason this didn't give me the timestamp but the current time with ":" in between.
    – erikbstack
    Commented Apr 13, 2017 at 11:06
  • 13
    I think a lot of people arrive at this question looking for a way to generate a unix timestamp (as I have) and find the answer by dchakarov to be more useful even though this answer better addresses the asker's question. Commented Jun 16, 2017 at 17:48
266

You can refer to the following table to generate timestamps in various formats:

Format / result Command Output
YYYY-MM-DD date -I $(date -I)
YYYY-MM-DD_hh:mm:ss date +%F_%T $(date +%F_%T)
YYYYMMDD_hhmmss date +%Y%m%d_%H%M%S $(date +%Y%m%d_%H%M%S)
YYYYMMDD_hhmmss (UTC version) date --utc +%Y%m%d_%H%M%SZ $(date --utc +%Y%m%d_%H%M%SZ)
YYYYMMDD_hhmmss (with local TZ) date +%Y%m%d_%H%M%S%Z $(date +%Y%m%d_%H%M%S%Z)
YYYYMMSShhmmss date +%Y%m%d%H%M%S $(date +%Y%m%d%H%M%S)
YYYYMMSShhmmssnnnnnnnnn date +%Y%m%d%H%M%S%N $(date +%Y%m%d%H%M%S%N)
YYMMDD_hhmmss date +%y%m%d_%H%M%S $(date +%y%m%d_%H%M%S)
Seconds since UNIX epoch date +%s $(date +%s)
Nanoseconds only date +%N $(date +%N)
Nanoseconds since UNIX epoch date +%s%N $(date +%s%N)
ISO8601 UTC timestamp date --utc +%FT%TZ $(date --utc +%FT%TZ)
ISO8601 UTC timestamp + ms date --utc +%FT%T.%3NZ $(date --utc +%FT%T.%3NZ)
ISO8601 Local TZ timestamp date +%FT%T%Z $(date +%FT%T%Z)
YYYY-MM-DD (Short day) date +%F\(%a\) $(date +%F\(%a\))
YYYY-MM-DD (Long day) date +%F\(%A\) $(date +%F\(%A\))
3
  • 34
    Not often do I have to scroll through 11 other answers to find the best one. :) Commented Oct 10, 2021 at 0:21
  • 2
    Pay attention todate -I, it does not work on macos bash or zsh. Nevertheless very useful answer.
    – freedev
    Commented Oct 2, 2022 at 21:50
  • $(date +%F) $(date +%T) if you don't want the underscore between date and time
    – Grumoll
    Commented Sep 20, 2023 at 11:23
114
DATE=`date "+%Y%m%d"`

DATE_WITH_TIME=`date "+%Y%m%d-%H%M%S"` #add %3N as we want millisecond too
2
  • 5
    +1 for adding the millisecond part. This echo $(date +"%Y-%m-%dT%T.%3N%z") However I can't get it to work in a Mac terminal. How to do the same in Mac. Thanks
    – kosgeinsky
    Commented Mar 18, 2019 at 9:18
  • 1
    @kosgeinsky I installed GNU date via brew install coreutils and then use gdate instead of date Commented May 3, 2023 at 1:36
84

ISO 8601 format (2018-12-23T12:34:56) is more readable than UNIX timestamp. However on some OSs you cannot have : in the filenames. Therefore I recommend using something like this instead:

2018-12-23_12-34-56

You can use the following command to get the timestamp in this format:

TIMESTAMP=`date +%Y-%m-%d_%H-%M-%S`

This is the format I have seen many applications use. Another nice thing about this is that if your file names start with this, you can sort them alphabetically and they would be sorted by date.

2
  • 4
    TZ=UTC date +... can make this more portable by using UTC timestamp Commented Dec 14, 2019 at 10:16
  • Incorporating @MichaelChirico's comment and adding a Zulu time (== UTC) Z at the end; and modifying @Caner's to use T: TIMESTAMP="$(TZ=UTC date +%Y-%m-%dT%H_%M_%SZ)"
    – Abdull
    Commented Dec 10, 2021 at 11:30
36

And for my fellow Europeans, try using this:

timestamp=$(date +%d-%m-%Y_%H-%M-%S)

will give a format of the format: "15-02-2020_19-21-58"

You call the variable and get the string representation like this

$timestamp
4
  • 1
    Please consider using the code notation for your code.
    – sao
    Commented Feb 15, 2020 at 18:49
  • 1
    or a universal solution: date +%Y-%m-%d_%H-%M-%S - and thank you for your answer. Commented Feb 7, 2021 at 16:48
  • 2
    As a European, I've never used DD-MM-YYYY in my life, always YYYY-MM-DD for everything. That is different from writing "22nd June 2022" in a document, but numerically its never "22-06-2022", its always "2022-06-22". Just saying.
    – Kareem
    Commented Aug 11, 2022 at 10:30
  • Good for you :-) Commented Aug 11, 2022 at 11:56
25

A lot of answers but I couldn't find what I was looking for :

date +"%s.%3N"

returns something like : 1606297368.210

5
  • 2
    On MacOS the built-in date doesn't support the %N format; see stackoverflow.com/a/33641565/1677912.
    – Mogsdad
    Commented Aug 13, 2021 at 17:15
  • 2
    Yes, lots of answers, most of which are wrong because people apparently didn't read the question
    – giordano
    Commented Aug 16, 2021 at 16:14
  • 1
    This works and I wonder what's the meaning of symbol N
    – Jerry An
    Commented Nov 19, 2021 at 2:43
  • They say "Nanoseconds", makes sense: stackoverflow.com/a/69400542/3322400
    – Loïc
    Commented May 27, 2023 at 13:02
  • was looking for this, simple and effective
    – PauAI
    Commented Nov 1, 2023 at 15:02
21

Use command substitution:

timestamp=$( date +%T )
2
  • 3
    This is what I already tried and it only prints out the time when the variable was initialized.
    – Dan
    Commented Jun 12, 2013 at 13:09
  • 12
    @dan08: That's how variables work. Use a function if you want dynamic output.
    – choroba
    Commented Jun 12, 2013 at 13:09
19

I am using ubuntu 14.04.

The correct way in my system should be date +%s.

The output of date +%T is like 12:25:25.

1
15

You can use

timestamp=`date --rfc-3339=seconds`

This delivers in the format 2014-02-01 15:12:35-05:00

The back-tick (`) characters will cause what is between them to be evaluated and have the result included in the line. date --help has other options.

3
  • 1
    As for what time it gets, this should be executed immediately before inclusion in screen output or a log file intended to have the time of the output listed.
    – Bill
    Commented Feb 1, 2014 at 20:25
  • 2
    this is less than ideal format for a timestamp because of the space in the output. Be sure to quote it "$timestamp" in usage or you will get two params to the command. e.g. touch $timestamp will produce two files.
    – harschware
    Commented Apr 7, 2017 at 16:12
  • 1
    For those wanting to customize this to remove the space, date --rfc-3339=... is (roughly?) equivalent to date '+%F %T%:z', so removing the space is simply (eg): date '+%F_%T%:z'
    – michael
    Commented Aug 29, 2020 at 10:37
15

Recent versions of bash don't require call to the external program date:

printf -v timestamp '%(%T)T'

%(...)T uses the corresponding argument as a UNIX timestamp, and formats it according to the strftime-style format between the parentheses. An argument of -1 corresponds to the current time, and when no ambiguity would occur can be omitted.

8

bash can show time in microseconds natively!

1. Avoid forks!!!

Having to run date for each logged line is overkill!!

Prefer to use bash's builtins whenever possible.

At time this question was asked, version was bash-4.2.

In this version, the pure bash way for printing current time is:

printf '%(%T)T\n' -1

or

printf '%(%T)T\n' -1

So a short function login each lines with timestamp could be:

logLine() {
    printf '%(%T)T %s\n' -1 "$*"
}

Then

$ logLine Hello world.
10:11:32 Hello world.

2. Time in seconds, using printf builtin:

For storing current time into a variable, you will use:

printf -v varname '%(%T)T' -1

or to store (reusable) UNIX EPOCH:

printf -v varname '%(%s)T' -1

Then

printf 'Stored time stamp is: %(%c)T\n' "$varname"
Stored time stamp is: Sat Jan 27 04:26:00 2018

2.1 Time in seconds, using $EPOCHSECONDS pseudo variable

From version 5.0-alpha of bash, (2018-05-22) we could use two pseudo variables: $EPOCHSECONDS and $EPOCHREALTIME:

man -P'less +/EPOCH' bash
EPOCHREALTIME
       Each time this parameter is referenced, it expands to the number
       of  seconds  since  the  Unix  Epoch (see time(3)) as a floating
       point  value  with  micro-second  granularity.   Assignments  to
       EPOCHREALTIME  are ignored.  If EPOCHREALTIME is unset, it loses
       its special properties, even if it is subsequently reset.
EPOCHSECONDS
       Each time this parameter is referenced, it expands to the number
       of  seconds  since the Unix Epoch (see time(3)).  Assignments to
       EPOCHSECONDS are ignored.  If EPOCHSECONDS is  unset,  it  loses
       its special properties, even if it is subsequently reset.
echo $EPOCHSECONDS
1692818546
myvar=$EPOCHSECONDS
echo $myvar
1692818547

Sample: Sleep until next minute

sleep $((60-EPOCHSECONDS%60));printf '%(%T)T\n' -1
21:26:00

3. EPOCH time expansion.

The native 's printf could expand UNIX EPOCH SECONDS by the classic date rules. See: man -P'less +/^\ *FORMAT' date or have a look at Instein's answer.

printf '%(%A %d %B %Y, %H:%M)T\n' $EPOCHSECONDS
Friday 24 November 2023, 09:21

With the big advantage of avoiding fork to set variable:

printf -v renderedTime '%(%A %d %B %Y, %H:%M)T' $EPOCHSECONDS
declare -p renderedTime
declare -- renderedTime="Friday 24 November 2023, 09:22"

4. About microseconds

Today, I use bash >= 5.1.4...

From version 5.0-alpha of bash, (2018-05-22):

b. There is an EPOCHSECONDS variable, which expands to the time in seconds since the Unix epoch.

c. There is an EPOCHREALTIME variable, which expands to the time in seconds since the Unix epoch with microsecond granularity.

So if you want to use microsecond granularity, function could become:

logLine() {
    local now=$EPOCHREALTIME
    printf '%(%T)T.%s %s\n' ${now%.*} ${now#*.} "$*"
}

Then

$ logLine Hello world.
10:15:56.862732 Hello world.

Sleep until next minute become a little more complex as can't compute real numbers:

slptim=00000$((60000000-${EPOCHREALTIME/.}%60000000));\
  printf -v slptim %.6f ${slptim::-6}.${slptim: -6};\
  sleep $slptim;\
  now=${EPOCHREALTIME};\
  printf '%(%H:%M)T:%06.3f\n' ${now%.*} $((${now%.*}%60)).${now#*.}
21:44:00.001

Storing $EPOCHREALTIME before use them

Important: But care! _both variables are not expanded in same way!! See: Don't mix EPOCHREALTIME and EPOCHSECONDS!!!

And Avoid to expand $EPOCHREALTIME two times for separating integer and fractional part:

Don't do this:

nowSec=${EPOCHREALTIME%.*}
nowMus=${EPOCHREALTIME#*.}

But ensure expanding $EPOCHREALTIME only once and split them simultaneously:

IFS=. read nowSec nowMus <<<"$EPOCHREALTIME"

So you could:

printf '%(%a %d %T)T.%s\n' $nowSec $nowMus
Fri 24 09:31:00.166914

Or even to reduce number or decimal:

printf -v nowMus %.3f .$nowMus
printf '%(%a %d %T)T.%s\n' $nowSec ${nowMus#*.}
Fri 24 09:31:00.167
0
7

A timestamp formatting trick for GNU bash, version 4.4.20(1)-release (x86_64-pc-linux-gnu)

 echo "$(date +%Y-%m-%d_%H:%M:%S.%6N) Info >>> enter main"

output:

 2023-01-08_23:08:48.013592 Info >>> enter main

If you want to replace '_' with a space, do the following (w/o '\' got error message)

 echo "$(date +%Y-%m-%d\ %H:%M:%S.%6N) Info >>> enter main"
 echo "$(date +%Y-%m-%d\ %T.%6N) Info >>> enter main"

output:

 2023-01-08 23:10:40.692674 Info >>> enter main
5
timestamp=$(awk 'BEGIN {srand(); print srand()}')

srand without a value uses the current timestamp with most Awk implementations.

1
  • 2
    fwiw, being curious about the performance: the following print the same: (1) awk '....' (as shown above); (2) date '+%s'; (3) printf '%(%s)T'; listed in order of increasing performance: on my system, date is roughly 2x faster than awk; and printf is over 50x faster than date & 100x faster than awk.
    – michael
    Commented Aug 29, 2020 at 10:32
4

You can do this with following comands.

For timestamp with seconds: checkDate=$(date "+%s")

For formated date: checkDate=$(date "+%Y-%m-%d %H:%M:%S")

2

This is a little more than you asked, so you can customize it to your needs.

I am trying to create a timestamp variable in a shell script...

This script will allow you to create a variable. Though I'm not entirely sure how reusable is when changing the shell context. But it will do the job.

function timestamp {
    TEXT="Date:"
    DATE=`date +%Y-%m-%d`
    TIME=`date +%H:%M:%S`
    ZONE=`date +"%Z %z"`
    echo $TEXT $DATE $TIME $ZONE
}

function fulldate {
  timevariable=$(timestamp)
  echo $timevariable
}

echo "- Output 1:"
timestamp
echo "- Output 2:"
fulldate
echo "- Output 3:"
echo $timevariable

Outputs:

- Output 1:
Date: 2021-08-12 23:28:08 UTC +0000
- Output 2:
Date: 2021-08-12 23:28:08 UTC +0000
- Output 3:
Date: 2021-08-12 23:28:08 UTC +0000

I've tested this working on GNU bash, version 4.4.23(1)-release (x86_64-pc-msys)

2

If performance is a concern, @chepner's answer is a clear winner.

With a bit more complexity, you can also get micro- or milli- second granularity using only bash built-ins. Below is an example of a function that emits the current timestamp including milliseconds:

timestamp() {
    IFS=. read S US <<<$EPOCHREALTIME # Read epoch seconds/microseconds
    MS=$((10#$US/1000)) # Convert to milliseconds (interpret in base-10, even with leading 0)
    printf '%(%F %T)T.%03i' $S $MS # Emit formatted timestamp
}

TS=$(timestamp) # Invoke function, assign to variable

Note that the printf format can be adjusted emit your preferred date/time format.

-1

The following will give local date and time - it does require internet access however. Depending on what is being logged, this could be beneficial - monitoring and logging connection status?

curl -i --silent https://google.com/ 2>&1 | grep date

date: Fri, 03 Jun 2022 17:39:19 GMT

Not the answer you're looking for? Browse other questions tagged or ask your own question.