Obtenga la fecha de ayer en bash en Linux, seguro para DST

158

Tengo un script de shell que se ejecuta en Linux y utiliza esta llamada para obtener la fecha de ayer en YYYY-MM-DDformato:

date -d "1 day ago" '+%Y-%m-%d'

Funciona la mayor parte del tiempo, pero cuando la secuencia de comandos se ejecutó ayer por la mañana en lugar de 2013-03-11 0:35 CDTvolver ."2013-03-09""2013-03-10"

Presumiblemente, el horario de verano (que comenzó ayer) es el culpable. Estoy adivinando el camino "1 day ago"se implementa se resta 24 horas y 24 horas antes de la 2013-03-11 0:35 CDTera 2013-03-09 23:35 CST, lo que llevó al resultado de "2013-03-09".

Entonces, ¿cuál es una buena forma segura de DST de obtener la fecha de ayer en bash en Linux?

Ike Walker
fuente
¿Siempre está ejecutando esto al mismo tiempo, lo está ejecutando repetidamente?
Tink
@tink funciona todos los días a las 00:35
Ike Walker

Respuestas:

267

Creo que esto debería funcionar, independientemente de con qué frecuencia y cuándo lo ejecute ...

date -d "yesterday 13:00" '+%Y-%m-%d'
tink
fuente
1
¿Cómo asignarías esto a una variable para usarla más adelante?
nulo
66
@null: de la misma manera que asignaría la salida de cualquier otro comando de shell. variable = $ (fecha -d "ayer 13:00" '+% Y-% m-% d') ...
tink
Para GNU-date:date -d yesterday 13:00 -I
gogstad
Esto se basa en el hecho de que el cambio entre el verano y el invierno siempre se realiza durante la noche, si lo entiendo correctamente.
Nicolas Raoul
2
@NicolasRaoul: No está garantizado; pero es una convención ampliamente seguida programar esto temprano en la mañana. Por otro lado, el IIRC no tiene un lugar donde el cambio ocurra cerca del mediodía local. Entonces, "1300J nunca está en un límite DST" es una suposición razonable .
Piskvor salió del edificio el
56

La fecha bajo Mac OSX es ligeramente diferente.

Para ayer

date -v-1d +%F

Para la semana pasada

date -v-1w +%F
Aries
fuente
8
Si está interesado en usar el estilo GNU dentro de OSX, también puede usarlo gdate, disponible en el coreutilspaquete de homebrew .
user456584
11
Quieres decir que datees diferente.
augurar
12

Esto también debería funcionar, pero quizás sea demasiado:

date -d @$(( $(date +"%s") - 86400)) +"%Y-%m-%d"
perreal
fuente
Se necesitan cosas como esta si necesita lidiar con Mac OS X dateque no admite la yesterdaysintaxis ...
Mikko Rantalainen
7

Si está seguro de que el script se ejecuta en las primeras horas del día, simplemente puede hacer

  date -d "12 hours ago" '+%Y-%m-%d'

Por cierto, si el script se ejecuta diariamente a las 00:35 (¿a través de crontab?), Debe preguntarse qué sucederá si un cambio de horario de verano cae en esa hora; el script no pudo ejecutarse, o ejecutarse dos veces en algunos casos. Sin embargo, las implementaciones modernas de cronson bastante inteligentes a este respecto.

leonbloy
fuente
5

puedes usar

date -d "30 days ago" +"%d/%m/%Y"

para obtener la fecha de hace 30 días, de manera similar, puede reemplazar 30 con x cantidad de días

Dan Pickard
fuente
Debe cambiar su formato para %Y%m%dque coincida con la pregunta. Voté de todos modos, ya que funcionó correctamente.
isapir
4

Aquí una solución que también funcionará con Solaris y AIX.

La manipulación de la zona horaria es posible para cambiar el reloj algunas horas. Debido al horario de verano, hace 24 horas puede ser hoy o anteayer.

Estás seguro de que ayer fue hace 20 o 30 horas. ¿Cúal? Bueno, el más reciente que no es hoy.

echo -e "$(TZ=GMT+30 date +%Y-%m-%d)\n$(TZ=GMT+20 date +%Y-%m-%d)" | grep -v $(date +%Y-%m-%d) | tail -1

El parámetro -e utilizado en el comando echo es necesario con bash, pero no funcionará con ksh. En ksh puede usar el mismo comando sin la bandera -e.

Cuando su script se utilizará en diferentes entornos, puede iniciar el script con #! / Bin / ksh o #! / Bin / bash. También puede reemplazar el \ n por una nueva línea:

echo "$(TZ=GMT+30 date +%Y-%m-%d)
$(TZ=GMT+20 date +%Y-%m-%d)" | grep -v $(date +%Y-%m-%d) | tail -1
Walter A
fuente
0

Solo usa date y segundos de confianza:

Como señala correctamente, muchos de los detalles sobre el cálculo subyacente se ocultan si confía en la aritmética del tiempo en inglés. Por ejemplo -d yesterday, y-d 1 day ago tendrá un comportamiento diferente.

En cambio, puede confiar de manera confiable en los segundos (documentados con precisión) desde el UTC de época de Unix y la aritmética de bash para obtener el momento que desee:

date -d @$(( $(date +"%s") - 24*3600)) +"%Y-%m-%d"

Esto se señaló en otra respuesta . Este formulario es más portátil en todas las plataformas con diferentes dateindicadores de línea de comandos, es independiente del idioma (por ejemplo, "ayer" frente a "hier" en francés) y, francamente (a largo plazo), será más fácil de recordar, porque bueno, usted ya lo se. De lo contrario, podría seguir preguntándose: "¿Fue -d 2 hours agoo fue de -d 2 hour agonuevo?" o "¿Es -d yesterdayo -d 1 day agoeso quiero?"). Lo único difícil aquí es el@ .

Armado con bash y nada más:

Bash únicamente en bash, también puede obtener la hora de ayer, a través de printf incorporado:

 %(datefmt)T
     causes printf to output the date-time string resulting from using
     datefmt as a format string for strftime(3).  The  corresponding  argu
     ment  is an integer representing the number of seconds since the
     epoch.  Two special argument values may be used: -1 represents the
     current time, and -2 represents the time the shell was invoked.
     If no argument is specified, conversion behaves as if -1 had
     been  given.
     This is an exception to the usual printf behavior.

Entonces,

# inner printf gets you the current unix time in seconds
# outer printf spits it out according to the format
printf "%(%Y-%m-%d)T\n" $(( $(printf "%(%s)T" -1) - 24*3600 ))

o, de manera equivalente con una variable temporal (subshell externo opcional, pero mantiene el entorno vars limpio).

(
  now=$(printf "%(%s)T" -1);
  printf "%(%Y-%m-%d)T\n" $((now - 24*3600));
)

Nota: a pesar de que la página de manual indica que ningún argumento para el %()Tformateador asumirá un valor predeterminado -1, parece que obtengo un 0 en su lugar (gracias, bash manual versión 4.3.48)

init_js
fuente
0
date -d "yesterday" '+%Y-%m-%d'

Para usar esto más tarde:

date=$(date -d "yesterday" '+%Y-%m-%d')
suresh Palemoni
fuente
2
Si bien este código puede resolver el problema del OP, es mejor incluir una explicación sobre cómo su código aborda el problema del OP. De esta manera, los futuros visitantes pueden aprender de su publicación y aplicarla a su propio código. SO no es un servicio de codificación, sino un recurso para el conocimiento. Las respuestas completas y de alta calidad refuerzan esta idea, y es más probable que sean votados. Estas características, más el requisito de que todas las publicaciones sean independientes, son algunos puntos fuertes de SO como una plataforma que nos diferencia de los foros. Puede editar para agregar información adicional y / o complementar sus explicaciones con la documentación de origen.
SherylHohman
0

Puedes usar:

date -d "yesterday 13:55" '+%Y-%m-%d'

O cualquier momento que desee recuperar será recuperado por bash.

Por mes:

date -d "30 days ago" '+%Y-%m-%d'
Daremitsu
fuente
0

Como esta pregunta está etiquetada "DST seguro"

Y usando fork para dateordenar el retraso implícito, hay una manera simple y más eficiente de usar bash puro incorporado:

printf -v tznow '%(%z %s)T' -1
TZ=${tznow% *} printf -v yesterday '%(%Y-%m-%d)T' $(( ${tznow#* } - 86400 ))
echo $yesterday

Esto es mucho más rápido en más amigable sistema de tener que desembolsar a date.

De V> = 5.0 , hay una nueva variable$EPOCHSECONDS

printf -v tz '%(%z)T' -1
TZ=$tz printf -v yesterday '%(%Y-%m-%d)T' $(( EPOCHSECONDS - 86400 ))
echo $yesterday
F. Hauri
fuente