9

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.

10 Answers 10

10

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.

  • 2
    Take $(...) instead of the deprecated backticks. They can easily be nested. – user unknown Feb 15 '12 at 4:45
  • 1
    just be curious: why other answers use 4 as divisor. – LiuYan 刘研 Jan 29 '13 at 10:32
  • 2
    @LiuYan刘研: Not sure. There are 3 months in a quarter, so I think 3 is the correct divisor. (Though that confused me at first, too.) – smokris Jan 29 '13 at 15:10
  • In 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. – Matthew Jul 17 '15 at 22:07
5

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".) – mattdm May 28 '15 at 1:36
5

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
  • 1
    +1 For "All solutions that divide by for fail". You're right! A quarter last for 3 months so the answers should be dividing by 3. – Stephen Quan May 28 '15 at 0:31
4

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"
  • Cool. I like the first date/awk line, since it avoids calling (and passing parameters to) date twice. – smokris Feb 15 '12 at 1:49
4

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))
  • The first line outputs 2012q0 which is incorrect. – smokris Feb 15 '12 at 4:25
  • @smokris: You're right - I picked the wrong line of my tests. – user unknown Feb 15 '12 at 4:41
4

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}'
3

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
2

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)"
2

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:

  1. $(unix-cmd) - evaluates a command in shell script
  2. $((expr)) - evaluates a mathematical expression
  3. remapping 1..12 -> 1..4 uses the following math (m-1)/3+1
  4. evaluating the previous month uses modulo math
2

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.