0

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?

Community
  • 1
  • 1
Miles
  • 145
  • 2
  • 6

2 Answers2

2

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.

tripleee
  • 175,061
  • 34
  • 275
  • 318
  • Thanks, code works perfectly. Been battling with that for about 8 hours! I had to google epoch time to understand your answer :-) – Miles Dec 19 '16 at 11:44
  • Thanks for the feedback; added a Wikipedia link. – tripleee Dec 19 '16 at 11:51
  • I also experienced this rare _feature_ of time going backwards when saying `+10 min`. – fedorqui Dec 19 '16 at 12:54
  • 1
    I think the reason that `+10 min` appears to have time go backwards is that the `+10` part is parsed as a timezone specification if `T00:00` or similar is present in the timestamp. `date -d '2015-01-01T00:00 + 10 + 20 minutes'` gives me `Wed Dec 31 15:20:00 CET 2014`, so an apparent 9 hours back in time because CET is +1 and I asked for +10, and then 20 minutes forward as specified. – Wintermute Dec 17 '17 at 01:09
1

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.

Sigve Karolius
  • 1,356
  • 10
  • 26
  • Thanks, Sigve, your answer also works. Not certain if I can tick multiple answers as correct. – Miles Dec 19 '16 at 23:22
  • On further testing, I'm changing to accept Sigve's answer. I ran both methods for a month. Sigve's was slightly faster (although not by much) @tripleee's real 1m1.310s user 0m1.156s sys 0m55.953s vs Sigve's real 0m57.308suser 0m0.953s sys 0m52.250s However, the reason I changed the answer was that I'm needing four variables derived from the date (old/new path (YYYYMMDD) and old/new name foo_HHMM) and the code above was easy to reformat the date whereas the other code was not. – Miles Dec 22 '16 at 01:39
  • 1
    Minor correction to start and end dates. Don't use Z (i.e. UTC). `code` begin_date="2015-01-01T00:00" end_date="2015-01-01T00:40" `code` – Miles Dec 22 '16 at 01:48