date: obtenir l'intervalle actuel de 15 minutes

15

Existe-t-il un moyen d'obtenir l'intervalle actuel de 15 minutes à l'aide de la commande date ou similaire?

Par exemple, quelque chose comme la date %Y.%m.%d %H:%M me donnera 2011.02.22 10:19, j'ai besoin de quelque chose qui cède 2011.02.22 10:15dans le laps de temps de 10:15à 10:29.

non
la source

Réponses:

17

Vous pouvez obtenir l'horodatage Unix actuel avec date "+%s", trouver le quart d'heure actuel avec des calculs simples (mon exemple est bashdedans) et l'imprimer avec un meilleur format avec date:

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

La @syntaxe pour définir la date et l'heure actuelles à partir d'un horodatage est une extension GNU à ce jour, si cela ne fonctionne pas sur votre système d'exploitation, vous pouvez faire la même chose comme ceci (n'oubliez pas de spécifier UTC, sinon, il gagnera ' t travail):

date -d"1970-01-01 $curquarter seconds UTC"
jon_d
la source
5

Les méthodes suivantes rendent inutile d'appeler datedeux fois.
La surcharge d'un appel système peut rendre une commande "simple" 100 fois plus lente que bash faire la même chose dans son propre environnement local.

MISE À JOUR Juste une brève mention de mon commentaire ci-dessus: "100 fois plus lent". Il peut maintenant lire " 500 fois plus lentement" ... Je suis récemment tombé (non, j'ai marché aveuglément) sur ce problème. voici le lien: Un moyen rapide de construire un fichier de test

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  

ou

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

Les deux versions ne reviendront que

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

Voici la première avec une boucle TEST pour les 60 valeurs {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
la source
1
Juste pour plus de précision - par "appel système", vous voulez dire "fork / exec / wait, comme l'appel system ()", pas l' appel système en général. (Je mentionne cela parce que faire des appels système a également une surcharge dans un programme, à cause du commutateur utilisateur / noyau. Ce n'est pas le problème particulier ici.)
mattdm
mattdm ... Merci .. Je travaille à partir de seulement 6 mois d'expérience Linux, donc j'ai probablement utilisé la mauvaise phrase, mais je continue à lire sur les frais généraux encourus par les appels inutiles, et dans ma propre expérience de tester la mienne scripts, j'ai vu de nombreux exemples où appeler printfou sedet aussi que "inutile" catvs <fichier fait une différence réelle d'exécution réelle. lors de la boucle, comme dans mon exemple "500 fois plus lent" .. Il semble donc que l'utilisation du shell autant que possible, et permettre un programme tel que datele traitement par lots est ce que je veux dire .. par exemple. Exemple de Gilles-Pad-0 gauche, vs printf
Peter.O
3

Voici un moyen de travailler sur les dates dans le shell. Le premier appel datepour obtenir les composants et remplir les paramètres de position ( $1, $2, etc.) avec les composants (notez que c'est l' un de ces rares cas où vous ne souhaitez utiliser en $(…)dehors des guillemets doubles, pour briser la chaîne en mots). Effectuez ensuite des calculs, des tests ou tout ce que vous devez faire sur les composants. Assemblez enfin les composants.

La partie arithmétique peut être un peu délicate car les coques sont traitées 0comme un préfixe octal; par exemple ici $(($5/15))échouerait à 8 ou 9 minutes après l'heure. Puisqu'il y a au plus un leader 0, ${5#0}est sûr pour l'arithmétique. L'ajout de 100 et la suppression ultérieure du 1est un moyen d'obtenir un nombre fixe de chiffres dans la sortie.

set $(date "+%Y %m %d %H %M")
m=$((100+15*(${5#0}/15)))
last_quarter_hour="$1.$2.$3 $4:${m#1}"
Gilles 'SO- arrête d'être méchant'
la source
"Les astuces du métier" ... une bonne. :)
Peter.O
2

Peut-être que cela n'a plus d'importance, mais vous pouvez essayer mes propres dateutils . L'arrondi (vers le bas) en minutes est effectué avec droundun argument négatif:

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

Ou pour adhérer à votre format:

dround now /-15m -f '%Y.%m.%d %H:%M'
=>
  2012.07.11 13:00
hroptatyr
la source
est-ce vraiment ainsi que fonctionnent vos utils? en utilisant -15m j'obtiens le rembobinage d'entrée à 15 minutes après une heure: ne dateutils.dround '2018-11-12 13:55' -15mproduit 2018-11-12T13:15:00pas 2018-11-12T13:45:00.
1
@JackDouglas Les outils ont évolué, ce que vous voulez maintenant /-15m, c'est-à-dire arrondir au multiple de 15 minutes suivant l'heure. Cette fonction a la syntaxe plus lourde , car il accepte moins de valeurs, / -13m n'est pas possible , par exemple , parce que 13 n'est pas un diviseur de 60 minutes (à l'heure)
hroptatyr
bien, j'obtiens ce dont j'ai besoin maintenant dateutils.dround '2018-11-12 12:52:31' /450s /-15m, merci!
2

Certains shells sont capables de faire le travail sans appeler une datecommande externe :

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

Les trois ci-dessus fournissent l'heure locale (pas UTC). Utilisez un TZ = UTC0 de tête si nécessaire.

La syntaxe ksh et bash est presque identique (sauf pour le nécessaire #dans ksh). Les zsh nécessitent de charger un module (inclus avec la distribution zsh).

Il est également possible de le faire avec (GNU) awk:

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

Cela fournit un résultat UTC (remplacez le dernier 1par 0) si local est nécessaire. Mais le chargement d'un awk externe ou d'un module zsh externe peut être aussi lent que l'appel de date lui-même:

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

Un petit exécutable comme busyboxpourrait fournir des résultats similaires:

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

Notez que le premier mot de la boîte occupée peut être omis si la boîte occupée est liée à ces noms dans un répertoire du CHEMIN.

Les deux dateet busybox dateau - dessus imprimeront les heures UTC. Supprimez l' -uoption pour les heures locales.


Si votre système d'exploitation a une version de date plus limitée (et c'est ce que vous devez utiliser), essayez:

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

Ou, si dans FreeBSD, essayez:

a=$(date +%s); a=$(( a-a%(15*60) ))
date -r "$a" +'%Y.%m.%d %H:%M'
Isaac
la source
1

Si vous pouvez vivre avec la date d'appel deux fois, celle-ci fonctionne en bash sur Solaris:

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

Modifié au nom du commentaire pour:

date +"%Y.%m.%d %H:$(( $(date +'%M') / 15 * 15 ))" | sed 's/:0$/:00/'
ddeimeke
la source
1
Dans le premier trimestre de l'heure, cela produira une sortie de minutes avec un seul 0 au lieu de 00
Peter.O
Corrigé, il s'agit d'un simple sed après la commande d'origine.
ddeimeke
Encore un bug: ça ne marche pas entre H: 08 et H: 10. Voir ma réponse pour savoir pourquoi et un correctif.
Gilles 'SO- arrête d'être méchant'
-1

Je ne suis pas sûr de vos besoins exacts. Cependant, si vous souhaitez générer le temps après 15 min, vous pouvez utiliser quelque chose comme date -d '+15 min'. La sortie est illustrée ci-dessous:

$ date; date  -d '+15 min'
Tue Feb 22 18:12:39 IST 2011
Tue Feb 22 18:27:39 IST 2011
Barun
la source
1
Vous avez mal compris la question. Le but est d'arrondir la date (vers le bas) à un multiple de 15 minutes.
Gilles 'SO- arrête d'être méchant'