Berechnen Sie die Differenz zwischen zwei Tagen.


11

Ein weiteres Problem bei der Datumsmanipulation: P.

Aufgabe

Schreiben Sie ein Programm oder eine Funktion, die die Differenz zwischen zwei von einem Benutzer angegebenen Daten berechnet.

Input-Output

Ähnlich wie bei der vorherigen Eingabe sind die Eingaben zwei YYYYMMDDs, die durch ein Leerzeichen , ein Komma ,oder ein Minuszeichen getrennt sind -.

Beispiel für Eingabewerte:

20100101-20010911
20110620-20121223
19000101 20101010
33330101,19960229
00010101 99991231

Die Ausgabe ist eine Ganzzahl, die die Differenz zwischen zwei Daten in Tagen darstellt.

Zum Beispiel Input- 20110101-20100101Erträge 365und 33320229 17000101Erträge 596124.

Sie können Ergebnisse testen hier hier . (Siehe die Kommentare von rintaun unten.) Wenn zwei Daten identisch sind, sollte das Programm zurückkehren 0, wenn das Datum gültig ist (siehe Punktzahl ).

Beschränkung

Natürlich Sie müssen nicht verwenden alle Arten von Funktion / Klasse / ..., die Zeitstempel oder das Datum bezogen sind, und sollten Sie gregorianischen Kalender .

Ergebnis

Wenn Ihr Code die Einschränkung nicht einhält, dann score = -∞.

Standard bonusist 1.

  • Wenn Ihr Code unabhängig von der Reihenfolge der Eingaben funktioniert (z. B. 20100101,20110101return 365oder -365) , bonus+=1.
  • Wenn Ihr Code das Jahr 0 verarbeiten kann , bonus+=0.5.
  • Wenn Ihr Code einen ungültigen Monat (zwischen 1 ~ 12) / Datum (zwischen 1 ~ 31) wie 20109901oder erkennt 34720132und druckt E(& das Programm beendet oder so etwas zurückgibt 0) , bonus+=1.
  • Unabhängig von der obigen Regel, wenn Ihr Code ungültige Daten wie 20100230, 20100229oder oder erkennt 20111131und druckt E(& das Programm beendet oder so etwas zurückgibt 0) , bonus+=1.
  • Unabhängig von den beiden oben genannten Regeln, wenn Ihr Code eine ungültige Eingabezeichenfolge wie 20100101|20100202oder erkennt 2010010120100202und druckt E(& das Programm beendet oder so etwas zurückgibt 0) , bonus+=1.

score = floor(-4.2*code.length/bonus). Code mit der höchsten Punktzahl gewinnt. Wenn zwei Top-Codes die gleiche Punktzahl haben, gewinnen Codes mit dem höchsten Bonus. Wenn zwei Top-Codes dieselbe Punktzahl und denselben Bonus haben, gewinnen Codes mit den höchsten Stimmen.

(Fällig: Wenn es mehr als 5 Codes gibt, die mehr als (oder gleiche) +1Stimmen haben.)


Wird 20030229 vom dritten Bonus als ungültiges Datum angesehen?
Rintaun

@ Rintaun Ja. Im Gegensatz dazu ist es ungültig 20040229. : P
JiminP

1
Gibt WolframAlpha tatsächlich das richtige Ergebnis zurück? Ich erhalte Antworten von widersprüchlichen es und timeanddate.com . Mein Programm, von dem ich glaube, dass es richtig funktioniert (zumindest in diesem Fall: P), stimmt mit letzterem überein.
Rintaun

@rintaun Ich denke Wolfram | Alpha hat sich geirrt, seit 365*4 + 2 + 2= 1464. Danke für die Information!
JiminP

1
Es sollte beachtet werden, dass es auch bei timeanddate.com einige Probleme gibt: Es akzeptiert nur die Jahre 1-3999 und passt sich automatisch an die 11-tägige Diskrepanz zwischen dem julianischen und dem gregorianischen Kalender für Daten vor dem 3. September 1752 an (17520903 bis 17520914 sind also keine gültigen Daten). Beachten Sie dies beim Testen der Ergebnisse.
Rintaun

Antworten:


3

Perl 5,14, Punktzahl = -162

-163 -181 -196 -214 -167 -213 -234
  • code.length = 211: 208 Quellzeichen + 3 zum Ausführen von Perl mit der -pOption
  • Bonus = 5,5: Standard, Bestellung, Jahr 0, nie gültiger Monat / Tag, ungültiges Datum, vollständig ungültige Eingabe

Code

$_=eval(join'-',map{($y,$m,$d)=/(....)(..)(..)/;die"E\n"if!($m*$d)||$m>12||$d>30+($m&1^$m>7)-($m==2)*(2-!($y=~s/00$//r%4));$y-=($m<3)-400;$d+int(($m+9)%12*30.6+.4)+int(365.2425*$y)}/^(\d{8})[ ,-](\d{8})$/)//E

Berechnet eine modifizierte julianische Tageszahl für jedes Datum (ohne Berücksichtigung der epochenbezogenen Anpassungen, um die Codelänge zu sparen) und subtrahiert die beiden. (Ref. "Julian Day" bei Wikipedia ).

  • erfordert Perl 5.14+ für die /rOption auf die Substitutionen
  • Monatslängenberechnung, um den ungültigen Datumsbonus zu erhalten: Der 30+($m&1^$m>7)Teil gibt die Länge eines Monats außer Februar an; Der Rest wird für den Februar in einem normalen oder Schaltjahr angepasst

Annahmen

  • "Gregorianischen Kalender verwenden" bezeichnet den proleptischen Gregorianischen Kalender für Daten vor dem von uns verwendeten Übergang von Julian zu Gregorian. Das heißt, subtrahieren Sie nicht 11 Tage für Intervalle, die beispielsweise den britischen Übergang vom 3. September 1752 bis 14. September 1752 überschreiten.
  • "Jahr 0 behandeln" bedeutet beispielsweise, 00000101-00010101dass 366 angegeben werden sollte, da 0 ein ganzzahliges Vielfaches von 400 ist und das Jahr 0 also ein Schaltjahr ist.

Mit den von Ihnen vorgenommenen Änderungen scheint Ihr Programm jetzt ungültige Monate und Tage zu akzeptieren, wie z . B. 20111300-20119999Rückgaben 2717.
Migimaru

@ Migimaru: Ich habe in der Tat die Richtigkeit optimiert. Verflixt. Ich werde bearbeiten und vielleicht darauf zurückkommen.
DCharness

2

PHP, Punktzahl: -539.1

  • 706 Zeichen
  • Alle Bonusgegenstände; Bonus = 5,5

Code

<?php $a='(\d{4})(0[0-9]|1[0-2])([0-2][0-9]|3[01])';@$p=preg_match;if(!$p('/^(\d{8})[- ,](\d{8})$/',fgets(STDIN),$z))@die(E);unset($z[0]);sort($z);foreach($z AS$x){if(!$p('/(\d{4})(0[0-9]|1[0-2])(0[1-9]|[12][0-9]|3[01])/',$x,$w))die(E);$n[]=$w;}$m=array(31,28,31,30,31,30,31,31,30,31,30,31);$r=0;$b=$n[0][1];$c=$n[0][2];$d=$n[0][3];$e=$n[1][1];$f=$n[1][2];$g=$n[1][3];@$t=str_pad;if((($b.$e==229)&&(!(!($b%4)+!($b%100)-!($b%400))))||($c>12))die(E);for($z=$b.$c.$d;;$s=$d,$r++){if($z==$e.$f.$g)break;if($z>$e.$f.$g)@die(E);if(@$s==$d)$d++;if((($c!=2)&&($d>$m[$c-1]))||(($c==2)&&($d>($m[$c-1]+!($b%4)-!($b%100)+!($b%400))))){$c++;$d=1;}if($c>12){$b++;$c=1;}$z=$b.$t($c,2,0,0).$t($d,2,0,0);}echo($r>0)?--$r:0;

Ungolfed

<?php
$a='(\d{4})(0[0-9]|1[0-2])([0-2][0-9]|3[01])';
@$p=preg_match;
if(!$p('/^(\d{8})[- ,](\d{8})$/',fgets(STDIN),$z)) @die(E);
unset($z[0]);
sort($z);
foreach($z AS $x)
{
        if (!$p('/(\d{4})(0[0-9]|1[0-2])(0[1-9]|[12][0-9]|3[01])/',$x,$w)) die(E);
        $n[]=$w;
}
$m=array(31,28,31,30,31,30,31,31,30,31,30,31);
$r=0;
$b=$n[0][1];
$c=$n[0][2];
$d=$n[0][3];
$e=$n[1][1];
$f=$n[1][2];
$g=$n[1][3];
@$t=str_pad;
if ((($b.$e==229)&&(!(!($b%4)+!($b%100)-!($b%400))))||($c>12)) die(E);
for ($z=$b.$c.$d;;$s=$d,$r++)
{
        if ($z==$e.$f.$g)break;
        if ($z>$e.$f.$g)@die(E);
        if (@$s==$d)$d++;
        if ((($c!=2)&&($d>$m[$c-1]))||(($c==2)&&($d>($m[$c-1]+!($b%4)-!($b%100)+!($b%400)))))
        {
                $c++;
                $d=1;
        }
        if ($c>12)
        {
                $b++;
                $c=1;
        }
        $z=$b.$t($c,2,0,0).$t($d,2,0,0);
}
echo($r>0)?--$r:0;

Hinweis

Berechnet die Anzahl der Tage durch Durchlaufen jedes gültigen Datums zwischen den beiden angegebenen. Bei größeren Reichweiten ist es ziemlich langsam. Ich bin mir sicher, dass dies nicht der beste Weg ist, dies zu lösen, aber ich wurde ungeduldig, und das ist es, was ich am Ende hatte. :) :)

Ich weiß auch, dass der "ungolfed" -Code immer noch nicht sehr gut lesbar ist, aber ein vollständiges Umschreiben würde zu viel Aufwand erfordern.


2

Ruby 1.9, Punktzahl: -175 -186 -191 -199

  • Codelänge: 229 243 250 260 Zeichen
  • Bonus: 5,5 (Standard, Bestellung, Jahr 0, ungültiger Monat / Tag, ungültiges Datum, ungültige Eingabe)

Der Code akzeptiert Eingaben über stdin.

h=->n{n/4-n/100+n/400+1}
u,v=gets.split(/[ ,-]/).map{|s|s=~/^\d{8}$/?(d,e,f=[s[0,4],s[4,2],s[6,2]].map &:to_i;x=[0,y=31,28+h[d]-z=h[d-1]]+[y,30,y,30,y]*2
(!x[e]||e*f<1||f>x[e])?0:d*365+z+eval(x[0,e]*?+)+f):0}
puts (v*u>0)?u-v :?E

Anmerkungen:

  • h gibt die Anzahl der Schaltjahre bis zu diesem Jahr zurück (einschließlich Jahr 0 für den Bonus).
  • Die Regex behandelt den ungültigen Eingabebonus.
  • Die (!x[e]||e*f<1||f>x[e])Bedingung behandelt die ungültigen Monats- / Tag- / Datumsboni.
  • Das Ergebnis wird als erstes Datum abzüglich des zweiten Datums angezeigt. Wenn das zweite Datum später liegt, wird es als negative Zahl ausgegeben.
  • Passt sich nicht an den Wechsel zwischen julianischem und gregorianischem Kalender an, führt also 33320229 17000101zu 596134.

Vielen Dank, dass Sie meine Lösung auf Fehler überprüft und mich dazu gedrängt haben, mich weiter zu verbessern. Ihre Februarlängenberechnung gefällt mir hier besonders gut.
DCharness

@DCharness Danke, dass du mich auch gepusht hast. Mir wurde klar, dass meine ursprüngliche Einreichung viel Raum für Verbesserungen bietet.
Migimaru

1

Python, Punktzahl: -478

  • Zeichen: 455
  • Bonus: umgekehrte Daten, ungültiger Tag / Monat, ungültiges Datum

Lösung:

import re
a=re.split('[-, ]',raw_input())
def c(x):return x[0]
def f(x,y=3):return(1if x%400==0 or x%100!=0and x%4==0 else 0)if y>2 else 0
t=[31,28,31,30,31,30,31,31,30,31,30,31]
[q,w,e],[i,o,p]=sorted([map(int,[a[x][:4],a[x][4:6],a[x][6:]])for x in[0,1]],key=c)
print sum(map(f,range(q,i)))+(i-q)*365+p+sum(t[:o-1])-e-sum(t[:w-1])+f(i,o)-f(q,w)if 0<w<13and 0<e<32and 0<o<13and 0<p<32and(e<=t[w-1]or(f(q)and e==29))and(p<=t[o-1]or(f(i)and p==29))else 'E'

Ich habe keine "ungolfed" -Version, da ich sie so geschrieben habe. Ich habe es nicht richtig getestet. Wenn Sie einen Fehler finden, kommentieren Sie ihn bitte.

edit: hoffentlich wurde ein Fehler behoben, auf den in einem Kommentar hingewiesen wurde, und das Auspacken in Form von [a, b], [c, d] = [[1,2], [3,4] hinzugefügt.


Entschuldigung, aber als ich mit Python 2.7 Shell getestet habe, werden ungültige Eingaben wie '20000001,20010101' nicht gedruckt E. (FYI, 0>-1>12, 0>6>12, 0>13>12kehrt False.)
JiminP

Vielen Dank. Ich bin ziemlich neu in Python. Beim Schreiben dieses Skripts habe ich gelernt, dass Python diesen x<y<zVergleich durchführt oder dass es eine gibt x if y else z. Versucht, es zu beheben.
rplnt

@rpInt: Für das Golfen gibt es auch das, [x,z][y]das kürzer ist als x if y else z, obwohl es nicht immer funktioniert, da es im Gegensatz zum if-Ausdruck nicht faul ist.
Lie Ryan

1

PHP, Punktzahl: -516

Zeichen: 685 676

Bonus: 5.5

<? $z='/((\d{1,4})(\d\d)(\d\d))[- ,]((\d{1,4})(\d\d)(\d\d))/';if(!preg_match($z,$argv[1],$m))die('E');$s=1;if($m[1]>$m[5]){if(!preg_match($z,"$m[5] $m[1]",$m))die('E');$s=-1;}$b=array(31,28,31,30,31,30,31,31,30,31,30,31);list($x,$v,$c,$d,$e,$w,$f,$g,$h)=$m;if($d>12||1>$d||$g>12||1>$g||1>$e||1>$h||($e>$b[$d-1]&&!($d==2&&$e<30&&$c%4==0))||($h>$b[$g-1]&&!($g==2&&$h<30&&$f%4==0)))die('E');$z='array_slice';$y='array_sum';$x=$d!=$g||$e>$h;$r=$x?$b[$d-1]+$h-$e:$h-$e;$d+=$x;if($d>12){$c++;$d=1;}$r+=$d>$g?$y($z($b,$d-1,13-$d))+$y($z($b,0,$g-1)):($d!=$g?$y($z($b,$d-1,$g-$d)):0);$r+=($f-$c-($d>$g))*365;for($i=$c;$i<=$f;$i++)if($i%4==0&&$i.'0229'>$v&&$i.'0229'<$w)$r++;echo $s*$r;

PHP-Code muss <?am Anfang ausgeführt werden, andernfalls wird nur der Code ausgedruckt.
Gareth
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.