2010-08-17 3 views
12

Comment est-ce que je bidouille ceci pour obtenir la date d'hier en utilisant localtime?Comment obtenir la date d'hier en utilisant localtime?

use strict; 

sub spGetCurrentDateTime; 
print spGetCurrentDateTime; 

sub spGetCurrentDateTime { 
my ($sec, $min, $hour, $mday, $mon, $year) = localtime(); 
my @abbr = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec); 
my $currentDateTime = sprintf "%s %02d %4d", $abbr[$mon], $mday, $year+1900; #Returns => 'Aug 17 2010' 
return $currentDateTime; 
} 

~

Répondre

11

Le problème DST peut être contourné en prenant 3600s à partir de midi aujourd'hui au lieu de l'heure actuelle:

#!/usr/bin/perl 
use strict; 
use warnings; 
use Time::Local; 

sub spGetYesterdaysDate; 
print spGetYesterdaysDate; 

sub spGetYesterdaysDate { 
my ($sec, $min, $hour, $mday, $mon, $year) = localtime(); 
my $yesterday_midday=timelocal(0,0,12,$mday,$mon,$year) - 24*60*60; 
($sec, $min, $hour, $mday, $mon, $year) = localtime($yesterday_midday); 
my @abbr = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec); 
my $YesterdaysDate = sprintf "%s %02d %4d", $abbr[$mon], $mday, $year+1900; 
return $YesterdaysDate; 
} 

À la lumière de la « non spécifié » comportement documenté de la solution strftime proposée par Chas, cette approche pourrait être meilleure si vous n'êtes pas en mesure de tester les résultats attendus mais non garantis sur plusieurs plates-formes.

+0

merci. Cela fonctionne bien avec ma routine existante. – jdamae

1
localtime(time() - 24*60*60) 
+5

Il y a un cas de bordure autour de l'heure d'été. Je ne conseille pas cette méthode si vous avez besoin que cela fonctionne tout le temps. –

+3

Downvote comme ci-dessus. Ce n'est pas une bonne réponse. – daxim

+0

Le cas de bordure DST peut être "travaillé", voir l'exemple de code dans une autre réponse. – bigiain

6

utilisation Time::Piece.

use strict; 
use warnings; 
use 5.010; 

# These are core modules in Perl 5.10 and newer 
use Time::Piece; 
use Time::Seconds; 

my $yesterday = localtime() - ONE_DAY; 
say $yesterday->strftime('%b %d %Y'); 

Notez que cela peut mal tourner dans certains cas limites, tels que le début de l'heure d'été. La version suivante ne se comporte correctement dans de tels cas:

use strict; 
use warnings; 
use 5.010; 

# These are core modules in Perl 5.10 and newer 
use Time::Piece; 
use Time::Seconds; 

my $now = localtime(); 
my $yesterday = $now - ONE_HOUR*($now->hour + 12); 
say $yesterday->strftime('%b %d %Y'); 

Alternativement, vous pouvez utiliser le module DateTime comme décrit dans une réponse différente. Ce n'est pas un module de base, cependant.

+0

Le même problème DST se cache sous l'API fantaisie. – daxim

+0

Bon point, daxim. J'ai ajouté une version qui n'a pas ce problème. – mscha

+2

'Time :: Piece' et' Time :: Seconds' n'ont pas été ajoutés au noyau jusqu'à Perl 5.10 (bien 5.9.5, mais qui utilise les versions de développement?). –

20
use DateTime qw(); 
DateTime->now->subtract(days => 1); 

L'expression de la deuxième ligne renvoie un objet DateTime.

+0

Il ne fonctionne pas correctement pour le fuseau horaire Asia/Kolkata. – user774250

+1

Ça marche, je viens de tester. Peut-être avez-vous simplement oublié de définir l'attribut 'time_zone' dans le constructeur, ou négligé d'appeler la méthode [' set_time_zone'] (http://p3rl.org/DateTime#dt-set_time_zone-tz-)? Peut-être avez-vous une version obsolète de la distribution ['DateTime :: TimeZone'] (https://metacpan.org/release/DateTime-TimeZone)? – daxim

18

Aussi tentant que de soustraire une journée de secondes de l'heure actuelle, il y a des moments où cela donnera la mauvaise réponse (secondes intercalaires, DST, et éventuellement d'autres). Je trouve plus facile de laisser simplement strftime (disponible dans le module de base Perl 5 POSIX) prendre soin de tout cela pour moi.

#!/usr/bin/perl 

use strict; 
use warnings; 

use Time::Local; 
use POSIX qw/strftime/; 

#2010-03-15 02:00:00 
my ($s, $min, $h, $d, $m, $y) = (0, 0, 0, 15, 2, 110); 

my $time  = timelocal $s, $min, $h, $d, $m, $y;  
my $today  = strftime "%Y-%m-%d %T", localtime $time; 
my $yesterday = strftime "%Y-%m-%d %T", $s, $min, $h, $d - 1, $m, $y; 
my $oops  = strftime "%Y-%m-%d %T", localtime $time - 24*60*60; 
print "$today -> $yesterday -> $oops\n"; 
+0

Ainsi, si la valeur 'day' est inférieure à 1, 'strftime' compte en arrière jour + 1 jours dans le mois précédent (et éventuellement l'année). Ce comportement est-il une partie documentée de POSIX ou est-il spécifique à la plate-forme? –

+1

@Grant Mclean Il peut ne pas être standard dans POSIX (ou SUS), mais il est standard dans Perl 5. La documentation dit que les arguments sont rendus cohérents comme si en appelant "mktime()" avant d'appeler "strftime()" '. –

+1

En tant que ligne simple: 'perl -MPOSIX -le '@ t = heure locale; - $ t [3]; imprime strftime"% Y% m% d ", @ t'' – theglauber

4

La solution proposée par la plupart des utilisateurs est incorrecte!

localtime(time() - 24*60*60) 

Le pire chose que vous pouvez faire est de supposer que 1 jour = 86400 secondes.

Exemple: fuseauHoraire Amérique/New_York, la date est Mon Apr 3 00:30:00 2006

timelocal nous donne

localtime (1144038600-86400) = Sat avril 1 23:30:00 EST 2006

oups!

Le droit et la seule solution est de laisser normaliser le fonctionnement du système des valeurs

$prev_day = timelocal(0, 0, 0, $mday-1, $mon, $year); 

Ou laisser les cadres datetime (DateTime, Class::Date, etc) font la même chose.

C'est tout.

-1
This is how I do it. 

#!/usr/bin/perl 

use POSIX qw(strftime); 

$epoc = time(); 
$epoc = $epoc - 24 * 60 * 60; 

$datestring = strftime "%F", localtime($epoc); 

print "Yesterday's date is $datestring \n"; 
+0

Cela peut échouer vers le début de l'heure d'été pour des raisons expliquées dans d'autres réponses. –

Questions connexes