Strange date behaviour in bash - linux

I am trying to add hours to a given datetime in bash and its giving weird results
This is just to check if its parsing the date time correctly
$ date -d "2020-01-21 12:00:00"
Tue 21 Jan 12:00:00 UTC 2020
Now when I try to do date math
$ date -d "2020-01-21 12:00:00 +2 hour"
Tue 21 Jan 11:00:00 UTC 2020
I tried few other operations but similar behaviour.
If I change my format then it behaves correctly for eg.
date -d "12:00:00 2020-01-21 +2 hour"
Tue 21 Jan 14:00:00 UTC 2020
not sure whats going on here.

The +2 is being interpreted as an explicit timezone specifier (equivalent to EET), so date -d "2020-01-21 12:00:00 +2 hour" is interpreted the same as date -d "2020-01-21 12:00:00 EET hour", which adds one hour to the timezone-adjusted time specified.
You can either provide an explicit timezone (as suggested by Maaz) so that +2 hour is syntactically an additional offset, or you can move it to the beginning of the expression, where it can't be parsed as a timezone.
date -d "+ 2 hour 2020-01-21 12:00:00"

Basically you need to pass the timezone in command as well like UTC/CT/IST, so that date command can understand the point of reference to add extra hours.
For example if you are in UTC timezone, then following will produce correct output for you.
date -d "2020-01-21 12:00:00 UTC + 2 hour"

Related

Can't use variable in date

I'm trying to convert a string into seconds using date +%s, but everytime i get this error:
deadline='Monday August 2 10:45:25 AM GMT'
date -d $deadline +%s
date: extra operand'2'
But if I don't use a variable this command works fine
date -d 'Monday August 2 10:45:25 AM GMT' +%s
1627901012
Can somebody explain why this command doesn't work with my variable?
why this command doesn't work with my variable?
Unquoted variable expansions undergo word splitting.
After expansion, you are executing:
date -d Monday August 2 10:45:25 AM GMT +%s
Monday is the argument for -d, August is the one argument that date takes. Then the rest August 2 10:... are just invalid positional arguments for date, so the tool exits with an error that too many arguments were passed.

How I can get the next month in shell?

I would like to get the current and next months using shell script, I have tried this command:
$ date '+%b'
mar
$ date +"%B %Y" --date="$(date +%Y-%m-15) next month"
March 2018
But it always displays only the current month.
Could you please help me if there is something wrong with the commands.
$ date -d "next month" '+%B %Y'
April 2018
Check this post about specific caveats
Note: your command works just fine for me (archlinux, bash4, date GNU coreutils 8.29)
I wouldn't rely on date alone to do this. Instead, perform a little basic math on the month number.
this_month=$(date +%-m) # GNU extension to avoid leading 0
next_month=$(( this_month % 12 + 1 ))
next_month_name=$(date +%B --date "2018-$next_month-1")
Since you are using bash, you don't need to use date at all to get the current month; the built-in printf can call the underlying date/time routines itself, saving a fork.
$ printf -v this_month '%(%-m)T\n'
$ echo $this_month
3
What variant and version of date are you running? "Solaris 5.2" was never released, though SunOS 5.2 was a kernel in Solaris 2.2 (EOL in 1999). See the Solaris OS version history. The Solaris 10 (SunOS 5.10) man page for date does not support GNU's --date= syntax used in the question, so I'm guessing you're using some version of date from GNU coreutils.
Here's a solution using BSD date (note, this is academic in the face of BSD's date -v 1m):
date -jf %s $((1728000+$(date -jf %Y-%m-%d $(date +%Y-%m-15) +%s))) +"%B %Y"
There are three date calls here. BSD's date allows specifying a format (GNU can intuit most formats on its own). The parent call is the one that takes the final time (as seconds since the 1970 epoch), expressing it in the desired "Month Year" format. Seconds are determine by adding 20 days to the epoch time of the current month on the 15th day. Since no month has 15+20 days, this is always the following month.
Here's a direct translation of that logic to GNU date:
date +"%B %Y" --date="#$((1728000+$(date +%s --date=$(date +%Y-%m-15))))"
Here's a simpler solution using GNU date, with one fewer date call:
date +"%B %Y" --date="$(date +%Y-%m-15) 20 days"
(A bug in GNU date will give you the wrong month if you run date --date="next month" on the 31st.)
The below one works in Red Hat 4.4.7-23, Linux version 2.6.32-754.2.1.el6.x86_64.
Just use the "month" for future months and "month ago" for previous months.. Dont confuse with adding +/- signs to the number. Check out.
> date "+%B-%Y" #current month
November-2018
> date -d" 1 month" "+%B-%Y"
December-2018
> date -d" 1 month ago" "+%B-%Y"
October-2018
>
More..
> date -d" 7 month ago" "+%B-%Y"
April-2018
> date -d" 7 month " "+%B-%Y"
June-2019
>

BASH/Linux - Finding the next date from a variable

In my Unix shell programming, I am trying to get the next date (tomorrow's date) over a reference date defined as "a". Here is the code:
a=2016-01-02
Which operator would I use in my code so that Unix will automatically define a as tomorrow's date as in below
a=2016-01-03
date has a -d option that is very useful in this situation.
To get the next day, add a space after the date then add 1 day
date +%Y-%m-%d -d "$a 1 day"
It's important to add the format specifier because without it, you would get the following output
=>"Sun Jan 3 00:00:00 UTC 2016"
To update the a variable, you could do something like this
a=$(date +%Y-%m-%d -d "$a 1 day")
Remember to wrap the command inside of parentheses with a $ sign in front of it.

Tz date format to human readable format

I have a log file containing date and time in the format below
2016-11-03T00:00:18.976926847Z
I would like to change this to more human readable formate, like 2016-11-03 00:00:18
If you have GNU date just do
$ date -d "2016-11-03T00:00:18.976926847Z"
Thu Nov 3 05:30:18 IST 2016
where the -d flag as per the man page
-d, --date=STRING
display time described by STRING, not 'now'
and to format it as you need add the custom format '%Y-%m-%d %H:%M:%S'
$ date -d "2016-11-03T00:00:18.976926847Z" +'%Y-%m-%d %H:%M:%S'
2016-11-03 05:30:18
$ echo 2016-11-03T00:00:18.976926847Z|sed 's/T/ /;s/\..*$//'
2016-11-03 00:00:18

Converting time to unix timestamp

I have the following time format
"2014-06-02T16:23:13+02:00"
I want to convert it to the unix timestamp (since 1/1/1970). For the above example, The command should return:
1401725705
Are there a linux command for that?
date -d"2014-06-02T16:23:13+02:00" +%s
should work if you have a newer GNU coreutil. I tested with v8.22 latest.
if you are on a elder coreutil box like 8.4. it won't work, you could try replace the T with space. use string "2014-06-02 16:23:13+02:00" in date -d"2014-06-02 16:23:13+02:00" +%s
this is tested on Red Hat Enterprise Linux Server release 6.5 (Santiago) with coreutil 8.4
$>date -d"2014-06-02 16:23:13+02:00" +%s
1401718993
date -d"2014-06-02T16:23:13+02:00" +%s
As pacholik indicates, %s is the way to convert date to seconds since 1970-01-01 00:00:00 UTC.
You can try either of these (note the usage of -d or --date=, as well as %s with + in or outside the quotes:
$ date --date="2014-06-02T16:23:13+02:00" "+%s"
1401718993
$ date --date="2014-06-02T16:23:13+02:00" +"%s"
1401718993
$ date -d"2014-06-02T16:23:13+02:00" +"%s"
1401718993
As a side note, you can do the opposite with -d#TIME:
$ date -d#1401718993
Mon Jun 2 14:23:13 UTC 2014
I see you were having problems with the T - time designator:
$ date -d"$(sed 's/\(.*\)T\(.*\).*/\1 \2/' <<< "2014-06-02T16:23:13+02:00")" +"%s"
1401718993
This sed gets the string and removes the T in the middle.
$ sed 's/\(.*\)T\(.*\).*/\1 \2/' <<< "2014-06-02T16:23:13+02:00"
2014-06-02 16:23:13+02:00

Resources