2011-06-07 15 views

Respuesta

24

Supongo que si la fecha dada es un lunes, quiere la misma fecha (y no el lunes anterior). He aquí una manera de hacerlo con DateTime:

use DateTime; 

my $date = DateTime->new(year => 2011, month => 6, day => 11); 
my $desired_dow = 1;   # Monday 
$date->subtract(days => ($date->day_of_week - $desired_dow) % 7); 
print "$date\n"; 

(En realidad, para el caso especial de los lunes, el % 7 no es necesario, porque siempre habrá 6, y que mod 7 es un no- Op. Pero con la % 7, funciona para cualquier deseada día de la semana, no sólo lunes)

Si quieres el lunes anterior, puede cambiar la resta:.

$date->subtract(days => ($date->day_of_week - $desired_dow) % 7 || 7); 

Si necesita analizar una fecha ingresada en la línea de comando, es posible que desee consultar DateTime::Format::Natural.

+2

Hay muchas maneras de hacerlo y muchos módulos de fecha/hora en CPAN, pero DateTime es, de lejos, el mejor módulo para hacer cualquier cosa con fechas y horas. –

1

Zeller's congruence le dará el día de la semana. A partir de ahí, debería ser bastante fácil.

+1

Esa es una publicación de noticias de un poste de noticias. Enlace alternativo a la publicación original, mejor legible: [''] (http://groups.google.com/group/comp.lang.perl/msg/dbd4d19f71ec6b9a) – daxim

+2

@daxim, sin mencionar totalmente innecesario en Perl 5. '(localtime) [6]' es el día de la semana. – Axeman

12

También podría usar Time :: ParseDate, que comprende "el último lunes".

Una sola línea para mantener la reputación de Perl:

perl -MTime::ParseDate -M'POSIX qw(strftime)' -l -e'foreach (@ARGV) { my $now= parsedate($_); my $e= parsedate("last Monday", NOW => $now) ; print "$_ : ", strftime "%F", localtime($e)}' 2011-06-11 2011-06-12 2011-06-13 2011-06-14 

y un guión cuerdo:

#!/usr/bin/perl 

use strict; 
use warnings; 

use Time::ParseDate; # to parse dates 
use POSIX qw(strftime); # to format dates 

foreach my $date (@ARGV) 
    { my $date_epoch= parsedate($date) || die"'cannot parse date '$date'\n"; 
    my $monday= parsedate("last Monday", NOW => $date_epoch);     # last Monday before NOW 
    print "Monday before $date: ", strftime("%F", localtime($monday)), "\n"; # %F is YYYY-MM-DD 
    } 

Un par de notas: si la fecha es un lunes, a continuación, se obtiene el anterior Lunes, que puede o no ser lo que desee, para cambiar el que acaba de establecer AHORA al día siguiente (agregue 60 * 60 * 24, un día, a $ date_epoch). Entonces Time :: ParseDate es bastante liberal, se analizará felizmente 2011-23-38 por ejemplo (como 2012-12-09).

+1

Mientras 'DateTime' es una manera canónica de trabajar con fechas y horas en Perl,' Time :: ParseDate' siempre ha sido mi favorito para este tipo de cosas. – Grrrr

+1

En realidad, rara vez tengo que trabajar con fechas, que tal vez por qué me parece parsedate ("último lunes", NOW => $ date_epoch); lindo y, más importante, fácil de recordar. – mirod

3

Bastante simple usando la biblioteca estándar de Perl.

#!/usr/bin/perl 

use strict; 
use warnings; 
use 5.010; 

use Time::Local; 
use POSIX 'strftime'; 

my $date = shift || die "No date given\n"; 

my @date = split /-/, $date; 
$date[0] -= 1900; 
$date[1]--; 

die "Invalid date: $date\n" unless @date == 3; 

my $now = timelocal(0, 0, 12, reverse @date); 

while (strftime('%u', localtime $now) != 1) { 
    $now -= 24 * 60 * 60; 
} 

Lo dejo como un ejercicio para que el lector busque los diferentes módulos y funciones utilizados.

Probablemente sea aún más simple si usa DateTime.

3

En el espíritu de Perl, hay más de una forma de hacerlo.

use Modern::Perl; 
use Date::Calc qw/Day_of_Week/; 
my $date = '2011/6/11'; 
my @fields = split /\//, $date; 
my @new_date = Add_Delta_Days(@fields , 1 - Day_of_Week(@fields)); 
say join "/", @new_date; 
2

Usted podría utilizar Date::Manip, que tiene una función Date_GetPrev y entiende "Lunes"

$ perl -MDate::Manip -le 'print UnixDate(Date_GetPrev(shift, "Monday", 0), "%Y-%m-%d")' 2011-06-11 
2011-06-06 
1

Al final de esto, $tstamp tendría la marca de tiempo que desee:

use strict; 
use warnings; 
use POSIX qw<mktime>; 

my $time = '2011-06-11'; 

my ($year, $month, $day) = split /-0?/, $time; 
my $tstamp = mktime(0, 0, 0, $day, $month - 1, $year - 1900); 
my $dow = (localtime $tstamp)[6]; 
$tstamp -= (($dow > 1 ? 0 : 7) + $dow - 1) * 24 * 60 * 60; 

Esto supone que por "último lunes" se refiere al último lunes de ocurrencia anterior al del día determinado."Entonces, si el día de la semana es lunes (1), resta 7 puntos adicionales.

+0

Usted está fuera por una prueba de dow, 2011-06-07 (martes) devolverá la marca de tiempo para 2011-05-30. –

+0

@ Ven'Tatsu Ah, me engañé a mí mismo. Probé, publiqué y luego leí el error comparativo y lo cambié apresuradamente a un 2. – Axeman

0

Si es un esclavo como yo y tiene que usar un Perl corporativo sin bibliotecas y no tiene permitido instalarlo tampoco , antigua usanza:

my $datestring = ""; 
my $secondsEpoc = time(); #gives the seconds from system epoch 
my $secondsWantedDate; 
my $seconds2substract; 

$datestring = localtime($secondsEpoc); 
print "Today's date and time ".$datestring."\n"; 
my ($second,$minute,$hour,$d,$M,$y,$wd,$yd) = (localtime)[0,1,2,3,4,5,6,7]; 
#print "hour: ".$hour; 
#print "minute: ".$minute; 
#print "second: ".$second; 
#print "week day: ".$wd; #week day is 1=Monday .. 7=Sunday 

$seconds2substract = 24 * 60 * 60; # seconds in 24 hours 
$secondsWantedDate=$secondsEpoc-$seconds2substract; 
$datestring = localtime($secondsWantedDate); 
print "Yesterday at the same time ".$datestring."\n"; 


my $days2Substract = $wd-1; 
$seconds2substract = ($days2Substract * 24 * 60 * 60); 
$secondsWantedDate=$secondsEpoc-$seconds2substract; 
$datestring = localtime($secondsWantedDate); 
print "Past Monday same time ".$datestring."\n"; 

$seconds2substract = ($days2Substract * 24 * 60 * 60) + ($hour *60 *60) + ($minute * 60) + $second; 
$secondsWantedDate = $secondsEpoc-$seconds2substract; 
$datestring = localtime($secondsWantedDate); 
print "Past Monday at 00:00:00 ".$datestring."\n"; 

espero que ayude a alguien

+0

Esto no soluciona el segundo intercalado, http://en.wikipedia.org/wiki/Leap_second – Toto

+0

Tienes razón, pero sirve para muchos propósitos donde el segundo intercalar no es importante: créanme, no se les ha permitido agregar bibliotecas es un infierno, puede hacer que su código crezca en líneas ridículamente, y lo único que importa es encontrar una solución rápida que sea lo suficientemente buena para el tarea requerida :) – Cristina

0

Hay muchas maneras de hacerlo en Perl así es como se puede hacer con la biblioteca Perl Moment

#!/usr/bin/perl 

use strict; 
use warnings FATAL => 'all'; 
use feature 'say'; 

use Moment; 

sub get_monday_date { 
    my ($date) = @_; 

    my $moment = Moment->new(dt => "$date 00:00:00"); 

    my $weekday_number = $moment->get_weekday_number(first_day => 'monday'); 

    my $monday = $moment->minus(day => ($weekday_number - 1)); 

    return $monday->get_d(); 
} 

say get_monday_date('2011-06-11'); # 2011-06-06 
Cuestiones relacionadas