data: uzyskaj bieżący odstęp 15 minut

15

Czy jest jakiś sposób na uzyskanie bieżącego 15-minutowego interwału za pomocą polecenia daty lub podobnego?

np. %Y.%m.%d %H:%M da mi coś takiego jak data 2011.02.22 10:19, potrzebuję czegoś, co przyniesie 2011.02.22 10:15czas od 10:15do 10:29.

nos
źródło

Odpowiedzi:

17

Możesz pobrać bieżący znacznik czasu unix date "+%s", znaleźć bieżący kwadrans za pomocą prostej matematyki (mój przykład jest w bash) i wydrukować go w lepszym formacie za pomocą date:

curdate=`date "+%s"`
curquarter=$(($curdate - ($curdate % (15 * 60))))
date -d"@$curquarter"

@Składnia aby ustawić aktualną datę i godzinę z datownika jest rozbudowa GNU do tej pory, jeśli nie działa na OS, można zrobić to samo jak ten (nie zapomnij podać UTC, w przeciwnym razie, to won” t pracy):

date -d"1970-01-01 $curquarter seconds UTC"
jon_d
źródło
5

Poniższe metody sprawiają, że nie trzeba dzwonić datedwukrotnie.
Narzut wywołania systemowego może wykonać „proste” polecenie 100 razy wolniej niż bash, robiąc to samo w swoim lokalnym środowisku.

AKTUALIZACJA Krótka wzmianka o moim powyższym komentarzu: „100 razy wolniej”. Teraz można odczytać „ 500 razy wolniej” ... Niedawno wpadłem (nie, szedłem na oślep) do tego właśnie problemu. tutaj jest link: Szybki sposób na zbudowanie pliku testowego

eval $(date +Y=%Y\;m=%m\;d=%d\;H=%H\;M=%M)
[[ "$M" < "15" ]] && M=00 # cater for octal clash
M=$(((M/15)*15))
((M==0)) && M=00 # the math returns 0, so make it 00  
echo $Y.$m.$d $H:$M  

lub

eval $(date +Y=%Y\;m=%m\;d=%d\;H=%H\;M=%M)
if   [[ "$M" < "15" ]] ; then M=00
elif [[ "$M" < "30" ]] ; then M=15
elif [[ "$M" < "45" ]] ; then M=30
else M=45
fi
echo $Y.$m.$d $H:$M

Obie wersje zostaną zwrócone tylko

2011.02.23 01:00
2011.02.23 01:15
2011.02.23 01:30
2011.02.23 01:45   

Oto pierwszy z pętlą TEST dla wszystkich 60 wartości {00..59}

for X in {00..59} ;                         ###### TEST
do                                          ###### TEST 
  eval $(date +Y=%Y\;m=%m\;d=%d\;H=%H\;M=%M)
  M=$X                                      ###### TEST 
  [[ "$M" < "15" ]] && M=00 # cater for octal clash
  M=$(((M/15)*15))
  ((M==0)) && M=00 # the math returns 0, so make it 00  
  echo $Y.$m.$d $H:$M 
done                                        ###### TEST 
Peter.O
źródło
1
Tylko dla wyjaśnienia - przez „wywołanie systemowe” masz na myśli „fork / exec / wait”, podobnie jak wywołanie systemowe (), a nie ogólne wywołanie systemowe . (Wspominam o tym, ponieważ wykonywanie wywołań systemowych ma również narzut w programie, ze względu na przełącznik użytkownik / jądro. To nie jest szczególny problem tutaj.)
mattdm
mattdm ... Dzięki .. Pracuję na Linuksie tylko od 6 miesięcy, więc prawdopodobnie użyłem złego wyrażenia, ale wciąż czytam o kosztach związanych z niepotrzebnymi połączeniami i z własnego doświadczenia w testowaniu własnego skrypty, widziałem wiele przykładów, gdzie dzwoni printflub sed, a także, że „niepotrzebne” catvs <plik robi dramatyczną rzeczywistą różnicę czasu wykonywania. podczas zapętlania, jak w moim przykładzie „500 razy wolniejszym”. Wydaje się, że używanie powłoki tam, gdzie to możliwe, i pozwalanie programowi takiemu jak dateproces wsadowy, mam na myśli… np. Przykład Gillesa Left-Pad-0, a printf
Peter.O
3

Oto sposób pracy nad datami w powłoce. Najpierw wywołaj, dateaby pobrać komponenty i wypełnić parametry pozycji ( $1, $2itp.) Komponentami (zauważ, że jest to jeden z tych rzadkich przypadków, w których chcesz użyć $(…)poza podwójnymi cudzysłowami, aby rozbić ciąg na słowa). Następnie wykonaj arytmetykę, testy lub cokolwiek innego, co musisz zrobić na komponentach. Na koniec zmontuj elementy.

Część arytmetyczna może być nieco trudna, ponieważ powłoki traktują 0jak ośmiokrotny przedrostek; na przykład tutaj $(($5/15))nie powiedzie się o 8 lub 9 minut po godzinie. Ponieważ jest co najwyżej jeden wiodący 0, ${5#0}jest bezpieczny dla arytmetyki. Dodanie 100, a następnie usunięcie, 1jest sposobem na uzyskanie stałej liczby cyfr na wyjściu.

set $(date "+%Y %m %d %H %M")
m=$((100+15*(${5#0}/15)))
last_quarter_hour="$1.$2.$3 $4:${m#1}"
Gilles „SO- przestań być zły”
źródło
„Sztuczki handlu” ... dobry. :)
Peter.O
2

Może to już nie ma znaczenia, ale możesz wypróbować moje własne dateutils . Zaokrąglanie (w dół) do minut odbywa się za droundpomocą argumentu ujemnego:

dround now /-15m
=>
  2012-07-11T13:00:00

Lub zastosować się do swojego formatu:

dround now /-15m -f '%Y.%m.%d %H:%M'
=>
  2012.07.11 13:00
hroptatyr
źródło
czy tak właściwie działają już twoje narzędzia? Używając -15m, przewijam dane wejściowe do najbliższych 15 minut po godzinie: nie dateutils.dround '2018-11-12 13:55' -15mprodukuje . 2018-11-12T13:15:002018-11-12T13:45:00
1
@JackDouglas Narzędzia ewoluowały, a teraz chcesz: /-15mtj. Zaokrąglić w dół do następnej wielokrotności 15 minut w ciągu godziny. Ta funkcja ma bardziej nieporęczną składnię, ponieważ akceptuje mniej wartości, / -13 m nie jest możliwe, na przykład ponieważ 13 nie jest dzielnikiem 60 (minut na godzinę)
hroptatyr
Fajnie, dostaję to, czego teraz potrzebuję dateutils.dround '2018-11-12 12:52:31' /450s /-15m, dzięki!
2

Niektóre powłoki są w stanie wykonać pracę bez wywoływania zewnętrznego datepolecenia:

a=$(printf '%(%s)T\n'); printf '%(%Y.%m.%d %H:%M)T\n' "#$((a-a%(15*60)))"
a=$(printf '%(%s)T\n'); printf '%(%Y.%m.%d %H:%M)T\n' "$((a-a%(15*60)))"
zmodload zsh/datetime; a=$EPOCHSECONDS; strftime '%Y-%m-%d %H:%M' $((a-a%(15*60)))

Trzy powyższe zapewniają czas lokalny (nie UTC). W razie potrzeby użyj wiodącego TZ = UTC0.

Składnia ksh i bash jest prawie identyczna (z wyjątkiem wymaganej #w ksh). Zsh wymaga załadowania modułu (zawartego w dystrybucji zsh).

Można to również zrobić za pomocą awk (GNU):

awk 'BEGIN{t=systime();print strftime("%Y.%m.%d %H:%M",t-t%(15*60),1)}'

Zapewnia to wynik UTC (zmień ostatni 1na 0), jeśli lokalny jest potrzebny. Ale ładowanie zewnętrznego awk lub zewnętrznego modułu zsh może być tak wolne jak sama data wywołania:

a=$(date +%s); date -ud "@$((a-a%(15*60)))" +'%Y.%m.%d %H:%M'

Mały plik wykonywalny, taki jak, busyboxmoże zapewnić podobne wyniki:

a=$(busybox date +%s);busybox date -ud "@$((a-a%(15*60)))" +'%Y.%m.%d %H:%M'

Zauważ, że wiodące słowo busybox może zostać pominięte, jeśli busybox jest powiązany z tymi nazwami w katalogu ŚCIEŻKI.

Zarówno wyżej, jak datei busybox datewyżej będą drukować czasy UTC. Usuń -uopcję czasu lokalnego.


Jeśli twój system operacyjny ma bardziej ograniczoną wersję daty (i właśnie tego musisz użyć), spróbuj:

a=$(date +%s); a=$(( a-a%(15*60) ))
date -d"1970-01-01 $a seconds UTC" +'%Y.%m.%d %H:%M'

Lub, jeśli we FreeBSD, spróbuj:

a=$(date +%s); a=$(( a-a%(15*60) ))
date -r "$a" +'%Y.%m.%d %H:%M'
Izaak
źródło
1

Jeśli możesz dwa razy żyć z datą dzwonienia, ta działa bash na Solarisie:

date +"%Y.%m.%d %H:$(( $(date +'%M') / 15 * 15 ))"

Edytowane w imieniu komentarza do:

date +"%Y.%m.%d %H:$(( $(date +'%M') / 15 * 15 ))" | sed 's/:0$/:00/'
ddeimeke
źródło
1
W pierwszym kwadransie godziny spowoduje to wygenerowanie minut z pojedynczym 0 zamiast 00
Peter.O
Poprawiony, jest to prosty sed po oryginalnym poleceniu.
ddeimeke
Jeszcze jeden błąd: nie działa między H: 08 a H: 10. Zobacz moją odpowiedź na pytanie dlaczego i poprawkę.
Gilles „SO- przestań być zły”
-1

Nie jestem pewien dokładnych wymagań. Jeśli jednak chcesz wygenerować czas po 15 minutach, możesz użyć czegoś takiego date -d '+15 min'. Dane wyjściowe pokazano poniżej:

$ date; date  -d '+15 min'
Tue Feb 22 18:12:39 IST 2011
Tue Feb 22 18:27:39 IST 2011
Barun
źródło
1
Źle zrozumiałeś pytanie. Chodzi o to, aby zaokrąglić datę (w dół) do wielokrotności 15 minut.
Gilles „SO- przestań być zły”