Snel naar JJJJ-mm-dd HH:MM:SS in Perl

Bij het schrijven van Perl-scripts heb ik vaak de behoefte om de huidige tijd te verkrijgen, weergegeven als een tekenreeks die is opgemaakt als YYYY-mm-dd HH:MM:SS(zeg 2009-11-29 14:28:29).

Als ik dit doe, betrap ik mezelf op dit nogal omslachtige pad:

  • man perlfunc
  • /localtimeom naar localtime te zoeken – herhaal vijf keer (/+ \n) om het relevante gedeelte van de manpage te bereiken
  • Kopieer de string ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);van de manpage naar mijn script.
  • Probeer met my $now = sprintf("%04d-%02d-%02d %02d:%02d:%02d", $year, $mon, $mday, $hour, $min, $sec);
  • Onthoud gotcha #1: je moet 1900 optellen bij $year om het huidige jaar te krijgen.
  • Probeer met my $now = sprintf("%04d-%02d-%02d %02d:%02d:%02d", $year+1900, $mon, $mday, $hour, $min, $sec);
  • Onthoud gotcha #2: moet 1 optellen bij $mon om de huidige maand te krijgen.
  • Probeer met my $now = sprintf("%04d-%02d-%02d %02d:%02d:%02d", $year+1900, $mon+1, $mday, $hour, $min, $sec);
  • Lijkt oké. Klaar!

Hoewel het hierboven beschreven proces werkt, is het verre van optimaal. Ik weet zeker dat er een slimmere manier is, dus mijn vraag is eenvoudig:

Wat is de gemakkelijkste manier om een ​​YYYY-mm-dd HH:MM:SSvan de huidige datum/tijd in Perl te verkrijgen?

Waarbij “gemakkelijk” zowel “gemakkelijk te schrijven” als “gemakkelijk te onthouden” omvat.


Antwoord 1, autoriteit 100%

Gebruik strftimein de standaard POSIX-module. De argumenten voor strftimein de binding van Perl zijn ontworpen om overeen te komen met de retourwaarden van localtimeen gmtime. Vergelijk

strftime(fmt, sec, min, hour, mday, mon, year, wday = -1, yday = -1, isdst = -1)

met

my          ($sec,$min,$hour,$mday,$mon,$year,$wday,     $yday,     $isdst) = gmtime(time);

Voorbeeld van gebruik via de opdrachtregel is

$ perl -MPOSIX -le 'print strftime "%F %T", localtime $^T'

of uit een bronbestand zoals in

use POSIX;
print strftime "%F %T", localtime time;

Sommige systemen ondersteunen de afkortingen %Fen %Tniet, dus u zult expliciet moeten zijn met

print strftime "%Y-%m-%d %H:%M:%S", localtime time;

of

print strftime "%Y-%m-%d %H:%M:%S", gmtime time;

Merk op dat timede huidige tijd retourneert wanneer deze wordt aangeroepen terwijl $^Tis vastgesteld op het tijdstip waarop uw programma gestart. Bij gmtimeis de retourwaarde de huidige tijd in GMT . Haal de tijd op in uw lokale tijdzone met localtime.


Antwoord 2, autoriteit 43%

Waarom zou u de module DateTimeniet gebruiken om het vuile werk voor u te doen? Het is gemakkelijk om ente schrijven en te onthouden!

use strict;
use warnings;
use DateTime;
my $dt   = DateTime->now;   # Stores current date and time as datetime object
my $date = $dt->ymd;   # Retrieves date as a string in 'yyyy-mm-dd' format
my $time = $dt->hms;   # Retrieves time as a string in 'hh:mm:ss' format
my $wanted = "$date $time";   # creates 'yyyy-mm-dd hh:mm:ss' string
print $wanted;

Zodra je weet wat er aan de hand is, kun je de tijdelijke krachten verwijderen en een paar regels code opslaan:

use strict;
use warnings;
use DateTime;
my $dt = DateTime->now;
print join ' ', $dt->ymd, $dt->hms;

Antwoord 3, autoriteit 39%

Probeer dit:

use POSIX qw/strftime/;
print strftime('%Y-%m-%d',localtime);

de strftimemethode doet het werk effectief voor mij. Heel eenvoudig en efficiënt.



Antwoord 4, autoriteit 15%

Time::Piece(in core sinds Perl 5.10) heeft ook een strftime-functie en overbelast standaard localtime en gmtime om terug te keren Tijd::Stukobjecten:

use Time::Piece;
print localtime->strftime('%Y-%m-%d');

of zonder de overschreven lokale tijd:

use Time::Piece (); 
print Time::Piece::localtime->strftime('%F %T');

Antwoord 5, autoriteit 11%

Ik heb een kleine test gedaan (Perl v5.20.1 onder FreeBSD in VM) waarbij ik de volgende blokken elk 1.000.000 keer aanroep:

A

my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
my $now = sprintf("%04d-%02d-%02d %02d:%02d:%02d", $year+1900, $mon+1, $mday, $hour, $min, $sec);

B

my $now = strftime('%Y%m%d%H%M%S',localtime);

C

my $now = Time::Piece::localtime->strftime('%Y%m%d%H%M%S');

met de volgende resultaten:

A: 2 seconden

B: 11 seconden

C: 19 seconden

Dit is natuurlijk geen grondige test of benchmark, maar het is in ieder geval reproduceerbaar voor mij, dus hoewel het ingewikkelder is, zou ik de eerste methode verkiezen als het genereren van een datetimestamp heel vaak vereist is.

>

Bellen (bijv. onder FreeBSD 10.1)

my $now = `date "+%Y%m%d%H%M%S" | tr -d "\n"`;

misschien niet zo’n goed idee omdat het niet OS-onafhankelijk is en behoorlijk wat tijd kost.

Met vriendelijke groet,
Holger


Antwoord 6, autoriteit 7%

als je alleen een door mensen leesbare tijdreeks wilt en niet dat exacte formaat:

$t = localtime;
print "$t\n";

afdrukken

Mon Apr 27 10:16:19 2015

of wat er ook is geconfigureerd voor uw landinstelling.


Antwoord 7, autoriteit 5%

Time::Piece::datetime()kan Telimineren.

use Time::Piece;
print localtime->datetime(T => q{ });

Antwoord 8, autoriteit 2%

Kort en krachtig, geen extra modules nodig:

my $toDate = `date +%m/%d/%Y" "%l:%M:%S" "%p`;

Uitvoer zou bijvoorbeeld zijn: 25-04-2017 9:30:33 AM


Antwoord 9, autoriteit 2%

In veel gevallen is de benodigde ‘huidige tijd’ eerder $^T, de tijd waarop het script begon te lopen, in hele seconden (uitgaande van slechts 60 seconden minuten) sinds het UNIX-tijdperk.

Dit om te voorkomen dat een vroeg deel van een script een andere datum (of zomertijd) gebruikt dan een later deel van een script, bijvoorbeeld in query-voorwaarden en andere afgeleide waarden.

Voor die variant van ‘huidige tijd’ kan men een constante gebruiken, ook om te documenteren dat deze tijdens het compileren was bevroren:

use constant YMD_HMS_AT_START => POSIX::strftime( "%F %T", localtime $^T );

Alternatieve opstarttijd met hogere resolutie:

0+ [ Time::HiRes::stat("/proc/$$") ]->[10]

Other episodes