Validating date in Unix - date

I have a scenario as below:
I will be getting two dates viz. start_dt and end_dt in yyyyMMdd format as arguments to my Unix Script.
I have to loop through each of the dates starting from start_dt till end_dt incrementing by a day each time.
The script I have written is as below:
start_date=$1
end_date=$2
#verify dates
if ! date -d "$start_date" 2>&1 > /dev/null ;
then echo "start date is invalid" ; exit 1
fi
if ! date -d "$end_date" 2>&1 > /dev/null ;
then echo "end date is invalid" ; exit 1
fi
#set current and end date
curr_dt=$(date -d "$start_date")
end_dt=$(date -d "$end_date +1 hours")
#loop over all dates
while [ "$end_dt" != "$curr_dt" ]
do
echo $curr_dt
# increment the date
curr_dt=$(date -d "$curr_dt +1 hours")
done
However, I am getting below error when I am running with input arguments as 20140128 and 20140130:
date: invalid date `20140130 +1 hours'
Tue Jan 28 00:00:00 EST 2014
date: invalid date `Tue Jan 28 00:00:00 EST 2014 +1 hours'

Related

Linux date command adds 10 hours to every datetime automatically

If I enter date +"%Y/%m/%d %H:%M" -d "20200819T1234" the expected output is 2020/08/19 12:34 when in I actually get 2020/08/19 02:34 that is, exactly 10 hours less. Could someone explain to me why this happens?
At the moment I manage with + 10 hours at the end of the command, but I don't think this is normal. The time zone set on the server is -03 so I am very confused.
This happens in both Ubuntu 16 and Debian 10
The GNU code for parsing dates (parse_datetime2) has this table embedded within it that provides the reason why you're getting the incorrect time (trimmed for conciseness):
/* Military time zone table.
Note 'T' is a special case, as it is used as the separator in ISO
8601 date and time of day representation. */
static table const military_table[] =
{
{ "A", tZONE, -HOUR ( 1) },
{ "B", tZONE, -HOUR ( 2) },
{ "C", tZONE, -HOUR ( 3) },
: : :
{ "Y", tZONE, HOUR (12) },
{ "Z", tZONE, HOUR ( 0) },
{ NULL, 0, 0 }
};
And, indeed, if you run date in debug mode, you can see what's happening (output trimmed for conciseness):
pax> for i in {A..I} {K..Z} ; do
...> date -d $i --debug 2>&1 | awk -vZ=$i '/parsed zone/{print " "Z":"$5}'
...> done
A:UTC-01
B:UTC-02
: :
T:UTC+07
: :
Z:UTC+00
Most letters apply a timezone offset based on military timezones, hence the T that would normally be used to separate date and time in ISO format is being handled differently here, as specifying UTC+7, explaining the ten-hour difference between that and your server at UTC-3.
The bottom line is that you need to use an input format that's acceptable to date. That's as simple as (in this case) replacing the T with a space, as per the following transcript:
pax:~> ### First, the problematic one.
pax:~> date +"%Y/%m/%d %H:%M" -d "20200819T1234" --debug
date: parsed number part: (Y-M-D) 2020-08-19
date: parsed zone part: UTC+07
date: parsed number part: 12:34:00
date: input timezone: parsed date/time string (+07)
date: using specified time as starting value: '12:34:00'
date: starting date/time: '(Y-M-D) 2020-08-19 12:34:00 TZ=+07'
date: '(Y-M-D) 2020-08-19 12:34:00 TZ=+07' = 1597815240 epoch-seconds
date: timezone: system default
date: final: 1597815240.000000000 (epoch-seconds)
date: final: (Y-M-D) 2020-08-19 05:34:00 (UTC)
date: final: (Y-M-D) 2020-08-19 13:34:00 (UTC+08)
2020/08/19 13:34
pax:~> ### Then, the correct one.
pax:~> date +"%Y/%m/%d %H:%M" -d "20200819 1234" --debug
date: parsed number part: (Y-M-D) 2020-08-19
date: parsed number part: 12:34:00
date: input timezone: system default
date: using specified time as starting value: '12:34:00'
date: starting date/time: '(Y-M-D) 2020-08-19 12:34:00'
date: '(Y-M-D) 2020-08-19 12:34:00' = 1597811640 epoch-seconds
date: timezone: system default
date: final: 1597811640.000000000 (epoch-seconds)
date: final: (Y-M-D) 2020-08-19 04:34:00 (UTC)
date: final: (Y-M-D) 2020-08-19 12:34:00 (UTC+08)
2020/08/19 12:34
Your format is mismatch with the time string: try
date +"%Y/%m/%d %H:%M" -d "2020/08/19 12:34"
2020/08/19 12:34

awk appears to be miscalculating dates

I have a log file where each line begins with a date; here is an example line:
26/06/2020 00:00:01 Executing daily job...
I am using the following awk command:
awk -v d="$(date -d "1 month ago" "+%d/%m/%Y")" '$1 $2 > d' log > temp-log
The result is supposed to be log entries in the last month but I only get the last day.
So, putting it all together, we get this solution:
cat logfile | awk -v startdate="$(date -d "1 month ago" "+%Y/%m/%d")" '
{sep="/"; split($1,array,sep); $1=array[3] sep array[2] sep array[1];
if ($1 > startdate) print}'

unix date command with nanosecond precision. Input parameter

I'm having difficulty parsing an inputted date with nanosecond precision:
date: invalid date `15-OCT-18 12:40:01:000203570 AM'
Yet when I drop the nanoseconds, it works fine:
$ date -d "15-OCT-18 12:40:01 AM" +"%d-%m-%Y %H:%M:%S %p"
15-10-2018 00:40:01 AM
Looking the docs its suggests uppercase N is to be used for ns
Even when I drop the Ns it generates the ns for me
$ date -d "15-OCT-18 12:40:01 AM" +"%d-%m-%Y %H:%M:%S:%N %p"
15-10-2018 00:40:01:000000000 AM
Should be in the format
date -d "15-OCT-18 12:40:01.000203570 AM" +"%d-%m-%Y %H:%M:%S:%N %p"
Data needs to have . instead of : spearating seconds and ns
You need to replace the : before the Nanoseconds identifier with .(dot)
> date -d"$(echo "15-OCT-18 12:40:01:000203570 AM" | sed 's/:/./3')" +"%d-%m-%Y %H:%M:%S.%N %p"
15-10-2018 00:40:01.000203570 AM
>

Finding start and end date from given year and month in Unix

I have a unix script named myScript where two arguments should be passed in YYYYMM format indicating starting month and ending month for the script.
Inside the script, based on the argument, I need to calculate the start date of the month in first argument and the end date of the month in second argument.
I wrote the below code:
startYr=`expr substr $2 1 4`
startMonth=`expr substr $2 5 2`
startDate=`cal $startMonth $startYr | grep . | fmt -1 | tail -1`
endYr=`expr substr $3 1 4`
endMonth=`expr substr $3 5 2`
endDate=`cal $endMonth $endYr | grep . | fmt -1 | tail -1`
export eomStartDate=$startYr-$startMonth-$startDate
export eomEndDate=$endYr-$endMonth-$endDate
echo "START DATE: $eomStartDate"
echo "END DATE: $eomEndDate"
However, on running above script as:
myScript 201401 201412
The result I am getting is:
START DATE: 2014-12-31
END DATE: --31
What am I missing ? I am using Korn Shell.
Thanks for reading!
The parameters should be $1 and $2, not $2 and $3. Also, for start date you should do sed -n 10p to get the 10th line, from where the days start.

Firefox Bookmarks add_date

One question to firefox exported bookmarks.
How to read this date: ADD_DATE="1375088003"? I think it is date when user add new website to bookmarks but how to read this all string? Where is year, day and month?
It's the Epoch time, ie the number of seconds since Jan 1 1970. To convert it to a human-friendly date, you can pass it through the 'date' unix command:
date -r 1375088003
will return
Mon 29 Jul 2013 18:53:23 AEST
(on my trusty Mac here in eastern Australia, hence the AEST)
Here's what I do. I export bookmarks from my browser. Assume the result file is called "bookmarks.html". I have a one-line executable script that takes a file as input, and creates another file with many long fields stripped. The one-liner I call "icon.sed" contains this:
sed 's/ICON=\"[^\"]*\"//' | sed 's/ICON_URI=\"[^\"]*\"//' | \
sed 's/LAST_CHARSET=\"[^\"]*\"//' | sed 's/HREF=\"[^\"]*\"//'| \
tr -s ' '
I use it like this:
~/icon.sed <bookmarks.html >newbook.txt
I have another script that takes a mm/dd/ccyy parameter, and returns the Epoch time for that date. That executable script is called "epoch.sh":
#!/bin/sh
if [ -z "$1" ]; then echo "You must supply a date"
else date -j -f "%m/%d/%Y" "$1" "+%s"; fi
exit 0
Choose a date you're looking for, and send it through "epoch.sh", such as: ~/epoch.sh 10/30/2015 which outputs this: 1446246082 .
You can then grep your newbook.txt file looking for either ADD_DATE or LAST_MODIFIED date which begins with the first four digits: 1446
grep 'LAST_MODIFIED="1446' newbook.txt
Also, use epoch.sh to get a pair of epoch times for start and stop dates so you can bracket your results by doing multiple greps over the range, using just the first four digits of each epoch time.
To convert a Firefox timestamp to a date with BASIC:
If the timestamp is from an sqlite dump of places.sqlite, you need to truncate it first:
stg0 = Left("1670163289502000", 10) results in "1670163289"
Convert the timestamp:
Dim var0 As double, var1 As Date
var0 = stg0
or
var0 = "1670163289" 'BASIC will do the conversion for you
var1 = (var0 / 86400) + 25569
where 86400 is the # of seconds in a day and 25569 is the BASIC daynumber for 1/1/1970