Hitung perbedaan antara dua hari.

11

Masalah manipulasi tanggal lainnya: P

Tugas

Tulis program atau fungsi yang menghitung perbedaan antara dua tanggal yang diberikan oleh pengguna.

Input output

Mirip dengan yang sebelumnya , input adalah dua YYYYMMDDs, dipisahkan oleh spasi , koma ,, atau tanda minus -.

Contoh nilai input:

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

Output adalah bilangan bulat, yang merupakan perbedaan antara dua tanggal, dalam hari.

Misalnya, input 20110101-20100101hasil 365, dan 33320229 17000101hasil 596124.

Anda dapat menguji hasilnya di sini di sini . (Lihat komentar rintaun di bawah ini.) Jika dua tanggal sama, program harus kembali 0, jika tanggal tersebut valid (lihat Skor ).

Larangan

Tentu saja, Anda tidak boleh menggunakan segala jenis fungsi / kelas / ... yang terkait dengan cap waktu atau tanggal, dan Anda harus menggunakan kalender Gregorian .

Skor

Jika kode Anda tidak memenuhi batasan, maka score = -∞.

Default bonusadalah 1.

  • Jika kode Anda berfungsi terlepas dari urutan input (misalnya, 20100101,20110101pengembalian 365atau -365) bonus+=1,.
  • Jika kode Anda dapat menangani tahun 0 , bonus+=0.5.
  • Jika kode Anda mengenali bulan yang tidak valid (antara 1 ~ 12) / tanggal (antara 1 ~ 31), sukai 20109901atau 34720132, dan cetak E(& akhiri program atau kembalikan sesuatu seperti 0) bonus+=1,.
  • Terlepas dari aturan di atas, jika kode Anda mengenali tanggal tidak valid, seperti 20100230, 20100229, atau 20111131, dan cetakan E(& mengakhiri program atau pengembalian sesuatu seperti 0), bonus+=1.
  • Terlepas dari dua aturan di atas, jika kode Anda mengenali string input yang tidak valid, seperti 20100101|20100202atau 2010010120100202, dan dicetak E(& mengakhiri program atau mengembalikan sesuatu seperti 0) bonus+=1,.

score = floor(-4.2*code.length/bonus). Kode dengan kemenangan skor tertinggi. Jika dua kode teratas memiliki skor yang sama, maka kode dengan bonus tertinggi akan menang. Jika dua kode teratas memiliki skor dan bonus yang sama, maka kode dengan suara terbanyak akan menang.

(Jatuh tempo: Ketika ada lebih dari 5 kode yang memiliki lebih dari (atau setara) +1suara.)

JiminP
sumber
Apakah 20030229 dianggap sebagai tanggal tidak valid dengan bonus ketiga?
rintaun
@rintaun Ya. Tidak valid, tidak seperti 20040229. : P
JiminP
1
Apakah WolframAlpha benar-benar mengembalikan hasil yang benar? Saya mendapat jawaban yang bertentangan dari itu dan timeanddate.com . Program saya, yang saya yakini berfungsi dengan benar (setidaknya dalam contoh itu: P), setuju dengan yang terakhir.
rintaun
@rintaun saya pikir Wolfram | Alpha salah, karena 365*4 + 2 + 2= 1464. Terima kasih atas informasinya!
JiminP
1
Perlu dicatat bahwa bahkan dengan timeanddate.com, ada beberapa masalah: hanya menerima tahun 1-3999, dan penyesuaian otomatis untuk perbedaan 11 hari antara kalender Julian dan Gregorian untuk tanggal sebelum 3 September 1752 (jadi 17520903 hingga 17520914 bukan tanggal yang valid). Ingatlah hal ini saat menguji hasil.
rintaun

Jawaban:

3

Perl 5.14, skor = -162

-163 -181 -196 -214 -167 -213 -234
  • code.length = 211: 208 karakter sumber + 3 untuk menjalankan perl dengan -popsi
  • bonus = 5,5: default, pesanan, tahun 0, bulan / hari yang tidak pernah berlaku, tanggal tidak valid, input yang sepenuhnya tidak valid

Kode

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

Menghitung angka hari Julian yang dimodifikasi untuk setiap tanggal (mengabaikan penyesuaian terkait zaman untuk menghemat panjang kode) dan mengurangi keduanya. (ref. "Julian Day" di Wikipedia ).

  • membutuhkan perl 5.14+ untuk /ropsi pada substitusi
  • perhitungan panjang bulan untuk mendapatkan bonus tanggal yang tidak valid: 30+($m&1^$m>7)bagian memberikan panjang bulan apa pun kecuali Februari; sisanya menyesuaikan untuk bulan Februari di tahun biasa atau tahun kabisat

Asumsi

  • "Gunakan kalender Gregorian" berarti kalender Gregorian yang subur untuk tanggal sebelum transisi Julian ke Gregorian mana pun yang kami gunakan. Artinya, jangan kurangi 11 hari untuk interval yang melintasi, misalnya, transisi Inggris 3 Sep 1752 - 14 Sep 1752.
  • "handle year 0" berarti, misalnya, 00000101-00010101harus memberikan 366, karena 0 adalah kelipatan integral dari 400, dan tahun 0 adalah tahun kabisat.
DCharness
sumber
Dengan perubahan yang Anda buat, sepertinya program Anda sekarang menerima bulan dan hari yang tidak valid, seperti 20111300-20119999pengembalian 2717.
migimaru
@migimaru: Saya memang telah mengoptimalkan kebenarannya. Menisik. Saya akan mengedit dan mungkin kembali ke sana.
DCharness
2

PHP, Skor: -539.1

  • 706 karakter
  • Semua item bonus; bonus = 5.5

Kode

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

Tidak disatukan

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

Catatan

Menghitung jumlah hari dengan mengulangi setiap tanggal yang valid antara keduanya. Cukup lambat pada rentang yang lebih besar. Saya yakin ini bukan cara terbaik untuk menyelesaikan ini, tetapi saya menjadi tidak sabar, dan inilah yang akhirnya saya lakukan. :)

Juga, saya tahu kode "ungolfed" masih belum bisa dibaca, tetapi menulis ulang sepenuhnya akan membutuhkan terlalu banyak usaha.

rintaun
sumber
2

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

  • Panjang kode: 229 243 250 260 karakter
  • Bonus: 5,5 (default, pesanan, tahun 0, bulan / hari tidak valid, tanggal tidak valid, input tidak valid)

Kode menerima input melalui 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

Catatan:

  • h mengembalikan jumlah tahun kabisat hingga tahun itu (termasuk tahun 0 untuk bonus).
  • Regex menangani bonus input yang tidak valid.
  • The (!x[e]||e*f<1||f>x[e])kondisi menangani bonus bulan / hari / tanggal yang tidak valid.
  • Hasilnya ditampilkan sebagai tanggal pertama dikurangi tanggal kedua, jadi jika tanggal kedua nanti akan ditampilkan sebagai angka negatif.
  • Tidak menyesuaikan untuk perubahan antara kalender Julian dan Gregorian, sehingga 33320229 17000101menghasilkan 596134.
migimaru
sumber
Terima kasih telah memeriksa kesalahan solusi saya dan mendorong saya untuk terus meningkatkan. Saya terutama menyukai perhitungan panjang Februari Anda di sini.
DCharness
@Charness Terima kasih telah mendorong saya juga. Saya menyadari ada banyak ruang untuk perbaikan dalam kiriman asli saya.
migimaru
1

Python, Nilai: -478

  • karakter: 455
  • bonus: tanggal mundur, hari / bulan tidak valid, tanggal tidak valid

larutan:

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'

Saya tidak memiliki versi "ungolfed" karena ini adalah bagaimana saya menulisnya. Saya tidak mengujinya dengan benar jadi jika Anda menemukan bug - silakan komentar.

sunting: mudah-mudahan memperbaiki bug yang ditunjukkan dalam komentar dan menambahkan membongkar dalam bentuk [a, b], [c, d] = [[1,2], [3,4]

rplnt
sumber
Maaf, tetapi ketika saya diuji dengan Python 2.7 Shell, input yang tidak valid seperti '20000001,20010101' tidak dapat dicetak E. (FYI, 0>-1>12, 0>6>12, 0>13>12pengembalian False.)
JiminP
Terima kasih. Saya cukup baru untuk python. Menulis skrip ini saya belajar bahwa python melakukan x<y<zperbandingan ini atau ada x if y else z. Mencoba memperbaikinya.
rplnt
@ rpInt: untuk bermain golf, ada juga [x,z][y]yang lebih pendek daripada x if y else z, meskipun tidak selalu berhasil karena tidak seperti ekspresi-jika itu tidak malas.
Lie Ryan
1

PHP, skor: -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;
Alfwed
sumber
Kode PHP membutuhkan <?di awal untuk dijalankan, jika tidak hanya akan mencetak kode.
Gareth