Why do I always get extra one day with date difference in bash? - bash

I'm trying to calculate the seconds between a date from now, however, I always get extra one day when adding the seconds from now.
echo $(($(date -ud "2020-03-15 19:13" +'%s') - $(date +'%s')))
As of posting, the result is 1744204
Using this website to check, I gets 16 March, not 15 March as expected. Any idea why?

verify the result of your date commands and verify the timezone of both.
The first result of the command shows the timestamp in UTC, and the second one shows the timestamp using the timezone of the system.
Here is the difference:
$ date -ud "2020-03-15 19:13" +'%s'
1584299580
With UTC-3 in my system:
$ date -d "2020-03-15 19:13" +'%s'
1584310380
I hope that help you.

Related

Unix shell scripting: date format syntax

I m trying to get yesterday date, it's not working in hp ux server.
Prev_date=$(date +"y%m%d" -d "1 day ago")
For this I m still getting current date only.
20210811
Could you please help on the same.
You missed a percentage in front of the 'y': this is working fine for me:
echo $(date +"%y%m%d" -d "1 day ago")
You can use below command, if you want.
date --date=' 1 days ago' '+%Y-%m-%d'
It will give result like
2021-09-06
I prefer this format since most of the time my scripts include SQL queries for data fetch and hence date is required to filter out data on daily basis.

How can I get the timestamp in days in awk?

I have a file "file_XYZ_18548".
Here the name's ending 18548 is a timestamp in days, and it is changing day by day, like "file_XYZ_18550".
I would like to get this date via variable but I couldn't find a date command to get the timestamp in days.
I can get the date result but I can't get the timestamp in reverse.
timeinday=18550
timestp=timeinday*86400
datetm=$(echo $timestp | gawk '{print(strftime("%Y-%m-%d %H:%M:%S", $0))}')
echo $datetm
2020-10-14 10:09:10
How can I get this with date command in bash scripting? Is there any way of this via awk/gawk etc..?
Given that 2020-10-14 - 18548 days corresponds to 1970-01-03, it is reasonable to guess that the 'epoch' for the day count is 1970-01-01. It is likely that day 1 was 1970-01-01, so day zero was 1969-12-31.
Converting day count to date
You can use the GNU date command like this:
daycount=18548
date -u -d "#$(( ($daycount-1) * 86400 ))" +"%Y-%m-%d %H:%M:%S"
That yields the result 2020-10-12 00:00:00. You can drop the time component of the format if you wish (you probably do; midnight isn't very exciting when it is always midnight). You can calibrate the -1 to resolve exactly what day should correspond to 18548. Just in case it isn't obvious, there are 86,400 seconds in a day (24 hours • 60 minutes per hour • 60 seconds per minute).
The $(( … )) notation is Bash's Arithmetic Expansion notation.
Converting current time to day count
If you want to convert the current time to the day offset, then you can use the %s specifier to get the seconds since 1970-01-01 00:00:00Z and divide by 86400 to get the number of days:
echo $(( $(date +'%s') / 86400 ))
which (at 2020-10-14 23:30 -06:00, aka 1602739800 seconds since the Unix Epoch) yields the result:
18550
Again, if need be, you can adjust the value of the division to account for when day 1 was in this scheme. Shell arithmetic in Bash is integer arithmetic, which is exactly what is wanted. You might need to use -u to get UTC as the time zone (as I did earlier), and so on.

Why is the date command throwing an error despite successfully computing an answer?

For context I am working on a Windows machine with MINGW64. I have not had the chance to test this on a machine running Linux.
I am working with [date][1] in bash and trying to add days to a date represented as seconds since 1970-01-01 00:00:00, i.e. in format %s. I have the following Bash code:
DATE1=$(date --date=now "+%s")
echo "DATE1: ${DATE1}"
DATE2=$(date --date="$(date --date="${DATE1}" "+%s")+2 days" "+%d%b%Y %H:%M:%S")
echo "DATE2: ${DATE2}"
Which gives console output
DATE1: 156133763
date: invalid date '1561337963'
DATE2: 26Jun2019 10:59:24
In fact, DATE2 has the expected value down to the second. However the console still throws an error. Why might this error be occurring? Would it have something to do with running MINGW64?
An update:
I ran this on a Debian server I have access to. It computed the time with now like on MINGW, but returned a different error: ./test.sh: line 3: --date=1561342165: command not found.
Running this on the same server with a custom date:
DATE1=$(date --date="$(date --date="19Jun2019 11:35:46" "+%d%b%Y %H:%M:%S")" "+%s")
Likewise returns
DATE1: 1560908146
date: invalid date ‘1560908146’
DATE2: 26Jun2019 12:20:08
Which actually indicates it isn't adding to the defined date at all, rather it is just adding to today's date (it's the 24th of June where I am now). Clearly, something is quite wrong!
If you want to convert timestamp to a date then you have to use #:
date --date=#1561344591 '+%F %T'
2019-06-24 04:49:51
The reason why you got seemingly correct result even with the error message is because your DATE1 is now, so your inner date call produces an error and returns nothing and then the outer call is just --date=+2 days, which produces 2 days from now.
I don't think you can use date-time in timestamp format together with relative statements, it doesn't work even with #. You have to convert your timestamp to human readable date first but even then you have to be careful. You could think that this is enough:
date --date="$(date --date=#1561344591 "+%F %T") + 2 days" "+%F %T"
2019-06-25 04:49:51
As you can see it is still wrong and that's because +2 is parsed as a timezone. You fix it by explicitly including timezone in you conversion from timestamp:
date --date="$(date --date=#1561344591 "+%F %T%Z") + 2 days" "+%F %T"
2019-06-26 04:49:51
In general, using bash debugging set -x and date debugging date --debug ... helps with solving such problems.

Strange behaviour of bash date and time arithmetics

When I issue bash command:
date --date="2018-03-03 12:16:13 -1hour" "+%Y:%m:%d %H:%M:%S"
I expect the result would be:
2018:03:03 11:16:13
but instead, I get:
2018:03:03 15:16:13
I wonder if this has to make with time zones, and how to avoid this behaviour.
I can reproduce this. My timezone is America/New_York
$ date --date="2018-03-03 12:16:13 - 1 hour" "+%Y:%m:%d %H:%M:%S"
2018:03:03 09:16:13
$ env TZ='Europe/Belgrade' date --date="2018-03-03 12:16:13 - 1 hour" "+%Y:%m:%d %H:%M:%S"
2018:03:03 15:16:13
The parser appears to be taking the -1 as the timezone GMT+01:00, then converting that to your local timezone.
If we rearrange the phrases to avoid the timezone parsing ambiguity, we can get your desired result:
$ date --date="- 1 hour 2018-03-03 12:16:13" "+%Y:%m:%d %H:%M:%S"
2018:03:03 11:16:13
From info coreutils 'date invocation'
When a relative item causes the resulting date to cross a boundary where the clocks were adjusted, typically for daylight saving time,
the resulting date and time are adjusted accordingly.
The fuzz in units can cause problems with relative items. For
example, '2003-07-31 -1 month' might evaluate to 2003-07-01, because
2003-06-31 is an invalid date. To determine the previous month more
reliably, you can ask for the month before the 15th of the current
month. For example:
$ date -R
Thu, 31 Jul 2003 13:02:39 -0700
$ date --date='-1 month' +'Last month was %B?'
Last month was July?
$ date --date="$(date +%Y-%m-15) -1 month" +'Last month was %B!'
Last month was June!
Also, take care when manipulating dates around clock changes such
as daylight saving leaps. In a few cases these have added or
subtracted as much as 24 hours from the clock, so it is often wise to
adopt universal time by setting the 'TZ' environment variable to
'UTC0' before embarking on calendrical calculations.
One can avoid that by putting -1 hour before the string,
$ date --date='-1 hour 2018-03-03 12:16:13' "+%Y:%m:%d %H:%M:%S"
2018:03:03 11:16:13

How to subtract a day from an invalid date in shell script?

I'm working on a script to automate the download of information from a customer in the period from 00:00 to 23:59 on the same day. To make the correct treatment of the first day of daylight saving time (10/15/2017, in my timezone - BRST), I need to check the timezone of the previous day. However, when I will subtract one day from the first valid time,
date --date="20171015 01:00 -1 day" +%Y-%m-%d
the result is the next day 2017-10-16, not the previous day 2017-10-14. Could anyone help me understand what I might be doing wrong and how should I do this operation in the right way?
I don't really trust GNU date's arithmetic. Instead, I would convert your starting time to seconds since the UNIX epoch, subtract 86400 seconds, and convert the result back to a day. Those conversion routines take daylight saving time into account.
$ TZ=BRST date +%s --date "20171015 01:00"
1508029200
$ TZ=BRST date +%F-%T --date #$((1508029200 - 86400))
2017-10-14-01:00:00
It appears the "BRST" timezone is not very useful: stick to Olson timezone names
$ TZ=BRST date --date="20171015 00:30" "+%F %T"
2017-10-15 00:30:00
$ TZ=America/Sao_Paulo date --date="20171015 00:30" "+%F %T"
date: invalid date ‘20171015 00:30’

Resources