I'm interested in outputting a representation of the current year-quarter, as well as the year-quarter for the previous month.
If today is 2012 January 1st, I'd like to get
2012q1
and
2011q4
as the respective outputs.
One (kinda ugly) solution, using BASH arithmetic evaluation and the GNU date
command:
echo $(date +%Y)q$(( ($(date +%-m)-1)/3+1 ))
echo $(date -d "-1 month" +%Y)q$(( ($(date -d "-1 month" +%-m)-1)/3+1 ))
Note that the %-m
prevents date
from 0-padding,
so this will still work for August and September.
%m
gives 09
which bash tries to interpret as octal due to the leading 0, so this throws an error that says 09: value too great for base (error token is "09")
. This can be fixed by disabling 0-padding by changing %m
to %-m
.
All solutions that divide by four fail, for instance November:
% echo $(( 11/4+1 ))
3
The correct math would be:
$(( (m-1)/3 +1 ))
And as such, the quarter of current and previous month would be:
echo curr ${y}q$(((m-1)/3+1))
if [ $m = 1 ]; then
echo prev $((y-1))q4
else
echo prev ${y}q$(((m-2)/3+1))
fi
It's only twelve values to check, really…
% for m in {1..12}; do echo $m Q$(((m-1)/3+1)); done
1 Q1
2 Q1
3 Q1
4 Q2
5 Q2
6 Q2
7 Q3
8 Q3
9 Q3
10 Q4
11 Q4
12 Q4
Use my dateutils:
dconv 2012-01-01 -f '%Y%Q'
=>
2012Q1
The %q
and %Q
flags are specific to dateutils, and return the quarter as number or in the form Q<NUMBER>
.
dconv now -f%Y%Q | tr Q q
if you really need that Q to be lower cased. (PS: we're packaging this in Fedora with date
as the prefix instead of d
, so "dateconv
".)
Probably, there is no direct solution.
You could use awk
to avoid so many back-ticks.
date +"%Y %m" | awk '{q=int($2/4)+1; printf("%sq%s\n", $1, q);}'
date +"%Y %m" | awk '{q=int($2/4);y=$1;if (q==0){q=4;y=y-1;}; printf("%sq%s\n", y, q);}'
A perl
solution would be cleaner but perl
and DateTime
are an heavy prerequisite.
#!/usr/bin/perl
use DateTime;
my $today = DateTime->now;
print "today: " . $today->year . "q" . $today->quarter . "\n";
my $ago = DateTime->now->subtract( months=> 4);
print "some time ago: " . $ago->year . "q" . $ago->quarter . "\n"
date
twice.
Split the format with date, calculate with awk, format with printf:
date +"%Y %m" | awk '{printf ("%4dq%1d\n", $1, ($2/4)+1)}'
Just date and bash:
echo $(date +%Yq)$(($(date +%m)/4+1))
An alternative, more as a curiosity. If GNU awk
is involved, date
is not needed:
awk 'BEGIN{print strftime("%Y")"q"int((strftime("%-m")-1)/3)+1}'
Call date
to retrieve the current year and month, and do the rest with arithmetic in the shell.
set $(date '+%Y %m');
this_quarter=${1}q$(($2 / 4 + 1))
if [ $2 -eq 1 ]; then
last_month_quarter=$(($1 - 1))q4
else
last_month_quarter=${1}q$((($2 - 1) / 4 + 1))
fi
Year-Quarter for this month
date +"%Yq$(expr $(expr $(date +%m) - 1) / 3 + 1)"
Year-Quarter for yester-month
date +"%Yq$(expr $(expr $(date -d '-1 month' +%m) - 1) / 3 + 1)"
Basic math for this quarter and last month's quarter:
y1=$(date +%Y)
m1=$(date +%m)
q1=$(( (m1 - 1) / 3 + 1))
y2=$(( y1 - (m1 == 1) ))
m2=$(( (m1 + 10) % 12 + 1 ))
q2=$(( (m2 - 1) / 3 + 1 ))
echo This Quarter: $((y1))q$q1
echo Last Month Quarter: $((y2))q$q2
The script uses the following parts:
There is now the %q
format to show this information.
From the coreutils-8.26 release log from November 30, 2016:
New Features
...
date now accepts the %q format to output the quarter of the year.
And yes it works!
$ date "+%q"
4
$ date "+%Yq%q"
2016q4
If you want the fiscal 13-week quarter that's based on the ISO week calendar, then the new handy %q isn't going to work, sadly. Here's a version of @manatwork's dateless solution with awk/strftime.
awk 'BEGIN{$x=int((strftime("%V")-1)/13)+1;print strftime("%G")"q"($x>4?4:$x)}'
The last little ternary bit handles the ISO leap-week years where the last quarter has 14 weeks.