Comment générer une date de trimestre à partir de la ligne de commande?

10

Je souhaite produire une représentation du trimestre de l'année en cours, ainsi que du trimestre de l'année du mois précédent.

Si aujourd'hui est le 1er janvier 2012, j'aimerais avoir

2012q1

et

2011q4

comme sorties respectives.

smokris
la source

Réponses:

10

Une solution (un peu moche), utilisant l'évaluation arithmétique BASH et la datecommande GNU :

echo $(date +%Y)q$(( ($(date +%-m)-1)/3+1 ))
echo $(date -d "-1 month" +%Y)q$(( ($(date -d "-1 month" +%-m)-1)/3+1 ))

Notez que le %-mempêche datede remplissage 0, donc cela fonctionnera toujours pour août et septembre.

smokris
la source
2
Prenez $ (...) au lieu des astuces déconseillées. Ils peuvent facilement être imbriqués.
utilisateur inconnu
1
soyez juste curieux: pourquoi les autres réponses utilisent 4 comme diviseur.
LiuYan 刘 研
2
@LiuYan 刘 研: Pas sûr. Il y a 3 mois dans un trimestre, donc je pense que 3 est le bon diviseur. (Même si cela m'a dérouté au début aussi.)
smokris
En Septembre %mdonne 09qui tente bash d'interpréter comme octal en raison de le 0, donc cela jette une erreur qui dit 09: value too great for base (error token is "09"). Cela peut être résolu en désactivant le remplissage 0 en passant %mà %-m.
Matthew
5

Utilisez mes dateutils :

dconv 2012-01-01 -f '%Y%Q'
=>
  2012Q1

Les drapeaux %qet %Qsont spécifiques aux dateutils et renvoient le trimestre sous forme de nombre ou dans le formulaire Q<NUMBER>.

hroptatyr
la source
dconv now -f%Y%Q | tr Q qsi vous avez vraiment besoin que ce Q soit inférieur. (PS: nous emballons ceci dans Fedora avec datecomme préfixe au lieu de d, donc " dateconv".)
mattdm
5

Toutes les solutions divisées par quatre échouent, par exemple en novembre:

% echo $(( 11/4+1 ))
3

Le calcul correct serait:

$(( (m-1)/3 +1 ))

Et en tant que tel, le trimestre du mois en cours et du mois précédent serait:

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

Ce n'est que douze valeurs à vérifier, vraiment ...

% 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
bif
la source
1
+1 Pour "Toutes les solutions qui se divisent par échec". Tu as raison! Un quart dernier pour 3 mois donc les réponses devraient être divisées par 3.
Stephen Quan
4

Il n'y a probablement pas de solution directe.

Vous pouvez utiliser awkpour éviter autant de tiques en arrière.

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);}'

Une perlsolution serait plus propre mais perlet DateTimesont une condition sine qua non lourd.

#!/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"
andcoz
la source
Cool. J'aime la première ligne date / awk, car elle évite d'appeler (et de passer des paramètres à) datedeux fois.
smokris
4

Divisez le format avec la date, calculez avec awk, formatez avec printf:

date +"%Y %m" | awk '{printf ("%4dq%1d\n", $1, ($2/4)+1)}'

Juste date et bash:

echo $(date +%Yq)$(($(date +%m)/4+1))
Utilisateur inconnu
la source
La première ligne sort, 2012q0ce qui est incorrect.
smokris
@smokris: Vous avez raison - j'ai choisi la mauvaise ligne de mes tests.
utilisateur inconnu
4

Une alternative, plus comme curiosité. Si GNU awkest impliqué, daten'est pas nécessaire:

awk 'BEGIN{print strftime("%Y")"q"int((strftime("%-m")-1)/3)+1}'
homme au travail
la source
3

Appelez datepour récupérer l'année et le mois en cours et faites le reste avec l'arithmétique dans la coquille.

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
Gilles 'SO- arrête d'être méchant'
la source
2

Trimestre pour ce mois

date +"%Yq$(expr $(expr $(date +%m) - 1) / 3 + 1)"

Trimestre annuel pour le mois précédent

date +"%Yq$(expr $(expr $(date -d '-1 month' +%m) - 1) / 3 + 1)"
rthbound
la source
2

Mathématiques de base pour ce trimestre et le trimestre du mois dernier:

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

Le script utilise les parties suivantes:

  1. $ (unix-cmd) - évalue une commande dans un script shell
  2. $ ((expr)) - évalue une expression mathématique
  3. le remappage 1..12 -> 1..4 utilise le calcul suivant (m-1) / 3 + 1
  4. évaluer le mois précédent utilise modulo math
Stephen Quan
la source
2

Il y a maintenant le %qformat pour afficher ces informations.

Depuis le journal des versions de coreutils-8.26 du 30 novembre 2016:

Nouvelles fonctionnalités
...
date accepte désormais le format% q pour afficher le trimestre de l'année.

Et oui ça marche!

$ date "+%q"
4
$ date "+%Yq%q"
2016q4
fedorqui
la source
0

Si vous voulez le trimestre fiscal de 13 semaines basé sur le calendrier hebdomadaire ISO, le nouveau% q pratique ne fonctionnera malheureusement pas. Voici une version de la solution sans date de @ manatwork avec awk / strftime.

awk 'BEGIN{$x=int((strftime("%V")-1)/13)+1;print strftime("%G")"q"($x>4?4:$x)}'

Le dernier petit morceau ternaire gère les années ISO de semaine bissextile où le dernier trimestre a 14 semaines.

TKH
la source