Looping through unix dates Code Answer

Hello Developer, Hope you guys are doing great. Today at Tutorial Guruji Official website, we are sharing the answer of Looping through unix dates without wasting too much if your time.

The question is published on by Tutorial Guruji team.

I have rather basic task but wasn’t able to find proper solution to it. I want to iterate date interval since 2008 to current and need epoch values for each iteration of the loop. I am interested in iterating both years, halves and months as well.
I wrote such script

#!/bin/bash
initial_date=`date -d "2008-02-04 00:00:00 UTC" +%s`
end_date=`date +%s`
n=0
until [ $initial_date -gt $end_date ]; do
 echo $initial_date
 let n+=1
 readable_date=`date +"%Y-%m-%d %T" -d "1970-01-01 $initial_date sec"`
 echo $readable_date
 readable_date=`date -d "$readable_date + $n year"`
 initial_date=`date -d "$readable_date" +%s`
done

but its output is rather weird to me:

1202083200
2008-02-04 00:00:00
1233702000
2009-02-03 23:00:00
1265230800
2010-02-03 21:00:00
1296756000
2011-02-03 18:00:00
1328277600
2012-02-03 15:00:00
1359885600
2013-02-03 11:00:00
1391403600
2014-02-03 06:00:00
1422918000
2015-02-02 23:00:00
1454425200
2016-02-02 15:00:00

Why the year is not incremented properly? Shifted hours seems to me a side-effect of unix>>UTC>>unix conversion. Is there any direct (without reconversion) method for doing this?

P.S.
And yes, I checked this, this and this question and found no clear way of doing this. All they are based on incrementing number and converting date with the help of it which doesn’t seem precise to me.

And yes, I thought about adding 60*60*24*30*365 to initial date but would it be correct? This approach doesn’t consider leap years, months comprised of 31 days and so on.

Answer

Date used:

$ dateA="2008-02-04 00:00:00 UTC"

The first reason to get dates with shifted times is to request “local” dates:

$ date -d "$dateA"
Sun Feb  3 19:00:00 EST 2008

Which will be corrected if you specify a UTC time:

$ TZ=UTC0 date -d "$dateA"
Mon Feb  4 00:00:00 UTC 2008

Or better (make an habit of using it) use the -u option of date:

$ date -ud "$dateA"
Mon Feb  4 00:00:00 UTC 2008

A second reason is to request “relative items” with a sign:

$ date -ud "$(date +"%Y-%m-%d %T" -ud "$dateA") +1 year"  ### wrong
Tue Feb  3 23:00:00 UTC 2009

$ date -ud "$(date +"%Y-%m-%d %T" -ud "$dateA") 1 year"  ### better
Mon Feb  4 00:00:00 UTC 2008

But all the time problems (usually) go away when a “time zone” (-z) is used:

$ date -ud "$(date +"%Y-%m-%d %T %z" -ud "$dateA") +1 year"  ### Best
Wed Feb  4 00:00:00 UTC 2009

$ date -ud "$(date +"%Y-%m-%d %T %z" -ud "$dateA") 1 year"  ### Preferred
Wed Feb  4 00:00:00 UTC 2009

The issue is related to the way a date string is parsed, if the TZ value is missing, the +1 may be interpreted as a Time Zone value:

$ date -ud "2008-02-04 00:00:00 +3 year"
Tue Feb  3 21:00:00 UTC 2009

Even if an environment value for TZ has been set:

$ TZ=UTC0 date -ud "2008-02-04 00:00:00 +3 year"
Tue Feb  3 21:00:00 UTC 2009

Yes, the year was incresed once (2009 instead of 2008) but the +3 was used for a change of the time presented (not what was intended).

I repeat: the problem is that the +3 may be parsed as a Time Zone value.


Also, to convert (epoch) seconds to dates, GNU date may use “@”

$ dateAsec="$( date -ud "$dateA" +"%s" )

$ date -ud @"$dateAsec"
Mon Feb  4 00:00:00 UTC 2008

The script (using a (newdate) function) could be written like this:

#!/bin/bash
dateI="$(date -ud "2008-02-04 00:00:00 UTC" +%s)"
dateF="$(date -u +%s)"

newdate(){ date -ud "$(date +"%Y-%m-%d %T %z" -ud @"$dateI") $1 year" +"%s"; }

n=0
while 
    dateN="$( newdate "$n" )"
    (( dateN < dateF ));
do
    dateNhuman="$(date +"%Y-%m-%d %T %z" -ud @"$dateN")"
    echo "dateN=$dateN --- $dateNhuman ---> $dateF $(( $dateF - $dateN )) $n"
    (( n++ ))
done

Results:

dateN=1202083200 --- 2008-02-04 00:00:00 +0000 ---> 1470543626 268460426 0
dateN=1233705600 --- 2009-02-04 00:00:00 +0000 ---> 1470543626 236838026 1
dateN=1265241600 --- 2010-02-04 00:00:00 +0000 ---> 1470543626 205302026 2
dateN=1296777600 --- 2011-02-04 00:00:00 +0000 ---> 1470543626 173766026 3
dateN=1328313600 --- 2012-02-04 00:00:00 +0000 ---> 1470543626 142230026 4
dateN=1359936000 --- 2013-02-04 00:00:00 +0000 ---> 1470543626 110607626 5
dateN=1391472000 --- 2014-02-04 00:00:00 +0000 ---> 1470543626 79071626 6
dateN=1423008000 --- 2015-02-04 00:00:00 +0000 ---> 1470543626 47535626 7
dateN=1454544000 --- 2016-02-04 00:00:00 +0000 ---> 1470543626 15999626 8

All years appear and all seems correct.

We are here to answer your question about Looping through unix dates - If you find the proper solution, please don't forgot to share this with your team members.

Related Posts

Tutorial Guruji