Reputation: 11104
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?
Upvotes: 636
Views: 1028132
Reputation: 70977
bash
can show time in microseconds natively!Having to run date
for each logged line is overkill!!
Prefer to use bash's builtins whenever possible.
At time this question was asked, bash 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.
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
$EPOCHSECONDS
pseudo variableFrom 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
The native bash'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"
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 bash 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
$EPOCHREALTIME
before use themImportant: 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
Upvotes: 8
Reputation: 11942
A lot of answers but I couldn't find what I was looking for :
date +"%s.%3N"
returns something like : 1606297368.210
Upvotes: 26
Reputation: 10688
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
Upvotes: 9
Reputation: 3564
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\)) |
Upvotes: 295
Reputation: 1342
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")
Upvotes: 4
Reputation: 524
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
Upvotes: -1
Reputation: 2104
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.
Upvotes: 2
Reputation: 2416
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)
Upvotes: 2
Reputation: 8344
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
Upvotes: 437
Reputation: 614
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
Upvotes: 37
Reputation: 59278
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.
Upvotes: 84
Reputation: 532093
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.
Upvotes: 15
Reputation: 404
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
.
Upvotes: 19
Reputation: 5615
DATE=`date "+%Y%m%d"`
DATE_WITH_TIME=`date "+%Y%m%d-%H%M%S"` #add %3N as we want millisecond too
Upvotes: 115
Reputation: 1
timestamp=$(awk 'BEGIN {srand(); print srand()}')
srand without a value uses the current timestamp with most Awk implementations.
Upvotes: 5
Reputation: 167
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.
Upvotes: 15
Reputation: 9518
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/)
Upvotes: 819