fecha: obtener el intervalo actual de 15 minutos


15

¿Hay alguna manera de obtener el intervalo actual de 15 minutos usando el comando de fecha o similar?

por ejemplo, algo como la fecha %Y.%m.%d %H:%M me dará 2011.02.22 10:19, necesito algo que ceda 2011.02.22 10:15en el lapso de tiempo de 10:15a 10:29.

Respuestas:


17

Puede obtener la marca de tiempo actual de Unix date "+%s", encontrar el cuarto de hora actual con algunas matemáticas simples (mi ejemplo está en bash) e imprimirlo de nuevo con un mejor formato con date:

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

La @sintaxis para establecer la fecha y hora actuales de una marca de tiempo es una extensión de GNU hasta la fecha, si no funciona en su sistema operativo, puede hacer lo mismo de esta manera (no olvide especificar UTC, de lo contrario, ganó ' t trabajo):

date -d"1970-01-01 $curquarter seconds UTC"

5

Los siguientes métodos hacen innecesario llamar datedos veces.
La sobrecarga de una llamada del sistema puede hacer que un comando "simple" sea 100 veces más lento que bash haciendo lo mismo en su propio entorno local.

ACTUALIZACIÓN Solo una mención rápida sobre mi comentario anterior: "100 veces más lento". Ahora puede leer " 500 veces más lento" ... Recientemente caí (no, caminé a ciegas) en este mismo problema. aquí está el enlace: forma rápida de crear un archivo de prueba

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  

o

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

Ambas versiones solo devolverán

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

Aquí está el primero con un bucle TEST para los 60 valores {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 

1
Solo para aclararlo: por "llamada al sistema", quiere decir "fork / exec / wait, como la llamada al sistema ()", no la llamada al sistema en general. (Menciono esto porque hacer llamadas al sistema también tiene una sobrecarga dentro de un programa, debido al cambio de usuario / kernel. Ese no es el problema particular aquí.)
mattdm

mattdm ... Gracias ... Estoy trabajando con solo 6 meses de experiencia en Linux, por lo que es muy probable que haya usado la frase incorrecta, pero sigo leyendo sobre los gastos generales incurridos por llamadas innecesarias, y en mi propia experiencia de probar la mía. scripts, he visto muchos ejemplos en los que llamar printfo sedy también ese catarchivo "innecesario" vs <hace una gran diferencia real en el tiempo de ejecución. al hacer un bucle, como en mi ejemplo "500 veces más lento". Parece que usar el shell siempre que sea posible y permitir que un programa como dateun proceso por lotes sea lo que quiero decir ... por ejemplo. Ejemplo de Gilles 'Left-Pad-0, vs printf
Peter.O

3

Aquí hay una manera de trabajar en fechas en el shell. Primera llamada datepara obtener los componentes, y llenar los parámetros posicionales ( $1, $2, etc.) con los componentes (nota que este es uno de esos casos raros en los que usted desee utilizar $(…)fuera de las comillas dobles, para romper la cadena en palabras). Luego realice aritmética, pruebas o lo que sea que necesite hacer en los componentes. Finalmente ensamblar los componentes.

La parte aritmética puede ser un poco complicada porque las conchas se tratan 0como un prefijo octal; por ejemplo, aquí $(($5/15))fallarían a las 8 o 9 minutos después de la hora. Como hay a lo sumo un líder 0, ${5#0}es seguro para la aritmética. Agregar 100 y luego quitar el 1es una forma de obtener un número fijo de dígitos en la salida.

set $(date "+%Y %m %d %H %M")
m=$((100+15*(${5#0}/15)))
last_quarter_hour="$1.$2.$3 $4:${m#1}"

"Los trucos del oficio" ... uno bueno. :)
Peter.O

2

Tal vez ya no importa, pero puedes probar mis propias dateutils . El redondeo (hacia abajo) a minutos se realiza con droundun argumento negativo:

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

O para adherirse a su formato:

dround now /-15m -f '%Y.%m.%d %H:%M'
=>
  2012.07.11 13:00

¿es así realmente como funcionan tus utilidades? usando -15m obtengo la entrada rebobinada a los 15 minutos más cercanos a la hora: no dateutils.dround '2018-11-12 13:55' -15mproduce . 2018-11-12T13:15:002018-11-12T13:45:00

1
@JackDouglas Las herramientas han evolucionado, lo que quieres es ahora: /-15mes decir, redondear al siguiente múltiplo de 15 minutos en la hora. Esta característica tiene la sintaxis más engorrosa porque acepta menos valores, / -13m no es posible, por ejemplo, porque 13 no es un divisor de 60 (minutos en la hora)
hroptatyr

bien, consigo lo que necesito ahora dateutils.dround '2018-11-12 12:52:31' /450s /-15m, ¡gracias!

2

Algunos shells pueden hacer el trabajo sin llamar a un datecomando externo :

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

Los tres anteriores proporcionan la hora local (no UTC). Use una TZ = UTC0 inicial si es necesario.

La sintaxis de ksh y bash es casi idéntica (excepto la requerida # en ksh). El zsh requiere cargar un módulo (incluido con la distribución zsh).

También es posible hacerlo con (GNU) awk:

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

Esto proporciona un resultado UTC (cambie el último 1a0 ) si se necesita local. Pero cargar un awk externo o un módulo zsh externo puede ser tan lento como llamar a la fecha:

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

Un pequeño ejecutable como busybox podría proporcionar resultados similares:

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

Tenga en cuenta que la palabra principal de busybox puede omitirse si busybox está vinculado a esos nombres en un directorio de la RUTA.

Ambos datey busybox datesuperiores imprimirán las horas UTC. Elimine la -uopción para horas locales.


Si su sistema operativo tiene una versión de fecha más limitada (y eso es lo que debe usar), intente:

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

O, si está en FreeBSD, intente:

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

1

Si puede vivir con la fecha de llamada dos veces, esta funciona en bash en Solaris:

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

Editado en nombre del comentario para:

date +"%Y.%m.%d %H:$(( $(date +'%M') / 15 * 15 ))" | sed 's/:0$/:00/'

1
En el primer trimestre de la hora, esto producirá una salida de minutos con solo un 0 en lugar de 00
Peter.O

Corregido, es un sed simple después del comando original.
ddeimeke

Un error más: no funciona entre H: 08 y H: 10. Vea mi respuesta por qué y una solución.
Gilles 'SO- deja de ser malvado'

-1

No estoy seguro acerca de su requerimiento exacto. Sin embargo, si desea generar el tiempo después de 15 minutos, puede usar algo como date -d '+15 min'. La salida se muestra a continuación:

$ date; date  -d '+15 min'
Tue Feb 22 18:12:39 IST 2011
Tue Feb 22 18:27:39 IST 2011

1
No entendiste la pregunta. El punto es redondear la fecha (abajo) a un múltiplo de 15 minutos.
Gilles 'SO- deja de ser malvado'
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.