Jak wygenerować datę kwartału z wiersza poleceń?

10

Interesuje mnie przedstawienie reprezentacji bieżącego kwartału, a także kwartału poprzedniego miesiąca.

Jeśli dzisiaj jest 1 stycznia 2012 r., Chciałbym dostać

2012q1

i

2011q4

jako odpowiednie wyjścia.

smokris
źródło

Odpowiedzi:

10

Jedno (trochę brzydkie) rozwiązanie, wykorzystujące analizę arytmetyczną BASH i datepolecenie 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 ))

Pamiętaj, że %-mzapobiega datezerowaniu, więc nadal będzie działać w sierpniu i wrześniu.

smokris
źródło
2
Weź $ (...) zamiast przestarzałych tyknięć. Można je łatwo zagnieżdżać.
użytkownik nieznany
1
bądźcie ciekawi: dlaczego inne odpowiedzi używają 4 jako dzielnika.
LiuYan
2
@LiuYan 刘 研: Nie jestem pewien. Są trzy miesiące na kwartał, więc myślę, że 3 to właściwy dzielnik. (Choć to też na początku mnie zdezorientowało).
smokris 29.01.2013
We wrześniu %mdaje, 09który bash próbuje interpretować jako ósemkowy z powodu wiodącego 0, więc generuje to błąd, który mówi 09: value too great for base (error token is "09"). Można to naprawić, wyłączając wypełnienie 0, zmieniając %mna %-m.
Matthew
5

Użyj moich dateutils :

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

%qI %Qflagi są specyficzne dla dateutils i powrót kwartał pod numerem lub w formie Q<NUMBER>.

hroptatyr
źródło
dconv now -f%Y%Q | tr Q qjeśli naprawdę potrzebujesz tego Q, aby małe litery. (PS: dateddateconv
pakujemy
5

Wszystkie rozwiązania dzielone przez cztery zawodzą, na przykład listopad:

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

Prawidłowa matematyka to:

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

I jako taki kwartał bieżącego i poprzedniego miesiąca byłby następujący:

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

To tylko dwanaście wartości do sprawdzenia, naprawdę…

% 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
źródło
1
+1 za „Wszystkie rozwiązania, które dzielą się z powodu niepowodzenia”. Masz rację! Jedna czwarta trwa przez 3 miesiące, więc odpowiedzi powinny być dzielone przez 3.
Stephen Quan
4

Prawdopodobnie nie ma bezpośredniego rozwiązania.

Możesz użyć, awkaby uniknąć tylu tyknięć.

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

perlRozwiązaniem byłoby czyszczenia, ale perli DateTimesą ciężkie nieodzowna.

#!/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
źródło
Fajne. Podoba mi się pierwsza linia date / awk, ponieważ unika ona datepodwójnego wywoływania (i przekazywania parametrów) .
smokris
4

Podziel format na datę, oblicz za pomocą awk, sformatuj za pomocą printf:

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

Tylko randka i bash:

echo $(date +%Yq)$(($(date +%m)/4+1))
nieznany użytkownik
źródło
Wyjście pierwszego wiersza, 2012q0które jest niepoprawne.
smokris
@smokris: Masz rację - wybrałem złą linię moich testów.
użytkownik nieznany
4

Alternatywa, bardziej jako ciekawostka. Jeśli awkzaangażowany jest GNU , datenie jest potrzebny:

awk 'BEGIN{print strftime("%Y")"q"int((strftime("%-m")-1)/3)+1}'
człowiek w pracy
źródło
3

Zadzwoń, dateaby pobrać bieżący rok i miesiąc, a resztę wykonaj z arytmetyką w powłoce.

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- przestań być zły”
źródło
2

Rok-kwartał w tym miesiącu

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

Rok-kwartał za ostatni miesiąc

date +"%Yq$(expr $(expr $(date -d '-1 month' +%m) - 1) / 3 + 1)"
rthbound
źródło
2

Podstawowa matematyka dla tego kwartału i kwartału ubiegłego miesiąca:

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

Skrypt składa się z następujących części:

  1. $ (unix-cmd) - ocenia polecenie w skrypcie powłoki
  2. $ ((wyrażenie)) - ocenia wyrażenie matematyczne
  3. odwzorowanie 1..12 -> 1..4 używa następującej matematyki (m-1) / 3 + 1
  4. oceniając poprzedni miesiąc używa matematyki modulo
Stephen Quan
źródło
2

Istnieje teraz %qformat wyświetlania tych informacji.

Z dziennika wersji coreutils-8.26 z 30 listopada 2016 r .:

Nowe funkcje
...
data akceptuje teraz format% q w celu wygenerowania kwartału roku.

I tak to działa!

$ date "+%q"
4
$ date "+%Yq%q"
2016q4
fedorqui
źródło
0

Jeśli chcesz 13-tygodniowego kwartału obrachunkowego opartego na kalendarzu tygodni ISO, nowy przydatny% q niestety nie zadziała. Oto wersja bez danych rozwiązania @ manatwork z awk / strftime.

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

Ostatni mały bit trójskładnikowy obsługuje lata przestępne ISO, w których ostatni kwartał ma 14 tygodni.

TKH
źródło