İki gün arasındaki farkı hesaplayın.


11

Başka bir tarih düzenleme sorunu: P

Görev

Bir kullanıcı tarafından verilen iki tarih arasındaki farkı hesaplayan bir program veya işlev yazın.

Giriş çıkış

Bir öncekine benzer şekilde , girişler YYYYMMDDboşluk , virgül ,veya eksi işareti ile ayrılmış iki s'dir -.

Giriş değerlerine örnek:

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

Çıktı, iki tarih arasındaki fark olan gün cinsinden bir tamsayıdır.

Örneğin, girdi 20110101-20100101verimleri 365ve 33320229 17000101verimleri 596124.

Sonuçları test edebilirsiniz burada burada . (Aşağıdaki rintaun'un yorumlarına bakın.) İki tarih aynıysa, 0tarih geçerliyse program geri dönmelidir (bkz. Skor ).

kısıtlama

Tabii ki, gereken kullanmayan herhangi / ... zaman damgası veya tarihe ilgili fonksiyon / sınıfın türlü ve kullanmak gerekir Gregoryen takvim .

Puan

Kodunuz kısıtlamayı korumuyorsa, o zaman score = -∞.

Varsayılan bonus1'dir.

  • Kodunuz giriş sırasından bağımsız olarak çalışıyorsa (örneğin, 20100101,20110101döndürür 365veya -365) bonus+=1,.
  • Kodunuz işleyebilir yıl 0 , bonus+=0.5.
  • Kodunuz geçersiz ayı (1 ~ 12 arasında) / tarihi (1 ~ 31 arasında) tanıyorsa 20109901veya beğenirse ve programı 34720132yazdırır E(& sonlandırır veya benzeri bir şey döndürürse 0) bonus+=1,.
  • Ne olursa olsun yukarıdaki kural, kodunuz geçersiz tarihleri gibi tanırsa 20100230, 20100229ya 20111131ve baskılar E(& gibi program veya döner bir şey sonlandırır 0), bonus+=1.
  • Ne olursa olsun iki kural yukarıdaki, kodunuz gibi geçersiz giriş dizesi, tanırsa 20100101|20100202veya 2010010120100202ve baskılar E(& gibi program veya döner bir şey sonlandırır 0), bonus+=1.

score = floor(-4.2*code.length/bonus). En yüksek puanı alan kod kazanır. En iyi iki kod aynı puana sahipse, en yüksek bonus kazanan kodlar kazanır. En iyi iki kodun skoru ve bonusu aynı ise, en yüksek oyu alan kodlar kazanır.

(Teslim tarihi: 5'ten fazla kod varsa (veya eşittir) +1.


20030229 üçüncü bonus tarafından geçersiz bir tarih olarak kabul ediliyor mu?
rintaun

@rintaun Evet. Bunun aksine, geçersiz 20040229. : P
JiminP

1
WolframAlpha aslında doğru sonucu veriyor mu? Ben cevaplar çelişkili alıyorum o ve timeanddate.com . Doğru çalıştığına inandığım programım (en azından bu durumda: P), ikincisine katılıyor.
rintaun

@rintaun Bence Wolfram | Alpha 365*4 + 2 + 2= 1464'ten beri yanlıştı . Bilgi için teşekkürler!
JiminP

1
Timeanddate.com ile bile bazı sorunların olduğu unutulmamalıdır: sadece 1-3999 yıllarını kabul eder ve 3 Eylül 1752'den önceki tarihler için Julian ve Gregorian takvimleri arasındaki 11 günlük tutarsızlığı otomatik olarak ayarlar. (yani 17520903 - 17520914 geçerli tarihler değildir). Sonuçları test ederken bunu aklınızda bulundurun.
rintaun

Yanıtlar:


3

Perl 5.14, skor = -162

-163 -181 -196 -214 -167 -213 -234
  • code.length = 211: 208 kaynak karakter + 3 perl -pseçeneği ile çalıştırma
  • bonus = 5.5: varsayılan, sipariş, yıl 0, asla geçerli olmayan ay / gün, geçersiz tarih, tamamen geçersiz giriş

kod

$_=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

Her tarih için değiştirilmiş bir Jülyen gün sayısını hesaplar (kod uzunluğunu kaydetmek için çağla ilgili ayarlamaları yoksayar) ve ikisini çıkarır. (ref. "Julian Day" Wikipedia'da ).

  • /royuncu değişikliği seçeneği için perl 5.14+ gerektirir
  • geçersiz tarih bonusu almak için ay uzunluğu hesaplama: 30+($m&1^$m>7)bölüm Şubat ayından sonra herhangi bir ayın uzunluğunu verir; geri kalanı, sıradan veya artık bir yılda Şubat ayında ayarlanıyor

Varsayımlar

  • "Gregoryen takvimini kullan", hangi Julian'dan Gregorian'a geçiş yaptığımızdan önceki tarihler için proleptik Gregoryen takvimi anlamına gelir. Yani, 3 Eylül 1752 - 14 Eylül 1752 İngiliz geçişini geçen zaman aralıklarında 11 gün çıkarmayın.
  • "işlem yılı 0", örneğin, 00000101-000101010'ın 400'ün integral katı olduğu ve dolayısıyla 0'ın artık yıl olduğu için 366 vermesi gerektiği anlamına gelir .

Yaptığınız değişikliklerle, programınız artık 20111300-20119999iade gibi geçersiz ayları ve günleri kabul ediyor gibi görünüyor 2717.
migimaru

@migimaru: Doğruluğu gerçekten optimize ettim. Lanet. Düzenleyeceğim ve belki de ona geri döneceğim.
DCharness

2

PHP, Puan: -539.1

  • 706 karakter
  • Tüm bonus eşyalar; bonus = 5.5

kod

<?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;

Not

Sağlanan ikisi arasındaki geçerli her bir tarihte yineleyerek gün sayısını hesaplar. Daha geniş aralıklarda oldukça yavaş. Eminim bu bunu çözmenin en iyi yolu değildir, ama sabırsızlandım ve sonuçta bunu yaptım. :)

Ayrıca, "ungolfed" kod hala çok okunabilir olmadığını biliyorum, ama tamamen yeniden yazmak çok fazla çaba gerektirecektir.


2

Yakut 1.9, Skor: -175 -186 -191 -199

  • Kod uzunluğu: 229 243 250 260 karakter
  • Bonus: 5.5 (varsayılan, sipariş, yıl 0, geçersiz ay / gün, geçersiz tarih, geçersiz giriş)

Kod stdin üzerinden girişi kabul eder.

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

Notlar:

  • h o yıla kadar artık yıl sayısını döndürür (bonus için 0 yılı dahil).
  • Normal ifade geçersiz giriş bonusunu işler.
  • (!x[e]||e*f<1||f>x[e])Koşul geçersiz ay / gün / tarih ikramiye işler.
  • Sonuç ilk tarih eksi ikinci tarih olarak görüntülenir, bu nedenle ikinci tarih daha sonra negatif bir sayı olarak verilir.
  • Julian ve Gregoryen takvimleri arasındaki değişikliği ayarlamaz, bu nedenle 33320229 17000101sonuçlanır 596134.

Çözümümü hata kontrol ettiğin için ve beni geliştirmeye devam etmem için teşekkürler. Özellikle Şubat-uzunluğundaki hesaplamanızı burada seviyorum.
DCharness

@DCharness Beni de ittiğin için teşekkürler. Orijinal gönderimi geliştirmek için yer bol olduğunu fark ettim.
migimaru

1

Python, Puan: -478

  • karakterler: 455
  • bonus: ters tarihler, geçersiz gün / ay, geçersiz tarih

çözüm:

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'

Ben "ungolfed" versiyonum yok çünkü böyle yazdım. Bir hata bulursanız düzgün test etmedim - lütfen yorum yapın.

edit: umarım bir yorumda işaret bir hata düzeltildi ve [a, b], [c, d] = [[1,2], [3,4] şeklinde ambalaj açma eklendi


Maalesef Python 2.7 Shell ile test ettiğimde, '20000001,20010101' gibi geçersiz girişler yazdırılmıyor E. (FYI 0>-1>12, 0>6>12, 0>13>12döner False.)
JiminP

Teşekkürler. Python için oldukça yeniyim. Bu komut dosyasını yazarken python'un bu x<y<zkarşılaştırmayı yaptığını ya da bir tane olduğunu öğrendim x if y else z. Düzeltmeye çalıştı.
rplnt

@rpInt: Golf için [x,z][y], daha kısa olan da var x if y else z, ancak if ifadesinin aksine tembel olmadığı için her zaman işe yaramaz.
Yalan Ryan

1

PHP, puan: -516

karakter: 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 kodu <?çalıştırmak için başlangıçta gerekir, aksi takdirde sadece kodu yazdırır.
Gareth
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.