2008-09-18 11 views
36

Wenn Sie ein Datum/eine Uhrzeit als Array von (Jahr, Monat, Tag, Stunde, Minute, Sekunde) angeben, wie würden Sie es in die Epoche umrechnen, dh die Anzahl der Sekunden seit 1970-01-01 00:00: 00 GMT?Wie wandle ich ein Datum/eine Uhrzeit in Epochzeit (Unixzeit/Sekunden seit 1970) in Perl um?

Bonus Frage: Datum/Uhrzeit als String Wenn gegeben, wie würden Sie es zuerst in das Array (y, m, d, h, m, s) analysieren?

+1

Diese Frage hat seltsame Abstimmungen – jdelator

+2

Obligatorischer Vorbehalt: Unix Epoch wird nur für die Jahre 1901 - 2038 definiert. – Piskvor

+5

@Piskvor: Das stimmt nicht genau. Und die Epoche ist definiert als der 1. Januar 1970, nicht eine Reihe. Dies ist jedoch der beste Bereich, den Sie für einen UNIX-Zeitstempel erhalten, wenn Sie ihn in einer 32-Bit-Ganzzahl darstellen (was eine weit verbreitete Konvention ist). –

Antwort

19

Dies ist der einfachste Weg, die Unix-Zeit zu bekommen:

use Time::Local; 
timelocal($second,$minute,$hour,$day,$month-1,$year); 

Beachten Sie die umgekehrte Reihenfolge der Argumente und dass der Januar ist Monat 0. Für viele weitere Optionen, die DateTime Modul von CPAN sehen.

Wie für die Analyse finden Sie in der Date::Parse Modul von CPAN. Wenn Sie wirklich mit Datum analysieren müssen, kann das Date::Manip hilfreich sein, obwohl seine eigene Dokumentation warnt Sie davor, da es eine Menge Gepäck (es kennt Dinge wie gemeinsame Geschäftsreisen, zum Beispiel) und andere Lösungen sind viel schneller.

Wenn Sie etwas über das Format des Datums/der Uhrzeit wissen, die Sie parsen, dann kann ein einfacher regulärer Ausdruck ausreichen, aber Sie sind wahrscheinlich besser dran mit einem geeigneten CPAN-Modul. Wenn Sie beispielsweise wissen, dass die Daten immer in YMDHMS-Reihenfolge vorliegen, verwenden Sie das CPAN-Modul DateTime::Format::ISO8601.


Für meine eigene Referenz, wenn nichts anderes, unten ist eine Funktion, die ich für eine Anwendung verwenden, wo ich die Daten weiß, werden immer mit allen oder einem Teil des „HMS“ Teils optional in YMDhms Ordnung sein. Es akzeptiert alle Begrenzer (zB "2009-02-15" oder "2009.02.15"). Es gibt die entsprechende Unix-Zeit (Sekunden seit 1970-01-01 00:00:00 GMT) oder -1 zurück, wenn es nicht analysiert werden konnte (was bedeutet, dass Sie besser sicher sein müssen, dass Sie das Datum 1969 nicht richtig analysieren müssen). 12-31 23:59:59). Es setzt auch zweistellige Jahre voraus XX bis "69" beziehen sich auf "20XX", ansonsten "19XX" (zB bedeutet "50-02-15" 2050-02-15, aber "75-02-15" bedeutet 1975- 02-15).

use Time::Local; 

sub parsedate { 
    my($s) = @_; 
    my($year, $month, $day, $hour, $minute, $second); 

    if($s =~ m{^\s*(\d{1,4})\W*0*(\d{1,2})\W*0*(\d{1,2})\W*0* 
       (\d{0,2})\W*0*(\d{0,2})\W*0*(\d{0,2})}x) { 
    $year = $1; $month = $2; $day = $3; 
    $hour = $4; $minute = $5; $second = $6; 
    $hour |= 0; $minute |= 0; $second |= 0; # defaults. 
    $year = ($year<100 ? ($year<70 ? 2000+$year : 1900+$year) : $year); 
    return timelocal($second,$minute,$hour,$day,$month-1,$year); 
    } 
    return -1; 
} 
+0

Welchen Vorteil hat Time :: Local Ihnen, dass das häufigere POSIX (strftime) nicht? –

+3

strftime ist für die Ausgabe Zeit, Timelocal ist es, sie "einzugeben". –

+1

$ Monat-1 für null indexierten Monat !!!!!! Ich werde versuchen, das nicht noch einmal zu vergessen. –

33

Wenn Sie das DateTime Modul verwenden, können Sie die epoch() Methode auf einem Datetime-Objekt aufrufen, denn das ist, was man sich vorstellen, wie die Unix-Zeit.

Datetime ermöglicht es Ihnen, relativ leicht von Epoche zu konvertieren, auf dem neuesten Stand Objekte.

Alternativly, localtime und gmtime wird eine Epoche in einem Array mit Tag Monat und Jahr, und timelocal und timegm vom Time::Local module wird das Gegenteil tun, die Umwandlung einer Reihe von Zeitelementen (Sekunden, Minuten, ..., Tage konvertieren , Monate etc.) in eine Epoche.

+0

Es ist immer besser, eine Bibliotheksfunktion für eine gemeinsame Operation zu verwenden, als eine eigene (fehlerhafte) Lösung zu erstellen. –

+0

Die 'Timelocal'-Lösung unten ist besser, da DateTime nicht Teil einer Standard-Perl-Installation ist –

-4

Wenn Sie suchen, nur für ein Befehlszeilenprogramm (das heißt, nicht etwas, das von anderen Funktionen aufgerufen werden lassen), dieses Skript ausprobieren. Es nimmt die Existenz von GNU date (präsentieren auf so ziemlich jedem Linux-System):

#! /usr/bin/perl -w 

use strict; 

$_ = (join ' ', @ARGV); 
$_ ||= <STDIN>; 

chomp; 

if (/^[\d.]+$/) { 
    print scalar localtime $_; 
    print "\n"; 
} 
else { 
    exec "date -d '$_' +%s"; 
} 

Hier ist, wie es funktioniert:

$ Time now 
1221763842 

$ Time yesterday 
1221677444 

$ Time 1221677444 
Wed Sep 17 11:50:44 2008 

$ Time '12:30pm jan 4 1987' 
536790600 

$ Time '9am 8 weeks ago' 
1216915200 
+0

Das ist die Art von Sache, die entweder ein Shell-Skript sein sollte, oder es sollte gemacht werden, ein richtiges Perl-Modul zu verwenden, um die Arbeit IMHO zu tun . –

+0

Warum schreiben Sie es als Shell-Skript um? Es funktioniert gut wie es ist und ich finde es sehr nützlich auf einer täglichen Basis. – raldi

+0

Keine Perl-Lösung, wenn sie auf Systemdatum angewiesen ist. Funktioniert nicht in Unix oder Windows. – kkoolpatz

-3

Ein Filter, der irgendwelche Daten in verschiedenen ISO-bezogenen Formaten konvertiert (und wer sonst noch alles nach dem Lesen von the writings des Mighty Kuhn verwendet?) Auf dem Standardeingabe-Sekunden seit der Epoche-Zeit auf der Standardausgabe beiden Teile zur Veranschaulichung dienen könnte:

[email protected]:~$ cat `which isoToEpoch` 
#!/usr/bin/perl -w 
use strict; 
use Time::Piece; 
# sudo apt-get install libtime-piece-perl 
while (<>) { 
    # date --iso=s: 
    # 2007-02-15T18:25:42-0800 
    # Other matched formats: 
    # 2007-02-15 13:50:29 (UTC-0800) 
    # 2007-02-15 13:50:29 (UTC-08:00) 
    s/(\d{4}-\d{2}-\d{2}([T ])\d{2}:\d{2}:\d{2})(?:\.\d+)? ?(?:\(UTC)?([+\-]\d{2})?:?00\)?/Time::Piece->strptime ($1, "%Y-%m-%d$2%H:%M:%S")->epoch - (defined ($3) ? $3 * 3600 : 0)/eg; 
    print; 
} 
[email protected]:~$ 
2

Mein Lieblingsdatetime-Parser ist DateTime::Format::ISO8601 Sobald Sie diese Arbeits haben, haben Sie eine Datetime Objekt, leicht konvertierbar Sekunden mit Epoche Epoche()

6

Get Date::Manip from CPAN, dann:

use Date::Manip; 
$string = '18-Sep-2008 20:09'; # or a wide range of other date formats 
$unix_time = UnixDate(ParseDate($string), "%s"); 

edit:

Datum :: Manip i s groß und langsam, aber sehr flexibel in der Analyse, und es ist reines Perl. Verwenden Sie es, wenn Sie es eilig haben, wenn Sie Code schreiben, und Sie wissen, dass Sie es nicht eilig haben werden, wenn Sie es ausführen.

z.B. Verwenden Sie es, um Befehlszeilenoptionen beim Starten einmal zu analysieren, aber verwenden Sie es nicht, um große Datenmengen auf einem ausgelasteten Webserver zu analysieren.

Siehe the authors comments.

(Danke an den Autor des ersten Kommentars unten)

+6

Nein, bitte nicht. Date :: Manips eigene Dokumentation hat einen großen Abschnitt, der versucht, Sie davon zu überzeugen, es nicht zu benutzen. –

+2

Datum :: Manip wird dich verraten, wenn du am verletzlichsten bist. Verwenden Sie DateTime. :) – Kevin

+0

@AristotlePagaltzis, wo "versucht, Sie zu überzeugen, es nicht zu verwenden" bedeutet nur "sagt, dass es alles mit einem Kalender tun kann, aber ermöglicht, dass mehrere weniger als alles durch mehrere andere Module effizienter durchgeführt werden können." Also, alles hat Scott schon gesagt, mit mehr Nachdruck auf Date :: Manip als One-Stop-Lösung. –

2

Möglicherweise eines der besseren Beispiele für ‚Es gibt mehr als einen Weg, es zu tun“, mit oder ohne Hilfe von CPAN.

Wenn Sie haben die Kontrolle darüber, was Sie als "Datum/Uhrzeit" erhalten. Ich würde vorschlagen, die Route DateTime entweder mit einer bestimmten Date :: Time :: Format-Unterklasse oder mit DateTime :: Format :: Strptime, wenn dort unterstützt nicht Ihr verrücktes Datumsformat (Details finden Sie unter datetime FAQ). Im Allgemeinen ist Date :: Time der richtige Weg, wenn Sie etwas Ernstes mit dem Ergebnis machen wollen: Nur wenige Klassen auf CPAN sind so zurückhaltend und obsess richtig genau.

Wenn Sie seltsame Freiform Sachen erwarten sind, werfen Sie es auf Date::Parse ‚s str2time() -Methode, which'll erhalten Sie ein-Sekunden seit Epoche Wert Sie können dann mit Ihrem bösen Art und Weise haben, ohne den Overhead von Date::Manip .

2

Es gibt viele Datumsmanipulationsmodule auf CPAN. Mein besonderer Favorit ist DateTime und Sie können die strptime modules verwenden, um Daten in beliebigen Formaten zu analysieren. Es gibt auch viele DateTime :: Format-Module in CPAN für die Verarbeitung spezieller Datumsformate, aber die Laufzeit ist am allgemeinsten.

7
$ENV{TZ}="GMT"; 
POSIX::tzset(); 
$time = POSIX::mktime($s,$m,$h,$d,$mo-1,$y-1900); 
+0

Epoche ist bereits in GMT, gibt es keine Zeitzone. Wenn Sie explizit TZ = GMT einstellen, analysieren Sie die Zeit nicht als ** von ** der GMT-Zeitzone und nicht als lokales Datum/Zeit? (und ich denke, dass Sie lieber TZ = UTC verwenden sollten, GMT ist die Zeitzone eines Landes) –

+0

@ ThomasGuyot-Sionnest meine Absicht war zu veranschaulichen, dass mktime von Ortszeit zu Epochse-Sekunden konvertiert, also müssen Sie wissen, in welcher Ortszeit Ihre Eingabe ist und stellen Sie TZ entsprechend ein (oder nehmen Sie einfach an, TZ ist bereits auf was Sie wollen, aber das ist schlampig) – ysth

+0

Ich denke, es ist sicher anzunehmen, dass die meisten Leute lokale Zeit verwenden wollen und das ist, was auf dem Computer/Server eingestellt ist. Ich verstehe, dass die Zone wichtig ist, wenn man mit verschiedenen Regionen arbeitet, aber ich denke, ein Beispiel zu zeigen, dass TZ bis GMT von der tatsächlichen Antwort ablenkt und sogar Neulinge dazu verleitet, die falsche Zeitzone für die Zeiteingabe zu verwenden. OTOH du bekommst einen Bonuspunkt für den Aufruf von tzset() nach dem TZ-Wechsel;) –

2

zur weiteren ein Motto, die in angewendet werden kann, beispielsweise !#/bin/sh Skripten.

EPOCH="`perl -e 'use Time::Local; print timelocal('${SEC}','${MIN}','${HOUR}','${DAY}','${MONTH}','${YEAR}'),\"\n\";'`" 

Denken Sie daran, Oktalwerte zu vermeiden!

+0

Warum benutzt man Perl, wenn man das unendlich flexiblere GNU-Datum verwenden kann? 'date -d" STRING "+% s' erlaubt fast alles von" gestern "bis" 90 Tage "[nach genau jetzt] zu traditionelleren Dingen wie" 15. März 2016 "und kann in fast jedes Format ausgeben (' +% s' ist Epoche, siehe 'date --help' für Tonnen mehr). (Es ist zu schade Perl 'DateTime' hat diese Funktionalität nicht.) –

7

Ich weiß, das ist eine alte Frage, aber dachte, ich würde eine andere Antwort anbieten.

Time::Piece ist als Kern von Perl 5.9.5

Dies ermöglicht Parsing der Zeit in willkürlichen Formaten über die strptime Methode.

z.B .:

my $t = Time::Piece->strptime("Sunday 3rd Nov, 1943", 
           "%A %drd %b, %Y"); 

Der nützliche Teil ist - weil es ein überladenes Objekt ist, können Sie es für numerische Vergleiche verwenden können.

z.B.

if ($t < time()) { #do something } 

Oder wenn Sie es in einem String-Kontext zuzugreifen:

print $t,"\n"; 

Sie erhalten:

Wed Nov 3 00:00:00 1943 

Es gibt eine Reihe von Zugriffsmethoden, die für einige verschiedene andere nützliche zeitbasierte Transformationen erlauben . https://metacpan.org/pod/Time::Piece