Configuring date command to meet my format - linux

I have a date in YYYY.MM.DD HH:SS format (e.g. 2014.02.14 13:30). I'd like to convert it in seconds since epoch using the date command.
The command
date -d"2014.02.14 13:30" +%s
won't work, because of the dots separation.
Any Ideas?

Why don't you make the date format acceptable? Just replace dots with dashes:
$ date --date="`echo '2014.02.14 13:30' | sed 's/\./-/g'`" +%s
1392370200
Here I first change the format:
$ echo '2014.02.14 13:30' | sed 's/\./-/g'
2014-02-14 13:30
and then use the result as a parameter for date.
Note that the result depends on your timezone.

You can use:
s='2014.02.14 13:30'
date -d "${s//./}"
Fri Feb 14 13:30:00 EST 2014
To get EPOCH value:
date -d "${s//./}" '+%s'
1392402600

using awk :
s=`echo "2014.02.14 13:30" | awk '{gsub(/\./,"-",$0);print $0}'`
echo -d "$s"
date -d "$s" +%s
output:
Fri Feb 14 13:30:00 IST 2014
1392364800

Perl: does not require you to munge the string
d="2014.02.14 13:30"
epoch_time=$(perl -MTime::Piece -E 'say Time::Piece->strptime(shift, "%Y.%m.%d %H:%M")->epoch' "$d")
echo $epoch_time
1392384600
Timezone: Canada/Eastern

I Finally solved it using
awk 'BEGIN{FS=","}{ gsub(/./," ",$1);gsub(/:/," ",$2); var=sprintf("%s %s 00",$1,$2); print mktime(var), $3,$4,$5,$6,$7 }' myfile | less
so myfile:
2014.09.24,15:15,1.27921,1.27933,1.279,1.27924,234
became
1411582500 1.27921 1.27933 1.279 1.27924 234
:)

Related

bash is eating spaces from date format in linux

date format shows correct when i execute just date but when I store in a variable, loosing a space in date if it has single digit(need that extra space to grep /var/log/messages). please suggest to get the exact format as it is. thanks!
$date -d '-1 day' '+%b %e'
Aug 1
$echo $(date -d '-1 day' '+%b %e')
Aug 1
$var=`date -d '-1 day' '+%b %e'`
$echo $var
Aug 1
Use double-quotes like this:
$ echo $(date -d '+1 day' '+%b %e')
Aug 2
$ echo "$(date -d '+1 day' '+%b %e')"
Aug 2
Or:
$ var="$(date -d '+1 day' '+%b %e')"
$ echo $var
Aug 2
$ echo "$var"
Aug 2
Without double-quotes, the shell, among other things, applies word splitting to the output and that collapses multiple spaces to one blank.

print time in double decimal shell script

how can I print output in double decimal.
below command will print hour in GMT format but i want output as 06 and for double digit hour it should be 10,11,12.
date -u --date="today" +"%I" | awk -F' ' '{print $1-1}'
6
You may use printf "%02d" in awk to achieve it,
$ date -u --date="today" +"%I" | awk -F' ' '{printf "%02d\n",$1-1}'
06
Perhaps you want:
date -u --date="- 1 hour" +"%I"`
If the time adjustment is part of your date string, the format will not be munged.
Alternately, if what you really want is a way to zero-pad a number in bash or awk, you have a variety of alternatives:
date -u --date="- 1 hour" +"%I" | awk '{printf "%02d\n",$1-1}'
Or in bash alone:
read hour < <( date -u --date="- 1 hour" +"%I" )
printf '%02d\n' "$hour"
Get the idea? Output format happens when you print your output, and printf in whatever language formats your output.
awk is superfluous here. You can use a relative time format with date:
date -u --date="-1 hour" +"%I"
06

need to split "date" command ouput in shell

I want to split date command output and extract time zone difference and represent that time difference in terms of 30 min.
I tried this:
date -R | awk 'NF>1{print $NF}'
I got the output -0530
This means 5 hours and 30 min difference from GMT. Now I want to convert this -0530 in to -11. So what logic should I use in shell command?
date -R | awk '{tz=$NF;ew=substr(tz,1,1);h=substr(tz,1,3)*2;m=ew substr(tz,4,2)/30;print h + m}'
https://en.wikipedia.org/wiki/ISO_8601#Time_offsets_from_UTC
Edited to work with omitted sign
date -R | awk '{tz=$NF;l=length(tz);m=substr(tz,l-1,2)/30;h=substr(tz,l-3,2)*2;ew=l>4?ew=substr(tz,1,1):"+";print (ew h)+(ew m)}'
No need to complicate things.
tz=$(date '+%z'); echo "${tz:0:1}$(( 2 * ${tz:1:2} + ${tz:3} ))"
I wouldn't, and instead use a different tool. In the perl module Time::Piece you have tzoffset which returns the current timezone skew in seconds.
Thus:
#!/usr/bin/env perl
use strict;
use warnings;
use Time::Piece;
$ENV{'TZ'}='GMT-6';
my $now = localtime;
#find number of 30m differences;
print $now -> tzoffset / 60 / 30;
You can also use variants of strftime to print time formatted to your liking:
print $now -> strftime("%c");
This can be cut down into a one liner if so desired:
perl -MTime::Piece 'print localtime -> tzoffset / 60 / 30'
With GNU date, you could perform math on time/date values (in UTC):
$ date -uR -d "now"; date -uR -d "now -60 min"
Sun, 27 Dec 2015 20:34:17 +0000
Sun, 27 Dec 2015 19:34:17 +0000
A time of -5:30 is -330 min:
$ date -uR -d "now"; date -uR -d "now -330 min"
Sun, 27 Dec 2015 20:34:55 +0000
Sun, 27 Dec 2015 15:04:55 +0000
That could be further moved by the time zone:
$ TZ=America/New_York date -R -d "now"; TZ=America/New_York date -R -d "now -330 min"
Sun, 27 Dec 2015 15:34:26 -0500
Sun, 27 Dec 2015 10:04:26 -0500
That is the local time (now) subtracting 5 hours and 30 minutes.
However, what is a time zone of -5:30?
I know that India is +5:30 and there are some (very few) places that are +11:00.
But I fail to find any -5:30 and -11:00 seems just odd.

set bash variable from two nested programs

I need to run many times an aplication and get some statistcs using some commands.
A simple exemple of what I'm traying to do is:
/usr/bin/time --format="%U" date
This line will print:
Seg Nov 2 22:15:28 BRST 2015
0.00
I need to format this output, and I want to do this using bash, like this:
echo "$usertime & $date"
where $usertime is the result from /usr/bin/time --format="%U" and $date the result of date
I know that the below works, but I don't know how to separate the values into two variables:
OUTPUT=`/usr/bin/time --format="%U" date`
echo "$OUTPUT"
the output from above is:
0.00
Seg Nov 2 22:23:50 BRST 2015
(in reverse order)
Using awk
Here, awk is used to reverse the line order and format the output:
$ /usr/bin/time --format="%U" date 2>&1 | awk 'NR==1{d=$0;next} {print $0 " & " d}'
0.00 & Mon Nov 2 16:58:40 PST 2015
Using sed
$ /usr/bin/time --format="%U" date 2>&1 | sed -E 'N; s/([^\n]*)\n(.*)/\2 \& \1/'
0.00 & Mon Nov 2 17:01:15 PST 2015
Using shell
$ /usr/bin/time --format="%U" date 2>&1 | ( read d; read t; echo "$t & $d" )
0.00 & Mon Nov 2 17:04:40 PST 2015
/usr/bin/time is writing the time to standard error, whereas the output of date is going to standard output. If you want them in separate variables, you can write the output of time to a file with the -o flag, then read it back in to another variable:
OUTPUT=`/usr/bin/time -o timefile --format="%U" date`
TIME=$(<timefile)

Replace strings with evaluated string based on matched group (elegant way, not using for .. in)

I'm looking for a way to replace strings of a file, matched by a regular expression, with another string that will be generated/evaluated out of the matched string.
For example, I want to replace the timestamps (timestamp + duration) in this file
1357222500 3600 ...
Maybe intermediate strings...
1357226100 3600 ...
Maybe intermediate strings...
...
By human readable date representations (date range).
Until now, I always used shell scripts like Bash to iterate over each line, matching for the line X, getting the matched group string and printing the line after processing, for example this way (from memory):
IFS="
"
for L in `cat file.txt`; do
if [[ "${L}" =~ ^([0-9]{1,10})\ ([0-9]{1,4})\ .*$ ]]; then
# Written as three lines for better readability/recognition
echo -n "`date --date=#${BASH_REMATCH[1]}` - "
echo -n "`date --date=#$(( ${BASH_REMATCH[1]} + ${BASH_REMATCH[2]} ))`"
echo ""
else
echo "$L"
fi
done
I wonder if there's something like this with a fictional(?) "sed-2.0":
cat file.txt | sed-2.0 's+/^\([0-9]\{1,10\}\) \([0-9]\{1,4\}\) .*$+`date --date="#\1"` - `date --date="#$(( \1 + \2 ))`'
Whereas the backticks in the sed-2.0 replacement will be evaluated as shell command passing the matched groups \1 and \2.
I know that this does not work as expected, but I'd like to write someting like this.
Edit 1
Edit of question above: added missing echo "" in if of Bash script example.
This should be the expected output:
Do 3. Jan 15:15:00 CET 2013 - Do 3. Jan 16:15:00 CET 2013
Maybe intermediate strings...
Do 3. Jan 16:15:00 CET 2013 - Do 3. Jan 17:15:00 CET 2013
Maybe intermediate strings...
...
Note, that the timestamp depends on the timezone.
Edit 2
Edit of question above: fixed syntax error of Bash script example, added comment.
Edit 3
Edit of question above: fixed syntax error of Bash script example. Changed the phrase "old-school example" to "Bash script example".
Summary of Kent's and glenn jackman's answer
There's a huge difference in both approaches: the execution time. I've compared all four methods, here are the results:
gawk using strftime()
/usr/bin/time gawk '/^[0-9]+ [0-9]+ / {t1=$1; $1=strftime("%c -",t1); $2=strftime("%c",t1+$2)} 1' /tmp/test
...
0.06user 0.12system 0:00.30elapsed 60%CPU (0avgtext+0avgdata 1148maxresident)k
0inputs+0outputs (0major+327minor)pagefaults 0swaps
gawk using execution through getline (Gnu AWK Manual)
/usr/bin/time gawk '/^[0-9]{1,10} [0-9]{1,4}/{l=$1+$2; "date --date=#"$1|getline d1; "date --date=#"l|getline d2;print d1" - "d2;next;}1' /tmp/test
...
1.89user 7.59system 0:10.34elapsed 91%CPU (0avgtext+0avgdata 5376maxresident)k
0inputs+0outputs (0major+557419minor)pagefaults 0swaps
Custom Bash script
./sed-2.0.sh /tmp/test
...
3.98user 10.33system 0:15.41elapsed 92%CPU (0avgtext+0avgdata 1536maxresident)k
0inputs+0outputs (0major+759829minor)pagefaults 0swaps
sed using e option
/usr/bin/time sed -r 's#^([0-9]{1,10}) ([0-9]{1,4})(.*$)#echo $(date --date=#\1 )" - "$(date --date=#$((\1+\2)))#ge' /tmp/test
...
3.88user 16.76system 0:21.89elapsed 94%CPU (0avgtext+0avgdata 1272maxresident)k
0inputs+0outputs (0major+1253409minor)pagefaults 0swaps
Input data
for N in `seq 1 1000`; do echo -e "$(( 1357226100 + ( $N * 3600 ) )) 3600 ...\nSomething else ..." >> /tmp/test ; done
We can see that AWK using the strffime() method is the fastest. But even the Bash script is faster than sed with shell execution.
Kent showed us a more generic, universal way to accomplish what I've asked for. My question actually was not only limited to my timestamp example. In this case I had to do exactly this (replacing timestamp + duration by human readable date representation), but I had situations where I had to execute other code.
glenn jackman showed us a specific solution which is suitable for situations were you can do string operations and calculation directly in AWK.
So, it depends on the time you have (or time your script may run), the amount of the data and use case which method should be preferred.
based on your sample input:
gawk '/^[0-9]+ [0-9]+ / {t1=$1; $1=strftime("%c -",t1); $2=strftime("%c",t1+$2)} 1'
outputs
Thu 03 Jan 2013 09:15:00 AM EST - Thu 03 Jan 2013 10:15:00 AM EST ...
Maybe intermediate strings...
Thu 03 Jan 2013 10:15:00 AM EST - Thu 03 Jan 2013 11:15:00 AM EST ...
Maybe intermediate strings...
...
awk oneliner: (the datetime format could be different from your output)
awk '/^[0-9]{1,10} [0-9]{1,4}/{l=$1+$2; "date --date=#"$1|getline d1; "date --date=#"l|getline d2;print d1" - "d2;next;}1' file
test:
kent$ echo "1357222500 3600 ...
Maybe intermediate strings...
1357226100 3600 ...
Maybe intermediate strings...
..."|awk '/^[0-9]{1,10} [0-9]{1,4}/{l=$1+$2; "date --date=#"$1|getline d1; "date --date=#"l|getline d2;print d1" - "d2;next;}1'
Thu Jan 3 15:15:00 CET 2013 - Thu Jan 3 16:15:00 CET 2013
Maybe intermediate strings...
Thu Jan 3 15:15:00 CET 2013 - Thu Jan 3 17:15:00 CET 2013
Maybe intermediate strings...
...
Gnu sed
if you have gnu sed, the idea from your "not working" sed line could work in real world by applying gnu sed's s/foo/shell cmds/ge see below:
sed -r 's#^([0-9]{1,10}) ([0-9]{1,4})(.*$)#echo $(date --date=#\1 )" - "$(date --date=#$((\1+\2)))#ge' file
test
kent$ echo "1357222500 3600 ...
Maybe intermediate strings...
1357226100 3600 ...
Maybe intermediate strings...
..."|sed -r 's#^([0-9]{1,10}) ([0-9]{1,4})(.*$)#echo $(date --date=#\1 )" - "$(date --date=#$((\1+\2)))#ge'
Thu Jan 3 15:15:00 CET 2013 - Thu Jan 3 16:15:00 CET 2013
Maybe intermediate strings...
Thu Jan 3 16:15:00 CET 2013 - Thu Jan 3 17:15:00 CET 2013
Maybe intermediate strings...
...
if I would work on this, personally I would go with awk. because it is straightforward and easy to write.
at the end I paste my sed/awk version info :
kent$ sed --version|head -1
sed (GNU sed) 4.2.2
kent$ awk -V|head -1
GNU Awk 4.0.1

Resources