Bash -1 year from date - bash

Year=`date '+%Y'`
RTRN1=$?
This returns the current date in the logs, however i want to return the year before, so instead of this returning 2017 i want 2016.
Any help appreciated! Thanks

For GNU date utility: use -d (--date) option to adjust the date:
Year=$(date +%Y -d'1 year ago')
echo $Year
2016

As we have bash, it's possible to use let
let YEAR=`date +%Y`-1
echo $YEAR

You can always capture the year with date +'%Y'. You can subtract 1 with the POSIX arithmetic operator, e.g.
$ echo $(($(date +%Y) - 1))
2016
You can also use the POSIX compliant expr math operators, e.g.
$ expr $(date +%Y) - 1
2016
(note: with expr you must leave a space between the math operator and the values)
The GNU date operator -d with '1 year ago' will work as specified in the comments and other answer, along with let dt=$(date +%Y)-1; echo $dt as specified in the other answer (no spaces allowed with let).
Of all the choices, if I didn't have GNU date, I'd pick the POSIX arithmetic operator $((...)) with a date command substitution minus 1.

Related

Bash: Calculate the time differences in hours from input like "YYYYMMDDHH"

I have two dates in forms like: YYYYMMDDHH and want to calculate the differences (in hours) between these two dates. For example
start_date=1996010100
end_date=1996010122
which stands for two dates: 1996-01-01 00:00:00 and 1996-01-01 22:00:00. I want to use date to calculate the difference in hours, the result shall be 22 hours. I tried with
START=$(date -d "$start_date" +"%s")
END=$(date -d "$end_date" +"%s")
HOURS=$(bc -l <<< "($END - $START) / 3600")
but it failed...
So how can I do this? Thanks!
For performance reasons we want to limit the number of sub-process calls we need to invoke:
use bash substring functionality to convert inputs into usable date/time strings
use bash math to replace bc call
bash substring functionality to break the inputs into a usable date/time format, eg:
# convert to usable date/time format:
$ start_date=1996010100
$ echo "${start_date:0:4}-${start_date:4:2}-${start_date:6:2} ${start_date:8:2}:00:00"
1996-01-01 00:00:00
# convert to epoch/seconds:
$ start=$(date -d "${start_date:0:4}-${start_date:4:2}-${start_date:6:2} ${start_date:8:2}:00:00" +"%s")
$ echo $start
820476000
Applying to ${end_date} and using bash math:
$ end_date=1996010122
$ end=$(date -d "${end_date:0:4}-${end_date:4:2}-${end_date:6:2} ${end_date:8:2}:00:00" +"%s")
$ echo $end
820555200
$ hours=$(( (end - start) / 3600))
$ echo $hours
22
This leaves us with 2 sub-process calls ($(date ...)). While other languages/tools (awk, perl, etc) can likely speed this up a bit, if you need to store the result in a bash variable then you're looking at needing at least 1 sub-process call (ie, hours=$(awk/perl/??? ...)).
If performance is really important (eg, needing to perform this 1000's of times) take a look at this SO answer that uses a fifo, background date process and io redirection ... yeah, a bit more coding and a bit more convoluted but also a bit faster for large volumes of operations.
busybox date can do the trick
start_date=1996010100
end_date=1996010122
START=$(busybox date -D "%Y%m%d%H" -d "$start_date" +"%s")
END=$(busybox date -D "%Y%m%d%H" -d "$end_date" +"%s")
HOURS=$(bc -l <<< "scale=0;($END - $START) / 3600")
echo $HOURS
If it's possible for you to use a more fully-featured scripting language like Python, it'll provide a much more pleasant and understandable date parsing experience, and is probably installed by default (datetime is also a standard Python library)
Structured with shell vars
start_date=1996010100
end_date=1996010122
python -c "import datetime ; td = datetime.datetime.strptime('${end_date}', '%Y%m%d%H') - datetime.datetime.strptime('${start_date}', '%Y%m%d%H') ; print(int(td.total_seconds() / 3600))"
Structured to read dates and format code from stdin
echo '%Y%m%d%H' 1996010100 1996010122 | python -c "import datetime,sys ; fmt, date_start, date_end = sys.stdin.read().strip().split() ; td = datetime.datetime.strptime(date_end, fmt) - datetime.datetime.strptime(date_start, fmt) ; print(int(td.total_seconds() / 3600))"
Should work with both Python 3 and Python 2.7
format codes available here (1989 C standard)
https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes
which stands for two dates: 1996-01-01 00:00:00
So convert it to that form if it stands for it.
start_date=1996010100
start_date=$(sed -E 's/(....)(..)(..)(..)/\1-\2-\3 \4:00:00/' <<<"$start_date")
start=$(date -d "$start_date" +"%s")
and the same with end.
the most simple way is to install "dateutils" using this command
sudo apt-get install dateutils
Run these commands to get the difference in seconds:
dateutils.ddiff -i '%Y%m%d%H%M%S' 20200817040001 20210817040101
output:
31536060s
next step: Simply divide by 86400 to get the number of days or similarly for hours and minutes :)

Bash date query stopped working

A few months ago I wrote a some bash to get dates. I needed these dates as facts in an ansible script to later use them to get data from the database. This worked fine until today here is the code:
- name: Set date variables
set_fact:
first_day_last_month: "{{lookup('pipe','date -d \"-1 month -$(($(date +%d)-1)) days\" +%Y-%m-%d')}}"
last_day_last_month: "{{lookup('pipe','date -d \"$(date +%Y-%m-01) -1 day\" +%Y-%m-%d')}}"
first_day_current_month: "{{lookup('pipe','date -d \"-$(($(date +%d)-1)) days\" +%Y-%m-%d')}}"
last_day_current_month: "{{lookup('pipe','date -d \"-$(date +%d) days +1 month\" +%Y-%m-%d')}}"
However when I run this now I get an error:
/bin/sh: 1: arithmetic expression: expecting EOF: "08-1"
I tried debugging it on the bash command line:
seven#monstermachine:~$ echo $(date -d "-$($(date +%d)-1)")
08-1: command not found
Mit Nov 8 00:00:00 CET 2017
but until now i'm not getting it fixed.
Anyone have any idea?
%d is zero padded which gives base eight or octal number and 08 is not a valid octal number which thows an error.
What you need is something like :
echo $(date -d "$(($(date +%e)-1))")
Wed Nov 8 07:00:00 IST 2017
Note %e will cause date to be space padded which is equivalent to %_d.
To perform a mathematical expression use $(( expression )) format. I didn't understand the actual logic behind your code, so make sure your code fits the logic.
To get first_day_current_month in your script, you could use:
date +%Y-%m-01
similar for the others, for example to get last_day_last_month:
date -d `date +%Y-%m-01`"-1 day" +%Y-%m-%d
Thanks for the help I will make use of both of your answers to come up with a better working command.

Using date to get tomorrows date in Bash

I want to write a bash script that will run on a given but process data with next days date, My current approach is to get the unix time stamp and add a days worth of seconds to it, but I cant get it working, and haven't yet found what I'm looking for online.
Here's what I've tried, I feel like the problem is that its a string an not a number, but I dont know enough about bash to be sure, is this correct? and how do I resolve this?
today="$(date +'%s')"
tomorrow="$($today + 86400)"
echo "$today"
echo "$tomorrow"
If you have gnu-date then to get next day you can just do:
date -d '+1 day'
Some of the answers for this question depend on having GNU date installed. If you don't have GNU date, you can use the built-in date command with the -v option.
The command
$ date -v+1d
returns tomorrow's date.
You can use it with all the standard date formatting options, so
$ date -v+1d +%Y-%m-%d
returns tomorrow's date in the format YYYY-MM-DD.
$(...) is command substitution. You're trying to run $today + 86400 as a command.
$((...)) is arithmetic expansion. This is what you want to use.
tomorrow=$(( today + 86400 ))
Also see http://mywiki.wooledge.org/ArithmeticExpression for more on doing arithmetics in the shell.
I hope that this will solve your problem here.
date --date 'next day'
Set your timezone, then run date.
E.g.
TZ=UTC-24 date
Alternatively, I'd use perl:
perl -e 'print localtime(time+84600)."\n"'
echo $(date --date="next day" +%Y%m%d)
This will output
20170623
I like
input_date=$(date '+%Y-%m-%d')
tomorrow_date=$(date '+%Y-%m-%d' -d "$input_date + 1 day")
echo "$tomorrow_date"
It returns the date of the day after $input_date, in format YYYY-MM-DD
You can try below
#!/bin/bash
today=`date`
tomorrow=`date --date="next day"`
echo "$today"
echo "$tomorrow"

Subtract two variables in unix

This is my script which I am running on UNIX(AIX):
$MON date +"%m"
echo 'expr $MON - 2'
Output:
04
expr $MON - 2
I just want to subtract 2 from my current month and display .
I realize that the default shell on AIX is some variant of ksh which doesn't suffer from the same deficiency as bash in the input base, but it is something to bear in mind if you end up encountering this on another platform.
If this is your input:
$MON date +"%m"
echo 'expr $MON - 2'
then you have several issues.
$MON is unset, which causes the invocation of the line date +"%m", which gives the output 04
the echo command does not execute the expr command as you're using the wrong kind of ticks, which causes the output expr $MON - 2
First, to assign the variable you do VARIABLE=value, in your case this should be:
MON=`date +"%m"`
Don't put a space before or after the = sign.
Secondly, to perform the expr, you need to use the backtick(`)
echo `expr $MON - 2`
However, for most shells, you should use the more modern version of i want to get the result of a command, which is the logic $(command). These can be embedded, which makes them a lot easier to understand (backticks require escaping, and the more backticks the more escaping needed which quickly leads to backslash-palooza).
For bash, you need to ensure that the month is interpreted as a base 10 number, as otherwise once you hit August the code will stop working:
To force the number to be interpreted as a base 10 number, precede it with 10#:
MON=10#$(date +"%m")
echo $(($MON-2))
Examples:
bash-3.2$ month=07
bash-3.2$ echo $(($month + 1))
8
bash-3.2$ month=08
bash-3.2$ echo $(($month + 1))
bash: 08: value too great for base (error token is "08")
bash-3.2$ month=10#08
bash-3.2$ echo $(($month + 1))
9
Try this:
MON=$(date +"%m")
echo $(($MON-2))
You don't need to use expr because bash can perform simple arithmetic as well.
If your shell doesn't support arithmetic expressions, use expr:
expr $MON - 2
In both cases, you will get 2 as the output.
Another option: if you want to see 11 or 12 in January or February, let GNU date do the arithmetic:
date -d "-2 months" +%m

Comparing dates of two files in shell

I have two files created at different times.
In my shell scripting program, I want to initialize a variable with the date of the file which was created earlier.
For eg. if file1 was created on 22 April and file2 was created on April 19. my variable should be initialized to 19th April.
How can I do this in bash shell?
Assuming existence of GNU stat (part of GNU coreutils):
if [[ $(stat -c%W <file1>) -lt $(stat -c%W <file2>) ]]
then
EARLIER="$(stat -c%w <file1>)"
else
EARLIER="$(stat -c%w <file1>)"
fi
Note the case of %W (integer) vs. %w (human-readable) is significant.
%W / %w is birth time, since you asked for "creation time". Usually %Y / %y (last modification) or %Z / %z (last change) are more meaningful.
If you need a different format for your date, you could feed the stat output to date, e.g.:
date -d "$(stat -c%w <earlier_file>)" +"%Y-%m-%d")
PS: While you are at the subject of time stamps, please consider RFC 3339 for your formatting, i.e. YYYY-MM-DD HH:MM:DD-TZ, which is non-ambiguous, portable, and sortable.
/bin/date can convert to timestamps, using the %s format, after which date comparison is a straight numeric compare, so the solution to your problem, modulo syntax errors, is:
DATE1=`date -j '22 April' +"%d %B"`
DATE2=`date -j '19 April' +"%d %B"`
if [[ $DATE2 < $DATE1 ]]; then
export VAR=`date -j $DATE1 +"%s"`
else
export VAR=`date -j $DATE2 +"%s"`
fi

Resources