2011-07-08 15 views
14

Me preguntaba, en Perl, ¿cuál es la forma más óptima/más clara de recorrer dos fechas? Hay muchos módulos en CPAN que se ocupan de esto, pero ¿hay alguna regla práctica para iterar entre dos fechas?¿Cuál es la forma óptima de bucle entre dos fechas en Perl?

Gracias,

+1

¿Qué quiere decir "loop between dates"? – Flimzy

+0

Iteratos pueden ser más adequat. Tengo la fecha A que es t y la fecha B que es t + x días, me gustaría pasar de la fecha A a la fecha B y hacer algo para cada día entre los dos. – Spredzy

+1

posible duplicado de [¿Cómo iterar por el rango de fechas?] (Http://stackoverflow.com/questions/3493880/how-to-iterate-through-range-of-dates) – daxim

Respuesta

28

Para todo lo que utiliza la manipulación de fecha DateTime es probablemente el mejor módulo disponible. Para obtener todas las fechas entre dos fechas con su propio uso de la subasta o menos así:

#!/usr/bin/env perl 
use strict; 
use warnings; 
use DateTime; 

my $start = DateTime->new(
    day => 1, 
    month => 1, 
    year => 2000, 
); 

my $stop = DateTime->new(
    day => 10, 
    month => 1, 
    year => 2000, 
); 


while ($start->add(days => 1) < $stop) { 
    printf "Date: %s\n", $start->ymd('-'); 
} 

Esta es la salida:

Date: 2000-01-02 
Date: 2000-01-03 
Date: 2000-01-04 
Date: 2000-01-05 
Date: 2000-01-06 
Date: 2000-01-07 
Date: 2000-01-08 
Date: 2000-01-09 
+2

eso es un poco confuso, ya que comienza el día después de '$ start' – ysth

+0

La mejor parte de esta solución: si necesito recorrer horas, minutos, segundos, meses o años, ahora sé exactamente qué hacer. – HoldOffHunger

1

creo que la "mejor" manera de hacer eso depende mucho de lo que que está haciendo entre estos dos días.

En muchos casos, un simple bucle for (0..31) será suficiente.

En otros casos, es posible que desee utilizar un valor de época y sumar/restar 86400 segundos en cada iteración.

En una aplicación que he escrito, hago exactamente esto, usando un objeto DateTime que agrego un día para cada iteración. Sin embargo, esto es demasiado para muchas aplicaciones.

+1

El enfoque con la adición de segundos a la época por lo general falla con horario de verano (horario de verano). Lo hice una vez en mi aplicación y obtuve errores extraños medio año después. – bvr

+0

Afortunadamente, todas las manipulaciones de la fecha están en UTC, donde el horario de verano no se aplica. :) Cientos programadores lo hacen de esta manera ... jeje Pero aun así, nunca dije que esta fuera una solución para cada caso. – Flimzy

+1

En su aplicación, es probable que desee mostrar la hora local. Si haces los cálculos en UTC y conviertes a la hora local, es posible que tu código se rompa. Por ejemplo, agregar 1 hora y 1 minuto a la hora UTC 27.3.2011 01:00:00 y convertirlo a "Europa/Berlín" dará como resultado un error, porque la fecha no es válida. Si establece time_zone antes de hacer los cálculos, su código funciona correctamente y devuelve la misma fecha con la hora 03:01:00. –

5

En estos días, la mayoría de la gente recomendaría el uso de DateTime:

use DateTime; 

my $start = DateTime->new(...); # create two DateTime objects 
my $end = DateTime->new(...); 

while ($start <= $end) { 
    print $start->ymd, "\n"; 
    $start->add(days => 1); 
} 
1

Ofrezco una solución de Time::Piece, porque - a diferencia de DateTime es un módulo de núcleo (a partir de perl 5.9.5):

#!/usr/bin/env perl 

use strict; 
use warnings; 
use Time::Piece; 
use Time::Seconds; 

my $FORMAT = '%Y-%m-%d'; 

my $start = '2016-01-22'; 
my $end = '2016-03-11'; 


my $start_t = Time::Piece->strptime($start, $FORMAT); 
my $end_t = Time::Piece->strptime($end, $FORMAT); 

while ($start_t <= $end_t) { 
    print $start_t ->strftime($FORMAT), "\n"; 
    $start_t += ONE_DAY; 
} 

Tanto Time::Piece y Time::Seconds son núcleo como de Perl 5.9.5. Este último solo es necesario para ONE_DAY; de lo contrario, solo puede agregar 60 * 60 * 24.

Esto tiene la ventaja de poder analizar formatos de fecha bastante arbitrarios.

Cuestiones relacionadas