How to get epoch time in shell script (for ksh)? - ksh

How to get epoch time in shell script (for ksh)?
I am interested in getting epoch time for the start of day (so e.g. now is July 28th, 2011 ~ 14:25:00 EST, I need time at midnight).

If you have GNU date,
epoch=$( date -d 00:00 +%s )
Otherwise, if you have tclsh,
epoch=$( echo 'puts [clock scan 00:00]' | tclsh )
Otherwise,
epoch=$( perl -MTime::Local -le 'print timelocal(0,0,0,(localtime)[3..8])' )

ksh's printf '%(fmt)T' supports time calculating. For example:
$ printf '%T\n' now
Mon Mar 18 15:11:46 CST 2013
$ printf '%T\n' '2 days ago'
Sat Mar 16 15:11:55 CST 2013
$ printf '%T\n' 'midnight today'
Mon Mar 18 00:00:00 CST 2013
$

Related

Bash script to iterate through a specific time range, one second at a time

I am trying to create some sort of loop in bash that will iterate through a specific time range, one second at a time.
At each interval, it will perform a duty with that timestamp I.e. "Wed Mar 2 12:00:03 CDT 2018"
I am having a hard time wrapping my head around how to make a loop that will iterate every second of time, and when it hits 60 seconds, update the minute, etc.
Thoughts? This seems obvious but the right syntax escapes me.
this is one way of doing it, delegate time computations to date
$ for i in {1..10}; do date -d "+$i seconds"; done
Sun Mar 11 20:40:57 UTC 2018
Sun Mar 11 20:40:58 UTC 2018
Sun Mar 11 20:40:59 UTC 2018
Sun Mar 11 20:41:00 UTC 2018
Sun Mar 11 20:41:01 UTC 2018
Sun Mar 11 20:41:02 UTC 2018
Sun Mar 11 20:41:03 UTC 2018
Sun Mar 11 20:41:04 UTC 2018
Sun Mar 11 20:41:05 UTC 2018
Sun Mar 11 20:41:06 UTC 2018
Sun Mar 11 20:41:07 UTC 2018
if you want to iterate up to a certain time, change the for loop to a while loop and a counter.
To make a loop with time you need to format date/time in such a way that can be comparable. The most easy trick is to transform date to something that will look like an integer and you then use lt,le,eq,gt,ge operators of bash.
Consider this :
$ date
Mon Mar 12 00:16:29 EET 2018 #this format/data type is not comparable by bash
$ date +%Y%m%d%H%M%S
20180312001629 #this is an integer representing the current time
This is a sample loop from now up to a specific time point:
stop=$(date +%Y%m%d%H%M%S --date "2018-03-12 00:20:55")
while [[ $(date +%Y%m%d%H%M%S) -le $stop ]];do #comparing current date & time with stop date & time
echo "date now is $(date)";
sleep 1; #sleep 1 second
done
date now is Mon Mar 12 00:20:51 EET 2018
date now is Mon Mar 12 00:20:52 EET 2018
date now is Mon Mar 12 00:20:53 EET 2018
date now is Mon Mar 12 00:20:54 EET 2018
date now is Mon Mar 12 00:20:55 EET 2018
The trick here is that the command
stop=$(date +%Y%m%d%H%M%S --date "2018-03-12 00:20:55")
converts given date (using the --date flag) to a kind of integer format.
Then the while loop keeps comparing current date in the same integer format with the stop date.
This is a similar script to start/stop at a specific time, but it is a bit "resources hungry" since it keeps comparing current time to start time:
date; #just print the current date & time
compl=false;
start=$(date +%Y%m%d%H%M%S --date "2018-03-12 01:45:50");
stop=$(date +%Y%m%d%H%M%S --date "2018-03-12 01:45:55");
while true;do
while [[ $(date +%Y%m%d%H%M%S) -ge $start ]] && [[ $(date +%Y%m%d%H%M%S) -le $stop ]];do
echo "date now is $(date)";
sleep 1;
compl=true;
done;
($compl) && break;
done
Mon Mar 12 01:45:37 EET 2018
date now is Mon Mar 12 01:45:50 EET 2018
date now is Mon Mar 12 01:45:51 EET 2018
date now is Mon Mar 12 01:45:52 EET 2018
date now is Mon Mar 12 01:45:53 EET 2018
date now is Mon Mar 12 01:45:54 EET 2018
date now is Mon Mar 12 01:45:55 EET 2018
An alternative to start/stop a script at specific time would be to use epoch date / epoch seconds.
Epoch date is measured in seconds since the epoch (1970-01-01 UTC).
Every date can be expressed as epoch seconds, using the format date +%s.
date #just print the current date & time
start="2018-03-12 02:17:52"
stop="2018-03-12 02:17:57"
timerequired=$(( $(date +%s --date "$start") - $(date +%s) ))
sleep $(($timerequired)) #sleep till the starting time
while [[ $(date +%s) -le $(date +%s --date "$stop") ]];do
echo "date now is $(date)";
sleep 1;
done
Mon Mar 12 02:17:39 EET 2018
date now is Mon Mar 12 02:17:52 EET 2018
date now is Mon Mar 12 02:17:53 EET 2018
date now is Mon Mar 12 02:17:54 EET 2018
date now is Mon Mar 12 02:17:55 EET 2018
date now is Mon Mar 12 02:17:56 EET 2018
date now is Mon Mar 12 02:17:57 EET 2018
Finally, you can use external tools to automate things based on date & time like cron, anacron , at, etc
Echo a date for every second in a range:
from=$(date -d "Wed Mar 2 12:59:58 CDT 2018" +%s)
to=$(date -d "Wed Mar 2 13:00:04 CDT 2018" +%s)
for s in $(seq $from $to); do echo $(date -d #$s); done
The date -d takes a well formed date as input. +%s formats it into seconds since epoch. So you get two big values like from=1520013598, to=...3604. The date -d #1520013598 transforms the timestamp back to a human readable date.
Your range might be in a variable like start and stop, and you might like to foobar ($time) instead of echoing it:
start="Wed Mar 2 12:59:58 CDT 2018"
stop="Wed Mar 2 13:00:04 CDT 2018"
from=$(date -d "$start" +%s)
to=$(date -d "$stop" +%s)
for s in $(seq $from $to)
do
timestamp=$(date -d #$s)
foobar $timestamp
done

Loop minutes and echo with bash

I want to iterate all the minutes in a month (the purpose will be to generate a CSV file).
But when I try this:
d="2016-09-01 00:00:00"
while [ "$d" != "2016-09-30 00:00:00" ]; do
echo $d
d=$(date --utc "+%Y-%m-%d %H:%M:00" -d "$d + 1 minute" )
done
Both the hour and minute are being incremented:
2016-09-01 00:00:00
2016-09-01 01:01:00
2016-09-01 02:02:00
2016-09-01 03:03:00
2016-09-01 04:04:00
2016-09-01 05:05:00
2016-09-01 06:06:00
2016-09-01 07:07:00
2016-09-01 08:08:00
What am I doing wrong and how to correctly loop minutes?
I would work with Unix timestamps instead.
d=$(date --utc +%s -d "2016-09-01 00:00:00")
end=$(date --utc +%s -d "2016-09-30 00:00:00")
while [ "$d" != "$end" ]; do
date --utc "+%Y-%m-%d %H:%M:00" -d "#$d"
d=$(( d + 60 ))
done
You can add timezone UTC after your date string variable $d to get the right output:
d="2016-09-01 00:00:00"
for ((i=0; i<=60; i++)); do
date --utc -d "$d UTC + $i minute"
done
Thu Sep 1 00:00:00 UTC 2016
Thu Sep 1 00:01:00 UTC 2016
Thu Sep 1 00:02:00 UTC 2016
Thu Sep 1 00:03:00 UTC 2016
Thu Sep 1 00:04:00 UTC 2016
Thu Sep 1 00:05:00 UTC 2016
...
...
Thu Sep 1 00:55:00 UTC 2016
Thu Sep 1 00:56:00 UTC 2016
Thu Sep 1 00:57:00 UTC 2016
Thu Sep 1 00:58:00 UTC 2016
Thu Sep 1 00:59:00 UTC 2016
Thu Sep 1 01:00:00 UTC 2016
Note use of UTC after $d.
Using + after a time component in the date string is used for ' time zone correction' not for doing what you want to do. Interestingly, inverting date and time works:
$ date "+%Y-%m-%d %H:%M:00" -d "21:31:00 2016-09-03 + 1 minute "
2016-09-03 21:32:00
while the other way around messes with timezones and offsets so the result might depend on your local configuration:
$ TZ=Europe/London date "+%Y-%m-%d %H:%M:00" -d "2016-09-03 21:32:00 + 1 minute "
2016-09-03 21:33:00
$ TZ=Europe/Brussels date "+%Y-%m-%d %H:%M:00" -d "2016-09-03 21:32:00 + 1 minute "
2016-09-03 22:33:00
$ TZ=Asia/Singapore date "+%Y-%m-%d %H:%M:00" -d "2016-09-03 21:32:00 + 1 minute "
2016-09-04 04:33:00

how to add number of days to custom date in bash shell script [duplicate]

In GNU with the command date I can do it:
date -d "+4 day"
datei=20130101
i=5
date -d "$datei +$i day"
But i like know:
how can i do it in Solaris?
with the date command
Tcl has a good free-form date scanner, if you have Tcl installed (try which tclsh). A shell function:
tcldate() {
d=${1:-now} # the date string
f=${2:-%c} # the output format
echo "puts [clock format [clock scan {$d}] -format {$f}]" | tclsh
}
In action on an ancient Solaris 8 box with bash 2.03 and tcl 8.3.3
$ tcldate
Tue Jul 23 13:27:17 2013
$ i=4
$ tcldate "$i days"
Sat Jul 27 13:27:34 2013
$ tcldate "$i days" "%Y-%m-%d"
2013-07-27
$ tcldate "20130101 + $i days" "%Y-%m-%d"
2013-01-05
This even handles daylight savings transitions:
$ tcldate "2014-03-09 00:30 + 1 hour" "%D %T %Z"
03/09/14 01:30:00 EST
$ tcldate "2014-03-09 00:30 + 2 hour" "%D %T %Z"
03/09/14 03:30:00 EDT
$ tcldate "2013-11-03 00:30 + 1 hour" "%D %T %Z"
11/03/13 01:30:00 EDT
$ tcldate "2013-11-03 00:30 + 2 hour" "%D %T %Z"
11/03/13 01:30:00 EST

How to subtract 5 minute from date

I have this data:
`date +%Y-%m-%d`" 00:00:00"
that return 2015-10-08 00:00:00
I would like cancel 5 minute:
2015-10-07 23:55:00
Many thanks
You need to subtract 5 minutes from a known point in time:
$ date -d "00:00:00 today"
Thu Oct 8 00:00:00 EDT 2015
$ date -d "00:00:00 today -5 minutes"
Wed Oct 7 23:55:00 EDT 2015
You just need to add your format string.
There's more than one way to subtract a value from the current time, although this should match the format shown in your question:
date -d "-5 min" "+%Y-%m-%d %H:%M:%S"
Result:
2015-10-08 15:26:13

Bash: get date and time from another time zone

I would want to get the date and time from another time zone (UTC-4) with a bash command, but I don't want to configure it as the default TZ for the system.
Is there a simple way to do it?
E.g 1 (current):
$ date
fri nov 7 13:15:35 UTC 2014
E.g 2 (what I need):
$ date (+ some option for UTC-4)
fri nov 7 09:15:35 UTC 2014
You could use
TZ=America/New_York date
or if you want to do date arithmetic you could use
date -d "+5 hours"
You can use offset value in TZ to get the date for a different timezone:
TZ=UTC date -R
Fri, 07 Nov 2014 13:55:07 +0000
TZ=UTC+4 date -R
Fri, 07 Nov 2014 09:54:52 -0400
I use a little script for that, so I don't have to know or remember the exact name of the timezone I'm looking for. The script takes a search string as argument, and gives the date and time for any timezone matching the search. I named it wdate.
#!/bin/bash
# Show date and time in other time zones
search=$1
format='%a %F %T %z'
zoneinfo=/usr/share/zoneinfo/posix/
if command -v timedatectl >/dev/null; then
tzlist=$(timedatectl list-timezones)
else
tzlist=$(find -L $zoneinfo -type f -printf "%P\n")
fi
grep -i "$search" <<< "$tzlist" \
| while read z
do
d=$(TZ=$z date +"$format")
printf "%-32s %s\n" "$z" "$d"
done
Example output:
$ wdate fax
America/Halifax Fri 2022-03-25 09:59:02 -0300
or
$ wdate canad
Canada/Atlantic Fri 2022-03-25 10:00:04 -0300
Canada/Central Fri 2022-03-25 08:00:04 -0500
Canada/Eastern Fri 2022-03-25 09:00:04 -0400
Canada/Mountain Fri 2022-03-25 07:00:04 -0600
Canada/Newfoundland Fri 2022-03-25 10:30:04 -0230
Canada/Pacific Fri 2022-03-25 06:00:04 -0700
Canada/Saskatchewan Fri 2022-03-25 07:00:04 -0600
Canada/Yukon Fri 2022-03-25 06:00:04 -0700
If the other solutioons don't work, use
date --date='TZ="UTC+4" 2016-08-22 10:37:44' "+%Y-%m-%d %H:%M:%S"
2016-08-22 16:37:44

Resources