Como se explica a continuación, pero sus fechas están al revés: deben ser aaaa-mm-dd
Peter Flynn
Muchas respuestas usan la opción -d de (GNU-) date. Quiero agregar que esto NO es parte de la fecha POSIX, por lo tanto, es menos portátil. Siempre que el OP no funcione en distribuciones Unix como Solaris, sino solo en "Linux común", debería ser bueno. Una etiqueta respectiva ayudaría en mi humilde opinión.
Cadoiz
Respuestas:
33
Si tiene GNU date, permite imprimir la representación de una fecha arbitraria ( -dopción). En este caso, convierta las fechas a segundos desde EPOCH, reste y divida por 24 * 3600.
@Tree: Creo que no hay una forma portátil de restar fechas antes de implementarlo usted mismo; no es tan difícil, lo único que interesa son los años bisiestos. Pero hoy en día todo el mundo quiere restar fechas, como parece: Eche un vistazo a unix.stackexchange.com/questions/1825/… :)
14
Por el bien de lazyweb, creo que esto es lo que quiso decir el usuario332325:echo "( `date -d $B +%s` - `date -d $A +%s`) / (24*3600)" | bc -l
Pablo Mendes
2
¿Qué significa portátil en este contexto?
htellez
@htellez algo que funciona en múltiples plataformas (Windows, Linux, etc.)
Esto no necesariamente necesita que las fechas estén en %y%m%dformato. Por ejemplo, gnu date aceptará el %Y-%m-%dformato que utilizó el OP. En general, ISO-8601 es una buena opción (y el formato de OP es uno de esos formatos). Es mejor evitar los formatos con años de 2 dígitos.
mc0e
2
Por la diferencia de hoy , uno puede querer usar days_diff=$(( (`date -d $B +%s` - `date -d "00:00" +%s`) / (24*3600) )). tenga en cuenta que $days_diffserá un número entero (es decir, sin decimales)
Julien
1
Esto depende de la variante de dateinstalado. Funciona para GNU date. No funciona con POSIX date. Probablemente esto no sea un problema para la mayoría de los lectores, pero vale la pena señalarlo.
Solo para combatir la confusión: el formato de OP no lo es %Y-%m-%d, hasta que lo presentamos August 2.0y October 2.0el formato de OP es %Y-%d-%m. Relevante xkcd: xkcd.com/1179
¡Cuidado! Muchas de las soluciones bash aquí están divididas para rangos de fechas que abarcan la fecha en que comienza el horario de verano (cuando corresponda). Esto se debe a que la construcción $ ((matemáticas)) realiza una operación de 'piso' / truncamiento en el valor resultante, devolviendo solo el número entero. Déjame ilustrarte:
El horario de verano comenzó el 8 de marzo de este año en los EE. UU., Así que usemos un rango de fechas que abarque eso:
Esto también debería ser un segundo intercalar seguro siempre que reste siempre la fecha anterior de la última, ya que los segundos intercalares solo aumentarán la diferencia: el truncamiento se redondea efectivamente al resultado correcto.
Si, en cambio, especifica la zona horaria tanto para el inicio como para el final (y se asegura de que sean iguales), entonces tampoco tendrá este problema, así:, echo $(( ($(date --date="2015-03-11 UTC" +%s) - $(date --date="2015-03-05 UTC" +%s) )/(60*60*24) ))que devuelve 6, en lugar de 5.
Hank Schultz
1
Ah, uno de los que respondieron pensó en las inexactitudes de la solución básica repetida por otros en variantes. ¡Pulgares hacia arriba! ¿Qué tal los segundos intercalares? ¿Es seguro para un segundo intercalar? Hay precedentes de software que devuelve un resultado de un día si se ejecuta en determinados momentos, problemas de referencia asociados con el segundo intercalar .
Stéphane Gourichon
Vaya, el cálculo "incorrecto" que da como ejemplo devuelve correctamente 6 aquí (Ubuntu 15.04 AMD64, fecha GNU versión 8.23). ¿Quizás su ejemplo depende de la zona horaria? Mi zona horaria es "Europa / París".
Stéphane Gourichon
El mismo buen resultado para el cálculo "incorrecto" con GNU date 2.0 en MSYS, misma zona horaria.
Stéphane Gourichon
1
@ StéphaneGourichon, el cambio de horario de verano de su zona horaria parece haber ocurrido el 29 de marzo de 2015, así que pruebe con un rango de fechas que lo incluya.
@mouviciel no realmente. Python no siempre está presente.
mc0e
1
@ mc0e en ese contexto, nada está siempre presente
Sumudu
5
@Anub es el OP especificado en las etiquetas como bashy shell, así que creo que podemos asumir que estamos hablando de un sistema * nix. Dentro de tales sistemas, echoy dateestán presentes de manera confiable, pero Python no lo está.
mc0e
2
@ mc0e sí, eso tiene sentido. Aunque python2 está disponible en la mayoría de los sistemas * nix, cuando se trata de dispositivos de gama baja (embebidos, etc.) tendremos que sobrevivir solo con herramientas primarias.
Si la opción -d funciona en su sistema, aquí hay otra forma de hacerlo. Hay una advertencia de que no daría cuenta de los años bisiestos, ya que he considerado 365 días al año.
-bash: (-) / 86400: error de sintaxis: operando esperado (el token de error es ") / 86400")
cabalgata
1
@cavalcade - eso es porque no lo ha hechoA="2002-20-10"; B="2003-22-11"
RAM237
Gracias, a pesar de que funcione para este caso particular, se recomienda usar echo $(((`date -jf "%Y-%d-%m" "$B" +%s` - `date -jf "%Y-%d-%m" "$A" +%s`)/86400)), es decir, envolver ambos formatos y variables en comillas dobles, de lo contrario puede fallar en diferente formato de fecha (por ejemplo, %b %d, %Y/ Jul 5, 2017)
RAM237
@ RAM237 Eso es lo que obtengo por no prestar atención headmack Bien visto, gracias
cabalgata
5
Incluso si no tiene la fecha de GNU, probablemente tenga Perl instalado:
use Time::Local;
sub to_epoch {
my ($t) = @_;
my ($y, $d, $m) = ($t =~ /(\d{4})-(\d{2})-(\d{2})/);
return timelocal(0, 0, 0, $d+0, $m-1, $y-1900);
}
sub diff_days {
my ($t1, $t2) = @_;
return (abs(to_epoch($t2) - to_epoch($t1))) / 86400;
}
print diff_days("2002-20-10", "2003-22-11"), "\n";
Esto regresa 398.041666666667: 398 días y una hora debido al horario de verano.
La pregunta volvió a aparecer en mi feed. Aquí hay un método más conciso usando un módulo incluido de Perl
Aquí está mi enfoque de trabajo usando zsh. Probado en OSX:
# Calculation dates## A random old date
START_DATE="2015-11-15"## Today's date
TODAY=$(date +%Y-%m-%d)
# Import zsh date modzmodload zsh/datetime
# Calculate number of days
DIFF=$(( ( $(strftime -r %Y-%m-%d $TODAY) - $(strftime -r %Y-%m-%d $START_DATE) ) / 86400 ))
echo"Your value: "$DIFF
Resultado:
Your value: 1577
Básicamente, usamos strftimela -rfunción reverse ( ) para transformar nuestra cadena de fecha nuevamente en una marca de tiempo, luego hacemos nuestro cálculo.
No hay una forma portátil de hacerlo en el propio shell. Todas las alternativas utilizan programas externos particulares (es decir, GNU dateo algún lenguaje de programación) y honestamente creo que Ruby es una buena forma de hacerlo. Esta solución es muy corta y no utiliza bibliotecas no estándar ni otras dependencias. De hecho, creo que hay más posibilidades de tener Ruby instalado que de tener GNU date instalado.
en Unix debería tener instaladas las fechas GNU. no es necesario que se desvíe de bash. aquí está la solución encadenada considerando días, solo para mostrar los pasos. se puede simplificar y ampliar a fechas completas.
Supongamos que sincronizamos manualmente las copias de seguridad de la base de datos de Oracle en un disco terciario. Entonces queremos eliminar las copias de seguridad antiguas en ese disco. Así que aquí hay un pequeño script de bash:
#!/bin/shfor backup_dir in {'/backup/cmsprd/local/backupset','/backup/cmsprd/local/autobackup','/backup/cfprd/backupset','/backup/cfprd/autobackup'}
dofor f in `find $backup_dir -type d -regex '.*_.*_.*' -printf"%f\n"`
do
f2=`echo$f | sed -e 's/_//g'`
days=$(((`date "+%s"` - `date -d "${f2}" "+%s"`)/86400))
if [ $days -gt 30 ]; then
rm -rf $backup_dir/$ffidonedone
Modifique los directorios y el período de retención ("30 días") para adaptarlos a sus necesidades.
Oracle coloca los conjuntos de respaldo en el Área de recuperación de Flash usando un formato como 'YYYY_MM_DD', por lo que eliminamos los guiones bajos para pasarlos a 'date -d'
Alex Cherkas
0
Para MacOS sierra (tal vez de Mac OS X yosemate),
Para obtener el tiempo de época (segundos desde 1970) de un archivo y guardarlo en una var:
old_dt=`date -j -r YOUR_FILE "+%s"`
Para obtener el tiempo de época del tiempo actual
new_dt=`date -j "+%s"`
Para calcular la diferencia del tiempo de dos épocas anteriores
(( diff = new_dt - old_dt ))
Para comprobar si la diferencia es superior a 23 días
(( new_dt - old_dt > (23*86400) )) && echo Is more than 23 days
Respuestas:
Si tiene GNU
date
, permite imprimir la representación de una fecha arbitraria (-d
opción). En este caso, convierta las fechas a segundos desde EPOCH, reste y divida por 24 * 3600.¿O necesitas una forma portátil?
fuente
echo "( `date -d $B +%s` - `date -d $A +%s`) / (24*3600)" | bc -l
El método bash: convierta las fechas en el formato% y% m% d y luego puede hacerlo directamente desde la línea de comando:
echo $(( ($(date --date="031122" +%s) - $(date --date="021020" +%s) )/(60*60*24) ))
fuente
%y%m%d
formato. Por ejemplo, gnu date aceptará el%Y-%m-%d
formato que utilizó el OP. En general, ISO-8601 es una buena opción (y el formato de OP es uno de esos formatos). Es mejor evitar los formatos con años de 2 dígitos.days_diff=$(( (`date -d $B +%s` - `date -d "00:00" +%s`) / (24*3600) ))
. tenga en cuenta que$days_diff
será un número entero (es decir, sin decimales)date
instalado. Funciona para GNUdate
. No funciona con POSIXdate
. Probablemente esto no sea un problema para la mayoría de los lectores, pero vale la pena señalarlo.%Y-%m-%d
, hasta que lo presentamosAugust 2.0
yOctober 2.0
el formato de OP es%Y-%d-%m
. Relevante xkcd: xkcd.com/1179tl; dr
date_diff=$(( ($(date -d "2015-03-11 UTC" +%s) - $(date -d "2015-03-05 UTC" +%s)) / (60*60*24) ))
¡Cuidado! Muchas de las soluciones bash aquí están divididas para rangos de fechas que abarcan la fecha en que comienza el horario de verano (cuando corresponda). Esto se debe a que la construcción $ ((matemáticas)) realiza una operación de 'piso' / truncamiento en el valor resultante, devolviendo solo el número entero. Déjame ilustrarte:
El horario de verano comenzó el 8 de marzo de este año en los EE. UU., Así que usemos un rango de fechas que abarque eso:
start_ts=$(date -d "2015-03-05" '+%s') end_ts=$(date -d "2015-03-11" '+%s')
Veamos qué obtenemos con el doble paréntesis:
echo $(( ( end_ts - start_ts )/(60*60*24) ))
Devuelve '5'.
Hacer esto usando 'bc' con más precisión nos da un resultado diferente:
echo "scale=2; ( $end_ts - $start_ts )/(60*60*24)" | bc
Devuelve '5,95'; el 0,05 que falta es la hora perdida del cambio de horario de verano.
Entonces, ¿cómo se debe hacer esto correctamente?
Sugeriría usar esto en su lugar:
printf "%.0f" $(echo "scale=2; ( $end_ts - $start_ts )/(60*60*24)" | bc)
Aquí, 'printf' redondea el resultado más preciso calculado por 'bc', lo que nos da el rango de fechas correcto de '6'.
Editar: resaltando la respuesta en un comentario de @ hank-schultz a continuación, que he estado usando últimamente:
date_diff=$(( ($(date -d "2015-03-11 UTC" +%s) - $(date -d "2015-03-05 UTC" +%s) )/(60*60*24) ))
Esto también debería ser un segundo intercalar seguro siempre que reste siempre la fecha anterior de la última, ya que los segundos intercalares solo aumentarán la diferencia: el truncamiento se redondea efectivamente al resultado correcto.
fuente
echo $(( ($(date --date="2015-03-11 UTC" +%s) - $(date --date="2015-03-05 UTC" +%s) )/(60*60*24) ))
que devuelve 6, en lugar de 5.Y en pitón
$python -c "from datetime import date; print (date(2003,11,22)-date(2002,10,20)).days" 398
fuente
bash
yshell
, así que creo que podemos asumir que estamos hablando de un sistema * nix. Dentro de tales sistemas,echo
ydate
están presentes de manera confiable, pero Python no lo está.Esto funciona para mi:
A="2002-10-20" B="2003-11-22" echo $(( ($(date -d $B +%s) - $(date -d $A +%s)) / 86400 )) days
Huellas dactilares
¿Qué está pasando?
date -d
para manejar cadenas de tiempodate %s
para convertir cadenas de tiempo a segundos desde 1970 (unix epoche)fuente
Si la opción -d funciona en su sistema, aquí hay otra forma de hacerlo. Hay una advertencia de que no daría cuenta de los años bisiestos, ya que he considerado 365 días al año.
date1yrs=`date -d "20100209" +%Y` date1days=`date -d "20100209" +%j` date2yrs=`date +%Y` date2days=`date +%j` diffyr=`expr $date2yrs - $date1yrs` diffyr2days=`expr $diffyr \* 365` diffdays=`expr $date2days - $date1days` echo `expr $diffyr2days + $diffdays`
fuente
Aquí está la versión de MAC OS X para su conveniencia.
$ A="2002-20-10"; B="2003-22-11"; $ echo $(((`date -jf %Y-%d-%m $B +%s` - `date -jf %Y-%d-%m $A +%s`)/86400))
nJoy!
fuente
A="2002-20-10"; B="2003-22-11"
echo $(((`date -jf "%Y-%d-%m" "$B" +%s` - `date -jf "%Y-%d-%m" "$A" +%s`)/86400))
, es decir, envolver ambos formatos y variables en comillas dobles, de lo contrario puede fallar en diferente formato de fecha (por ejemplo,%b %d, %Y
/Jul 5, 2017
)Incluso si no tiene la fecha de GNU, probablemente tenga Perl instalado:
use Time::Local; sub to_epoch { my ($t) = @_; my ($y, $d, $m) = ($t =~ /(\d{4})-(\d{2})-(\d{2})/); return timelocal(0, 0, 0, $d+0, $m-1, $y-1900); } sub diff_days { my ($t1, $t2) = @_; return (abs(to_epoch($t2) - to_epoch($t1))) / 86400; } print diff_days("2002-20-10", "2003-22-11"), "\n";
Esto regresa
398.041666666667
: 398 días y una hora debido al horario de verano.La pregunta volvió a aparecer en mi feed. Aquí hay un método más conciso usando un módulo incluido de Perl
days=$(perl -MDateTime -le ' sub parse_date { @f = split /-/, shift; return DateTime->new(year=>$f[0], month=>$f[2], day=>$f[1]); } print parse_date(shift)->delta_days(parse_date(shift))->in_units("days"); ' $A $B) echo $days # => 398
fuente
Este es el más simple que logré trabajar en centos 7:
OLDDATE="2018-12-31" TODAY=$(date -d $(date +%Y-%m-%d) '+%s') LINUXDATE=$(date -d "$OLDDATE" '+%s') DIFFDAYS=$(( ($TODAY - $LINUXDATE) / (60*60*24) )) echo $DIFFDAYS
fuente
Aquí está mi enfoque de trabajo usando zsh. Probado en OSX:
# Calculation dates ## A random old date START_DATE="2015-11-15" ## Today's date TODAY=$(date +%Y-%m-%d) # Import zsh date mod zmodload zsh/datetime # Calculate number of days DIFF=$(( ( $(strftime -r %Y-%m-%d $TODAY) - $(strftime -r %Y-%m-%d $START_DATE) ) / 86400 )) echo "Your value: " $DIFF
Resultado:
Básicamente, usamos
strftime
la-r
función reverse ( ) para transformar nuestra cadena de fecha nuevamente en una marca de tiempo, luego hacemos nuestro cálculo.fuente
Presentaría otra posible solución en Ruby. Parece que es el más pequeño y el más limpio hasta ahora:
A=2003-12-11 B=2002-10-10 DIFF=$(ruby -rdate -e "puts Date.parse('$A') - Date.parse('$B')") echo $DIFF
fuente
date
o algún lenguaje de programación) y honestamente creo que Ruby es una buena forma de hacerlo. Esta solución es muy corta y no utiliza bibliotecas no estándar ni otras dependencias. De hecho, creo que hay más posibilidades de tener Ruby instalado que de tener GNU date instalado.Otra versión de Python:
python -c "from datetime import date; print date(2003, 11, 22).toordinal() - date(2002, 10, 20).toordinal()"
fuente
Utilice las funciones de shell de http://cfajohnson.com/shell/ssr/ssr-scripts.tar.gz ; funcionan en cualquier shell estándar de Unix.
date1=2012-09-22 date2=2013-01-31 . date-funcs-sh _date2julian "$date1" jd1=$_DATE2JULIAN _date2julian "$date2" echo $(( _DATE2JULIAN - jd1 ))
Consulte la documentación en http://cfajohnson.com/shell/ssr/08-The-Dating-Game.shtml
fuente
Usando el comando mysql
$ echo "select datediff('2013-06-20 18:12:54+08:00', '2013-05-30 18:12:54+08:00');" | mysql -N
Resultado: 21
NOTA: Solo las partes de la fecha de los valores se utilizan en el cálculo
Referencia: http://dev.mysql.com/doc/refman/5.6/en/date-and-time-functions.html#function_datediff
fuente
en Unix debería tener instaladas las fechas GNU. no es necesario que se desvíe de bash. aquí está la solución encadenada considerando días, solo para mostrar los pasos. se puede simplificar y ampliar a fechas completas.
DATE=$(echo `date`) DATENOW=$(echo `date -d "$DATE" +%j`) DATECOMING=$(echo `date -d "20131220" +%j`) THEDAY=$(echo `expr $DATECOMING - $DATENOW`) echo $THEDAY
fuente
Esto supone que un mes es 1/12 de un año:
#!/usr/bin/awk -f function mktm(datespec) { split(datespec, q, "-") return q[1] * 365.25 + q[3] * 365.25 / 12 + q[2] } BEGIN { printf "%d\n", mktm(ARGV[2]) - mktm(ARGV[1]) }
fuente
Prueba esto:
perl -e 'use Date::Calc qw(Delta_Days); printf "%d\n", Delta_Days(2002,10,20,2003,11,22);'
fuente
Supongamos que sincronizamos manualmente las copias de seguridad de la base de datos de Oracle en un disco terciario. Entonces queremos eliminar las copias de seguridad antiguas en ese disco. Así que aquí hay un pequeño script de bash:
#!/bin/sh for backup_dir in {'/backup/cmsprd/local/backupset','/backup/cmsprd/local/autobackup','/backup/cfprd/backupset','/backup/cfprd/autobackup'} do for f in `find $backup_dir -type d -regex '.*_.*_.*' -printf "%f\n"` do f2=`echo $f | sed -e 's/_//g'` days=$(((`date "+%s"` - `date -d "${f2}" "+%s"`)/86400)) if [ $days -gt 30 ]; then rm -rf $backup_dir/$f fi done done
Modifique los directorios y el período de retención ("30 días") para adaptarlos a sus necesidades.
fuente
Para MacOS sierra (tal vez de Mac OS X yosemate),
Para obtener el tiempo de época (segundos desde 1970) de un archivo y guardarlo en una var:
old_dt=`date -j -r YOUR_FILE "+%s"`
Para obtener el tiempo de época del tiempo actual
new_dt=`date -j "+%s"`
Para calcular la diferencia del tiempo de dos épocas anteriores
(( diff = new_dt - old_dt ))
Para comprobar si la diferencia es superior a 23 días
(( new_dt - old_dt > (23*86400) )) && echo Is more than 23 days
fuente
echo $(date +%d/%h/%y) date_today echo " The other date is 1970/01/01" TODAY_DATE="1970-01-01" BEFORE_DATE=$(date +%d%h%y) echo "THE DIFFERNS IS " $(( ($(date -d $BEFORE_DATE +%s) - $(date -d $TODAY_DATE +%s)) )) SECOUND
Úselo para obtener su fecha de hoy y su segundo desde la fecha que desea. si lo quieres con días solo divídelo con 86400
echo $(date +%d/%h/%y) date_today echo " The other date is 1970/01/01" TODAY_DATE="1970-01-01" BEFORE_DATE=$(date +%d%h%y) echo "THE DIFFERNS IS " $(( ($(date -d $BEFORE_DATE +%s) - $(date -d $TODAY_DATE +%s))/ 86400)) SECOUND
fuente