2016-12-13 26 views
1

Ich fange mit zwei Daten an.Wie kann ich an Sonntagen zwischen zwei Terminen teilnehmen?

my $date1 = 01/01/2016; 
my $date2 = 05/15/2016; 

Ich muss alle Daten der Sonntage zwischen zwei Daten setzen.

Irgendeine Idee, wo ich anfangen sollte?

+1

[Datetime] (https: // metacpan.org/pod/DateTime) – stevieb

+0

Sie sollten mit der Auswahl eines Moduls beginnen. Ich bin teilweise auf [DateTime] (http://search.cpan.org/perldoc?DateTime) mit [DateTime :: Format :: Strptime] (http://search.cpan.org/perldoc?DateTime :: Format :: Strptime) für das Parsen. – ikegami

+0

Ist der Sonntag zwischen * und * beiden Daten? – Borodin

Antwort

6

Your solution is good, aber es verbraucht möglicherweise viel Speicher eine Reihe von Sonntagen zu schaffen, die verwendet werden könnten nie. DateTime-Objekte sind nicht klein und nicht billig.

Eine Alternative ist ein Iterator, eine Funktion, die bei jedem Aufruf den nächsten Sonntag generiert. Es erzeugt jeden Sonntag auf Nachfrage, anstatt sie alle vorher zu berechnen. Dies spart Speicher und unterstützt potentiell unendliche Sonntage.

Das gibt eine Closure zurück, eine anonyme Subroutine, die sich an die lexikalischen Variablen erinnert, mit denen sie erstellt wurde. So ähnlich wie ein Inside-Out-Objekt, eine Funktion mit angehängten Daten. Sie können es dann wie jede Subroutinenreferenz aufrufen.

my $sundays = sundays_iterator($startDate, $endDate); 
while(my $sunday = $sundays->()) { 
    say $sunday; 
} 

Der Vorteil ist es viel Speicher spart, dies besonders wichtig sein kann, wenn Sie die Daten als Benutzereingabe sind unter: ein böswilliger Angreifer kann eine enorme Bandbreite verlangen viel von Ihrem Server Speicher raubend .

Es ermöglicht Ihnen auch, die Erstellung der Liste von der Verwendung der Liste zu trennen. Jetzt haben Sie eine allgemeine Möglichkeit, Sonntage innerhalb eines Datumsbereichs zu erzeugen (oder, mit einer kleinen Verbesserung, jeden Tag der Woche).

Der Nachteil ist, dass es wahrscheinlich etwas langsamer ist als ein Array in einer Schleife zu bauen ... aber wahrscheinlich nicht merklich. Funktionsaufrufe sind in Perl relativ langsam, so dass ein Funktionsaufruf für jeden Sonntag langsamer als ein Looping ist, aber das Aufrufen dieser DateTime-Methoden (die andere Methoden aufrufen, die andere Methoden aufrufen) wird diese Kosten überschwemmen. Im Vergleich zur Verwendung von DateTime ist das Aufrufen der Iterator-Funktion ein Drop in the Bucket.

+0

Er könnte einfach "print" $ sonnay \ n ";' in die erste Schleife verschieben, wenn der Speicher war ein Problem. [Sorry, wusste nicht, dass Sie antworten würden, wenn ich mein Update machte.] – ikegami

+0

@ikegami Das würde schweißen, indem die Liste der Sonntage mit der Liste der Sonntage erzeugt wird die Liste der Sonntage (und mit einem kleinen Tweak jeden Wochentag) für jeden Zweck verwendet werden, ohne sie vorgenerieren zu müssen. – Schwern

+0

War der Wechsel von 'print $ sunday-> strftime ("% m /% d /% Y ");' um 'sayay zu sagen;' absichtlich? – ikegami

0

Das ist, was ich kam, aber lassen Sie mich bitte wissen, wenn es einen besseren Weg gibt.

use DateTime; 

my $date1 = "1/1/2016"; 
my $date2 = "5/15/2016"; 

my ($startMonth, $startDay, $startYear) = split(/\//, $date1); 
my ($endMonth, $endDay, $endYear) = split(/\//, $date2); 

my $startDate = DateTime->new(
    year => $startYear, 
    month => $startMonth, 
    day => $startDay 
); 

my $endDate = DateTime->new(
    year => $endYear, 
    month => $endMonth, 
    day => $endDay 
); 

my @sundays; 

do { 
    my $date = DateTime->new(
    year => $startDate->year, 
    month => $startDate->month, 
    day => $startDate->day 
); 

    push @sundays, $date if ($date->day_of_week == 7); 
    $startDate->add(days => 1); 

} while ($startDate <= $endDate); 

foreach my $sunday (@sundays) { 
    print $sunday->strftime("%m/%d/%Y"); 
} 
+0

Da die Tage der Woche zusammenhängend sind (es sei denn, wir gehen in Julianische vs Gregorianische Kalenderlücken), können Sie das um 7 (oder vielleicht 6) beschleunigen, indem Sie zuerst '$ startDate' in a verschieben Sonntag einmal mit '$ startDate-> day_of_week' und dann 7 Tage addieren, um den nächsten Sonntag zu bekommen, bis Sie das' $ endDate' übergeben. Es könnte auch ein Haar schneller zu "meinem $ date = $ startDate-> clone" sein. Und schließlich funktioniert Time :: Piece möglicherweise schneller als DateTime, da es viel weniger Gepäck enthält. – Schwern

+2

@ikegami Während Ihre Revisionen sehr gut sind, ändern sie grundsätzlich die Antwort von jemand anderem. Setzen Sie sie als Ihre eigene Antwort oder Kommentare statt. – Schwern

+0

Ich stimme nicht zu. Probleme mit der Antwort sollten in der Antwort behoben werden. Ein Klon sollte nicht gemacht werden. Jetzt gibt es drei Antworten, die alle sagen: "DateTime verwenden". – ikegami

3

Sie sollten mit der Auswahl eines Moduls beginnen. Ich bin teilweise auf DateTime, mit DateTime::Format::Strptime für das Parsen.

use DateTime     qw(); 
use DateTime::Format::Strptime qw(); 

my $start_date = "01/01/2016"; 
my $end_date = "05/15/2016"; 

my $format = DateTime::Format::Strptime->new(
    pattern => '%m/%d/%Y', 
    time_zone => 'local', 
    on_error => 'croak', 
); 

my $start_dt = $format->parse_datetime($start_date)->set_formatter($format); 
my $end_dt = $format->parse_datetime($end_date )->set_formatter($format); 

my $sunday_dt = $start_dt->clone->add(days => 7 - $start_dt->day_of_week); 
while ($sunday_dt <= $end_dt) { 
    print "$sunday_dt\n"; 
    $sunday_dt->add(days => 7); 
} 

Hinweis: Sie wirklich nicht DateTime->new verwenden sollten, als Bill verwendet und Schwern gebilligt. Es ist nicht die empfohlene Verwendung von DateTime, da Code viel komplizierter und fehleranfälliger ist. Wie Sie sehen, können Sie mit einem Formatierer die Codegröße halbieren.


Hinweis: Schwern ist die Verwendung eines Iterators befürwortet, mit etwas die letzten vier Zeilen meiner Antwort zu ersetzen 4-mal länger (alle den Code in seiner Antwort). Es gibt keinen Grund für diese hohe Komplexität! Er geht in die Länge und sagt, wie viel Speicher der Iterator speichert, aber er speichert überhaupt nichts.

2

Datetime :: Set macht die Konstruktion einen Iterator einfach:

use DateTime::Format::Strptime(); 
use DateTime::Set(); 

my $start_date = "01/01/2016"; 
my $end_date = "05/15/2016"; 

my $format = DateTime::Format::Strptime->new(
    pattern => '%m/%d/%Y', 
    time_zone => 'local', 
    on_error => 'croak', 
); 

my $iterator = DateTime::Set->from_recurrence(
    start => $format->parse_datetime($start_date)->set_formatter($format), 
    end => $format->parse_datetime($end_date)->set_formatter($format), 
    recurrence => sub { $_[0]->add(days => 7 - $_[0]->day_of_week || 7) }, # next Sunday after $_[0] 
); 

while (my $date = $iterator->next) { 
    say $date; 
} 
+0

Schön! Ich war mir dieses Moduls nicht bewusst. – ikegami

Verwandte Themen