计算两天之间的差。


11

另一个日期处理问题:P

任务

编写一个程序或函数来计算用户给定的两个日期之间的差。

输入输出

上一个输入类似,输入为2 YYYYMMDD,以空格,逗号,或减号分隔-

输入值示例:

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

输出是一个整数,它是两个日期之间的差,以天为单位。

例如,输入20110101-20100101yields 36533320229 17000101yields 596124

您可以测试结果 在这里 在这里。(请参阅下面的rintaun注释。)如果两个日期相同0,则该日期应该是有效的(请参见Score)。

限制

当然,你必须不能使用任何 / ......这些都与时间戳或日期类型的函数/类的,你应该使用公历

得分了

如果您的代码没有保留该限制,则score = -∞

默认bonus值为1。

  • 如果您的代码不管输入顺序如何(例如20100101,20110101return 365-365)都可以工作,则bonus+=1
  • 如果您的代码可以处理0年bonus+=0.5
  • 如果您的代码识别出无效的月份(介于1到12之间)/日期(介于1到31之间),例如2010990134720132,并打印E(&终止程序或返回类似的东西0bonus+=1
  • 不管上面的规则,如果你的代码识别无效的日期,如201002302010022920111131,并打印E(终止程序或返回类似0bonus+=1
  • 无论上述两个规则,如果你的代码识别无效的输入字符串,如20100101|201002022010010120100202,并打印E(终止程序或返回类似0bonus+=1

score = floor(-4.2*code.length/bonus)。得分最高的代码获胜。如果两个最高代码得分相同,则奖金最高的代码获胜。如果两个最高代码同时具有相同的得分和奖金,则获胜最多的代码将获胜。

(到期日:当有5个以上的代码具有超过(或相等的)+1票数时。)


第三奖金将20030229视为无效日期吗?
rintaun

@rintaun是的。不同于,它是无效的20040229。:P
JiminP 2011年

1
WolframAlpha实际上返回正确的结果吗?我从timeanddate.com得到了矛盾的答案。我认为我的程序运行正常(至少在这种情况下:P),我同意后者。
rintaun

@rintaun我认为Wolfram | Alpha是错误的,因为365*4 + 2 + 2=1464。感谢您提供的信息!
JiminP 2011年

1
应该注意的是,即使使用timeanddate.com,也存在一些问题:它只接受1-3999年,并且会自动调整1752年9月3日之前的儒略历和公历之间的11天差异。 (因此17520903至17520914是无效日期)。测试结果时请记住这一点。
rintaun

Answers:


3

Perl 5.14,得分= -162

-163 -181 -196 -214 -167 -213 -234
  • code.length = 211:208个源字符+ 3个用于运行perl的-p选项
  • 红利= 5.5:默认值,订单,年0,永远无效的月/日,无效日期,完全无效的输入

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

计算每个日期的修改后的儒略日数(忽略与历元相关的调整以节省代码长度),并将两者相减。(参见Wikipedia中的“朱利安日”)。

  • 需要perl 5.14+作为/r替代选项
  • 计算无效日期奖励的月长计算:该30+($m&1^$m>7)部分给出除2月之外的任何月份的时长;其余的调整为普通或year年的2月

假设条件

  • “使用公历”是指我们使用的从朱利安到公历过渡之前的日期的公历。也就是说,对于相隔的时间间隔(例如1752年9月3日至1752年9月14日英国过渡),不要减去11天。
  • 例如,“处理年份0”意味着00000101-00010101应给出366,因为0是400的整数倍,因此0年是a年。

进行更改后,您的程序现在似乎可以接受无效的月份和日期,例如20111300-20119999return 2717
migimaru 2011年

@migimaru:我确实已经优化了正确性。真是 我会编辑,也许会再来。
DCharness

2

PHP,得分:-539.1

  • 706个字符
  • 所有奖金项目;奖金= 5.5

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

不打高尔夫球

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

注意

通过对提供的两个日期之间的每个有效日期进行迭代来计算天数。在较大范围内,它相当慢。我确定这不是解决此问题的最佳方法,但是我很不耐烦,这就是我最终得到的结果。:)

另外,我知道“ unolfed”代码仍然不是很可读,但是要完全重写它需要太多的工作。


2

Ruby 1.9,得分:-175 -186 -191 -199

  • 代码长度:229 243 250 260个字符
  • 奖励:5.5(默认,订单,年份0,无效的月/日,无效的日期,无效的输入)

该代码通过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

笔记:

  • h返回到该年为止的of年数(包括奖金的第0年)。
  • 正则表达式处理无效的输入奖金。
  • (!x[e]||e*f<1||f>x[e])条件处理无效的月/日/日期奖金。
  • 结果显示为第一个日期减去第二个日期,因此,如果第二个日期晚于第二个日期,它将输出为负数。
  • 不适应儒略历和公历之间的变化,因此33320229 17000101导致596134

感谢您对我的解决方案进行错误检查并推动我不断改进。我特别喜欢这里的二月长度计算。
DCharness

@DCharness感谢您也推动了我。我意识到原始提交内容还有很多改进的余地。
migimaru 2011年

1

Python,得分:-478

  • 字符:455
  • 奖励:反向日期,无效的日期/月份,无效的日期

解:

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'

我没有“ unolfed”版本,因为这是我写的方式。我没有对其进行正确的测试,因此,如果您发现错误,请发表评论。

编辑:希望修复注释中指出的错误,并以[a,b],[c,d] = [[1,2],[3,4]的形式添加解压缩


抱歉,但是当我使用Python 2.7 Shell进行测试时,无效的输入(例如'20000001,20010101')不会打印E。(仅供参考,“ 0>-1>120>6>120>13>12返回False。)
JiminP 2011年

谢谢。我是python的新手。编写此脚本时,我了解到python可以进行此x<y<z比较,或者有一个x if y else z。试图修复它。
rplnt 2011年

@rpInt:对于打高尔夫球,还有[x,z][y]比短的x if y else z,尽管它并不总是有效,因为与if表达式不同,它并不懒惰。
Lie Ryan

1

PHP,得分:-516

字符:685 676

奖金: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代码需要<?在开始时运行,否则它只会打印出代码。
加雷斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.