Bash convert string to timestamp
Solution 1
With GNU date, you can convert YYYY-MM-DDTHH:MM:SS
to epoch time (seconds since 1-1-1970) easily, like so:
date -d '2014-12-25T09:30:00' +%s
To do this starting without any delimiters:
in=20141225093000
rfc_form="${in:0:4}-${in:4:2}-${in:6:2}T${in:8:2}:${in:10:2}:${in:12:2}"
epoch_time=$(date -d "$rfc_form" +%s)
Solution 2
This Bash function does the conversion with builtins:
# Convert UTC datetime string (YYYY-MM-DD hh:mm:ss) to Unix epoch seconds
function ymdhms_to_epoch
{
local -r ymdhms=${1//[!0-9]} # Remove non-digits
if (( ${#ymdhms} != 14 )) ; then
echo "error - '$ymdhms' is not a valid datetime" >&2
return 1
fi
# Extract datetime components, possibly with leading zeros
local -r year=${ymdhms:0:4}
local -r month_z=${ymdhms:4:2}
local -r day_z=${ymdhms:6:2}
local -r hour_z=${ymdhms:8:2}
local -r minute_z=${ymdhms:10:2}
local -r second_z=${ymdhms:12:2}
# Remove leading zeros from datetime components to prevent them
# being treated as octal values
local -r month=${month_z#0}
local -r day=${day_z#0}
local -r hour=${hour_z#0}
local -r minute=${minute_z#0}
local -r second=${second_z#0}
# Calculate Julian Day Number (jdn)
# (See <http://en.wikipedia.org/wiki/Julian_day>, Calculation)
local -r -i a='(14-month)/12'
local -r -i y=year+4800-a
local -r -i m=month+12*a-3
local -r -i jdn='day+(153*m+2)/5+365*y+(y/4)-(y/100)+(y/400)-32045'
# Calculate days since the Unix epoch (1 Jan. 1970)
local -r -i epoch_days=jdn-2440588
local -r -i epoch_seconds='((epoch_days*24+hour)*60+minute)*60+second'
echo $epoch_seconds
return 0
}
Example usage:
$ ymdhms_to_epoch '1970-01-01 00:00:00'
0
$ ymdhms_to_epoch '2014-10-18 00:10:06'
1413591006
$ ymdhms_to_epoch '2014-12-25 09:30:00'
1419499800
Solution 3
You need to transform the string before calling date
:
#!/bin/bash
s="20141225093000"
s=$(perl -pe 's/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/$1-$2-$3 $4:$5:$6/g' <<< "$s")
date -d "$s" +%s
Yet another way:
perl -MDate::Parse -MPOSIX -le '$s="20141225093000"; $s =~ s/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/$1-$2-$3 $4:$5:$6/g ; print str2time($s);'
1419499800
Solution 4
GNU awk:
gawk -v t=20141225093000 'BEGIN {gsub(/../, "& ", t); sub(/ /,"",t); print mktime(t)}'
If GNU date is not available, then it's likely GNU awk may not be. Perl probably has the highest chance of being available. This snippet uses strptime
so you don't have to parse the time string at all:
perl -MTime::Piece -E 'say Time::Piece->strptime(shift, "%Y%m%d%H%M%S")->epoch' 20141225093000
user3979986
Updated on June 14, 2022Comments
-
user3979986 almost 2 years
I have a string in format
20141225093000
which representsDec 25, 2014 09:30:00
and I want to convert the original format to a unix timestamp format so i can do time operations on it.How would I do this in bash?I can easily parse out the values with
expr
but I was hoping to be able to identify a format like YYYYmmddHHMMSS and then convert it based on that. -
Charles Duffy over 9 yearsIf you're going to use
perl
, why not do the whole thing there? That way you don't need to depend on GNU date (and will work on non-GNU platforms such as MacOS)... and Perl's date-time libraries will take a format string, so you can do the actual conversion in a shorter/more readable way. -
Charles Duffy over 9 years+1: Tooling with a reasonable chance of being installed in places where GNU date is not.
-
Tiago Lopo over 9 years@CharlesDuffy it could be done in
perl
but when I seesh
bash
tags I limit my perl commands to one-liner and avoid using non-core modules which may not be installed. -
Charles Duffy over 9 yearsfair 'nuff, but if you're trying to honor the
bash
tag, none of the functionality you used in perl is anything bash doesn't already have built-in (there's already support for regular expressions with capture and group extraction via the=~
operator and BASH_REMATCH). -
Tiago Lopo over 9 years@CharlesDuffy Date::Parse and POSIX are core modules so I can use :)
-
Charles Duffy over 9 years+1; adds something new and useful to the other answers (by being something that'll work on systems with neither GNU date nor GNU awk). :)
-
Charles Duffy over 9 yearsInteresting. Have you compared results against a canonical implementation? I'm curious as to whether there are other factors such as leap seconds involved.
-
pjh over 9 yearsI compared the results of this implementation against GNU 'date' for a large number of random dates and times between 1970 and 2038 on a modern Linux system. They all agreed. The GNU 'date' documentation (gnu.org/software/coreutils/manual/html_node/…) suggests that most systems do not use leap seconds. Even on a system that did use leap seconds, this implementation could be useful for the purposes suggested in the question.