2010-05-26 46 views
6

Tengo el siguiente ciclo para calcular las fechas de la semana actual e imprimirlas. Funciona, pero estoy nadando en la cantidad de posibilidades de fecha/hora en Perl y quiero obtener tu opinión sobre si hay una mejor manera. Aquí está el código que he escrito:¿Cómo puedo obtener las fechas de esta semana en Perl?

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

use DateTime; 

# Calculate numeric value of today and the 
# target day (Monday = 1, Sunday = 7); the 
# target, in this case, is Monday, since that's 
# when I want the week to start 
my $today_dt = DateTime->now; 
my $today = $today_dt->day_of_week; 
my $target = 1; 

# Create DateTime copies to act as the "bookends" 
# for the date range 
my ($start, $end) = ($today_dt->clone(), $today_dt->clone()); 

if ($today == $target) 
{ 
    # If today is the target, "start" is already set; 
    # we simply need to set the end date 
    $end->add(days => 6); 
} 
else 
{ 
    # Otherwise, we calculate the Monday preceeding today 
    # and the Sunday following today 
    my $delta = ($target - $today + 7) % 7; 
    $start->add(days => $delta - 7); 
    $end->add(days => $delta - 1); 
} 

# I clone the DateTime object again because, for some reason, 
# I'm wary of using $start directly... 
my $cur_date = $start->clone(); 

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

Como se mencionó, esto funciona, pero ¿es el más rápido o más eficiente? Supongo que la rapidez y la eficiencia no necesariamente van de la mano, pero sus comentarios son muy apreciados.

Respuesta

14

Una versión ligeramente mejorada de la respuesta de Friedo ...

my $start_of_week = 
    DateTime->today() 
      ->truncate(to => 'week'); 

for (0..6) { 
    print $start_of_week->clone()->add(days => $_); 
} 

Sin embargo, esto supone que el lunes es el primer día de la semana. Para el domingo, comenzar con ...

my $start_of_week = 
    DateTime->today() 
      ->truncate(to => 'week') 
      ->subtract(days => 1); 

De cualquier manera, es mejor usar el método truncate de volver a ponerlo en práctica, como lo hizo Friedo;)

+0

Gracias por el código actualizado. – ABach

+0

Una pregunta rápida: ¿eso para loop crea un nuevo clon DateTime en cada iteración? ¿Eso está bien que hacer en Perl? – ABach

+0

Tenga en cuenta que la versión del domingo no funciona correctamente. Necesita '-> agregar (días => 1)' antes de '-> truncar', o comenzar con Domingo le dará el inicio de la semana anterior. – cjm

4

Puede usar el objeto DateTime para obtener el día actual de la semana como un número (1-7). Entonces solo usa eso para encontrar el lunes de la semana actual. Por ejemplo:

my $today = DateTime->now; 
my $start = $today->clone; 

# move $start to Monday 
$start->subtract(days => ($today->wday - 1)); # Monday gives 1, so on monday we 
                # subtract zero. 

my $end = $start->clone->add(days => 7); 

Lo anterior no se ha probado pero la idea debería funcionar.

+0

Guau, eso es mucho más simple. ¡Gracias! – ABach

1

Esto debería funcionar:

use POSIX; # for strftime 
my $time = time(); 
my $seconds = 24*60*60; 
my @time = gmtime(); 
$time = $time - $time[6] * $seconds; 
for my $wday (0..6) { 
    $time += $seconds; 
    my @wday = gmtime ($time); 
    print strftime ("%A %d %B %Y\n", @wday); 
} 

me da:

 
$ ./week.pl 
Monday 24 May 2010 
Tuesday 25 May 2010 
Wednesday 26 May 2010 
Thursday 27 May 2010 
Friday 28 May 2010 
Saturday 29 May 2010 
Sunday 30 May 2010 

Si desea obtener semana que comienza el domingo, cambiar $time[6] a ($time[6] + 1).

Esto supone que desea las semanas GMT. Cambie gmtime a localtime para obtener las semanas locales de la zona horaria.

+1

Si solo está usando POSIX para strftime (que de hecho es un buen motivo para usarlo), entonces sería mejor decir: use POSIX qw (strftime); Además,% F muestra el formato AAAA-MM-DD que fue el póster original. –

+0

Gracias.Hay muchas otras liendres para elegir en ese código (¿qué hace '$ wday'?), Pero básicamente quería ofrecer un ejemplo de hacerlo sin' DateTime', que no es necesario para esta tarea. –

2

Que este trabajo:

use strict; 
use warnings; 
use POSIX qw<strftime>; 
my ($day, $pmon, $pyear, $wday) = (localtime)[3..6]; 
$day -= $wday - 1; # Get monday 
for my $d (map { $day + $_ } 0..6) { 
    print strftime('%A, %B %d, %Y', (0) x 3, $d, $pmon, $pyear), "\n"; 
} 

los estoy imprimiendo sólo como ilustración. Puede almacenarlos como marcas de tiempo, como esta:

use POSIX qw<mktime>; 
my @week = map { mktime((0) x 3, $day + $_, $pmon, $pyear) } 0..6; 
+0

tienes razón. Lo siento. –

+0

@Snake Plissken: No hay problema Buen nombre. :) – Axeman

+0

Gracias Axeman, su código está trabajando en perl v5.8.8 sin el módulo DateTime instalado. Esto es genial. No puedo instalar ningún módulo en mi servidor de prod. – Gary

Cuestiones relacionadas