Given a date in format 20130522, I need to generate a sequence of date+hour as below:
2013052112,2013052113,2013052114,...,2013052122,2013052123,
2013052200,2013052201,2013052202,...,2013052222,2013052223,
2013052300
in which the first date+hour is 12 hours before the given date and the last date+hour is the midnight in the next day of the given date.
I tried several ways but none of them is ideal. How to generate such a sequence in a clean way using shell script? Thanks!
--Edit--
Per your request, this is what I have so far:
day=20130522
begin=`date --date "$day -12 hours"`
begin=`date -d "${begin:0:8} ${begin:8:2}" +%s`
end=`date --date "$day +1 day"`
end=`date -d "${end:0:8} ${end:8:2}" +%s`
datestr=`date -d #${begin} +%Y%m%d%H`
let begin=$begin+3600
while [ $begin -le $end ]
do
hr=`date -d #${begin} +%Y%m%d%H`
datestr="$datestr,$hr"
let begin=$begin+3600
done
and this is what I got from above:
2013052100,2013052101,2013052102,...,2013052123,
2013052200,2013052201,2013052202,...,2013052223,
2013052300
You can use date and brace expansion:
date=20130522
echo $(date -d "-1 day $date" +%Y%m%d){12..23} \
"$date"{00..23} \
$(date -d "+1 day $date" +%Y%m%d)00
Output (wrapped):
2013052112 2013052113 2013052114 2013052115 2013052116 2013052117 2013052118 2013052119 2013052120
2013052121 2013052122 2013052123 2013052200 2013052201 2013052202 2013052203 2013052204 2013052205
2013052206 2013052207 2013052208 2013052209 2013052210 2013052211 2013052212 2013052213 2013052214
2013052215 2013052216 2013052217 2013052218 2013052219 2013052220 2013052221 2013052222 2013052223
2013052300
Your code was quite well. What I think is that you used so much bash conversion, while date is very powerful and handles in an easier way.
I rewrited something and now I get this:
day=20130522
begin=$(date --date "$day -12 hours" "+%s")
end=$(date --date "$day +1 day" "+%s")
hr=$(date --date "#$begin" "+%s")
while [[ $hr -lt $end ]]
do
hr=$(($hr + 3600))
echo $(date -d "#$hr" "+%Y%m%d %H")
done
$ ./script
20130521 13
20130521 14
.../...
20130522 22
20130522 23
20130523 00
Related
I want to write a bash script that determines the 10 day period (decade) has ended relative to the start date (in the format YYYY-MM-DD).
If the 10 day period is finished script has to output the 10 days period.
Im new in bash and has a lot syntax errors with code, help me pls.
#!/bin/bash
# GNU bash, version 4.3.46
CURRENT_DATE=$(date +%Y-%m-%d)
START_DATE=2019-01-01
IS_TODAY_DECADE_CALCULATION_DAY = (CURRENT_DATE - START_DATE) % 10
if [ $IS_TODAY_DECADE_CALCULATION_DAY -eq 0 ]
then
BEGIN_DATE = $("$CURRENT_DATE - 11 days" +%Y-%m-%d)"
END_DATE = $("$CURRENT_DATE - 1 day" +%Y-%m-%d)"
echo "Period is="$BEGIN_DATE":"$END_DATE"
else
echo "Decade is not finished."
fi
You should compare the unix time stamps. If the time stamp "now+10 days" is larger than the start date, the period is ended.
#! /bin/bash
DATE_OLD=$(date "+%F" -d "-11 days")
DATE_NOW=$(date "+%F")
TEST_DATE_NOW=$(date "+%s" -d ${DATE_NOW})
TEST_DATE_OLD=$(date "+%s" -d ${DATE_OLD})
DIVIDER=$(( (TEST_DATE_NOW - TEST_DATE_OLD) / (60*60*24) ))
REMAINING=$(( DIVIDER % 10 ))
echo "Days between ${DATE_OLD} and ${DATE_NOW} is $DIVIDER"
if [ ${DIVIDER} -gt 0 ]; then
echo "Date ${DATE_OLD} is in the past"
else
echo "Date ${DATE_OLD} is in the future"
fi
if [ $REMAINING -eq 0 ]; then
echo "Ten days period ended"
else
echo "Still in ten day period"
fi
exit 0;
The question implies that the code should identify each 10 day period starting on a specific START_DATE. Bash does not have date math - it can not calculate difference between dates (as expected by '(CURRENT_DATE - START_DATE)'). Two options
Convert date to seconds since Unix Epoch, and do the math on those values, OR
Use date utilities package, OR
using Python, awk, perl
Implementing #1 is simple. Notice few changes to assignments - in particular no spaces are allowed in assignments variable=expression, or let variable=expression
#! /bin/bash
CURRENT_DATE=$(date +%Y-%m-%d)
START_DATE=2019-01-01
# Instead of IS_TODAY_DECADE_CALCULATION_DAY = (CURRENT_DATE - START_DATE) % 10
SEC_IN_DAY=$((60*60*24))
let D1=$(date '+%s' -d "$CURRENT_DATE Z")/SEC_IN_DAY
let D2=$(date '+%s' -d "$START_DATE Z")/SEC_IN_DAY
let IS_TODAY_DECADE_CALCULATION_DAY=(CURRENT_DATE-START_DATE)%10
# Rest of script here
if [ $IS_TODAY_DECADE_CALCULATION_DAY -eq 0 ]
then
BEGIN_DATE=$(date -d "$CURRENT_DATE - 11 days" +%Y-%m-%d)
END_DATE=$(date -d "$CURRENT_DATE - 1 day" +%Y-%m-%d)
echo "Period is=$BEGIN_DATE:$END_DATE"
else
echo "Decade is not finished."
fi
I am trying to manipulate timestamps using date in shell script. My code is this
echo $(date -d '+10 mins' +%s%N)
This will print time 10 mins from current time in nanoseconds
1554242194228787268
When i move the echo statement inside a for loop to do a custom action based on the loop variable.
for repi in `seq 1 2`;
do
lp_incr=$((repi*10))
n_incr='+'$lp_incr' mins'
echo $(date -d $n_incr +%s%N)
done
Getting error like this
date: extra operand '+%s%N'
Remove that extra operand won't help me to view date alone
for repi in `seq 1 2`;
do
lp_incr=$((repi*10))
n_incr='+'$lp_incr' mins'
echo $n_incr
echo $(date -d $n_incr)
done
Again getting different error
+10 mins
date: the argument 'mins' lacks a leading '+';
$n_incr have the '+'still it throws an error.
It seems like i miss something in this. Entire motive is generate timestamp in nano seconds for some interval.
Thanks in advance for all suggestions or alternate approaches.
In
echo $(date -d $n_incr +%s%N)
$n_incr is expanded to
echo $(date -d +10 mins +%s%N)
Note that +10 mins is not a single argument, but two.
The fix is to quote the argument:
echo $(date -d "$n_incr" +%s%N)
You can also omit $n_incr:
echo $(date -d "+$lp_incr mins" +%s%N)
I'm trying to the month number of the last Monday of this week. I got it to check what day of the week it is and if it's not Monday then subtract x days and set that new date as the variable value.
What I'm having trouble with is formatting this variable to only get the month. Everything works except the 2nd to last line below.
startDate=$(date)
weekDayNum=$(date +'%u') # 1 is Monday
# If today is NOT Monday
if [ weekDayNum > 1 ];
then
# Get the date for the last Monday
newWeekDayNum=$(($weekDayNum-1))
startDate=$(date -j -v-${newWeekDayNum}d)
fi
month=$(date -d "$startDate" +'%m')
echo $month```
[ weekDayNum > 1 ] doesn't test for numeric order. Use [ $weekDayNum -gt 10 ] (you also did not access the value of your weekDayNum variable).
It seems you have to supply the format string in the BSD variant of date:
This works for me:
#!/usr/bin/env bash
LANG=C
startDate=$(date)
weekDayNum=$(date +'%u') # 1 is Monday
# If today is NOT Monday
if [ $weekDayNum -gt 1 ];
then
startDate=$(date -j -v "-$(($weekDayNum - 1))d")
fi
month=$(date -j -f "%a %b %d %T %Z %Y" "${startDate}" +'%m')
echo $month
Use expr to convert it to number.
month=$(date -d "$startDate" +'%m')
month=$(expr $month + 0)
echo $month
Output:
8
Using BASH I want to loop from a start to end date at ten-minute intervals.
I tried
begin_date="2015-01-01 00:00:00"
end_date="2015-02-20 00:00:00"
d=$begin_date
while [ "$d" != "$end_date" ]; do
echo $d
d=$(date -d "${d} + 10 min" +"%Y-%m-%d %H:%M")
done
But it didn't work. Looking at Bash:Looping thru dates
#This works
d=$(date -I -d "${d} + 1 day")
#This doesn't work
d=$(date -d "${d} + 1 day" +"%Y-%m-%d")
What am I missing in the format string?
The expression date -d "${d} + 10 min" seems not to produce a date with an offset of 10 minutes. In fact, when I run your code, I see a date counter going backwards. (Posting this diagnostic as part of your question would help others see where the problem is; you should not require others to run your code just to see what it does.)
Anyway, the sane way to do this is to convert the dates to Unix epoch, then take it from there.
for ((d=$(date -d "$begin_date" +%s); d <= $(date -d "$end_date" +%s); d += 600))
do
date -d #$d +"%F %H:%M"
done
Doing date arithmetic in the shell is probably going to be rather inefficient; converting this to e.g. Awk or Perl might be worth your time if you find it's too sluggish, or need to run it lots of times.
The example you linked to just needs to be adjusted slightly:
#!/bin/bash
## User-specified dates.
# See [GNU Coreutils: Date] for more info
# [GNU Coreutils: Date]: https://www.gnu.org/software/coreutils/manual/html_node/Combined-date-and-time-of-day-items.html#Combined-date-and-time-of-day-items
begin_date="2015-01-01T00:00"
end_date="2015-01-01T00:40"
# Run through `date` to ensure iso-8601 consistency
startdate=$(date --iso-8601='minutes' --date="${begin_date}")
enddate=$(date --iso-8601='minutes' --date="${end_date}")
# Do loop
d="$startdate"
while [ "$d" != "$enddate" ]; do
echo $d
d=$(date --iso-8601='minutes' --date="$d + 10 minutes")
done
Note that the options -I and -d are equivalent to --iso-8601 and --date respectively.
I trying to print date between 2 dates using while loop in a bash script.
But when i execute i am getting below error:
test.sh: line 8: [: 02-12-14: integer expression expected
Below is my code, can anyone help me out
#!/bin/bash
sdate=02-12-14
edate=02-25-14
while [ "$sdate" -le "$edate" ]
do
echo $sdate
sdate=$(date +%m-%d-%y -d "$sdate + 1 day")
done
You should store them as timestamps:
#!/bin/bash
sdate=$(date -d '2014-02-12' +%s)
edate=$(date -d '2014-02-25' +%s)
while [[ sdate -le edate ]]; do
date -d "#$sdate" '+%m-%d-%y'
sdate=$(date -d "$(date -d "#${sdate}" ) + 1 day" +%s)
done
Output:
02-12-14
02-13-14
02-14-14
02-15-14
02-16-14
02-17-14
02-18-14
02-19-14
02-20-14
02-21-14
02-22-14
02-23-14
02-24-14
02-25-14
Always prefer [[ ]] over [ ] when it comes to conditional expressions in Bash. (( )) may also be a preference.
It requires GNU date. e.g. date --version = date (GNU coreutils) 8.21 ...
mm-dd-yy is not a format acceptable by date for input so I used yyyy-mm-dd which is acceptable.