所以我构建了一个各种日期的数组。生日,纪念日和假期。我想订购接下来发生的阵列,基本上是10月到9月(包装到明年)
所以如果我的数组是
$a = ([0]=>"1980-04-14", [1]=>"2007-06-08",
[2]=>"2008-12-25", [3]=>"1978-11-03")
我想对它进行排序以便安排
$a = ([0]=>"1978-11-03", [1]=>"2008-12-25",
[2]=>"1980-04-14", [3]=>"2007-06-08")
因为11月'事件'是接下来发生的事件(基于它现在是10月)。
我正在尝试使用我的cmp功能
function cmp($a, $b)
{
$a_tmp = split("-", $a);
$b_tmp = split("-", $b);
return strcmp($a_tmp[1], $b_tmp[1]);
}
我不知道如何修改它以获得我想要的效果。
答案 0 :(得分:3)
function relative_year_day($date) {
$value = date('z', strtotime($date)) - date('z');
if ($value < 0)
$value += 365;
return $value;
}
function cmp($a, $b)
{
$aValue = relative_year_day($a);
$bValue = relative_year_day($b);
if ($aValue == $bValue)
return 0;
return ($aValue < $bValue) ? -1 : 1;
}
$a = array("1980-04-14", "2007-06-08",
"2008-12-25", "1978-11-03");
usort($a, "cmp");
答案 1 :(得分:1)
我很想确定活动的原始年份,然后添加足够的整年以确保该值大于您的参考日期(通常是今天的日期)。或者,可能大于或等于参考日期。然后,您可以按简单的日期顺序排序。
已编辑添加:
我在PHP中不够流利,无法给出答案,但这是一个Perl解决方案。
#!/bin/perl -w
# Sort sequence of dates by next occurrence of anniversary.
# Today's "birthdays" count as low (will appear first in sequence)
use strict;
my $refdate = "2008-10-05";
my @list = (
"1980-04-14", "2007-06-08",
"2008-12-25", "1978-11-03",
"2008-10-04", "2008-10-05",
"2008-10-06", "2008-02-29"
);
sub date_on_or_after
{
my($actdate, $refdate) = @_;
my($answer) = $actdate;
if ($actdate lt $refdate) # String compare OK with ISO8601 format
{
my($act_yy, $act_mm, $act_dd) = split /-/, $actdate;
my($ref_yy, $ref_mm, $ref_dd) = split /-/, $refdate;
$ref_yy++ if ($act_mm < $ref_mm || ($act_mm == $ref_mm && $act_dd < $ref_dd));
$answer = "$ref_yy-$act_mm-$act_dd";
}
return $answer;
}
sub anniversary_compare
{
my $r1 = date_on_or_after($a, $refdate);
my $r2 = date_on_or_after($b, $refdate);
return $r1 cmp $r2;
}
my @result = sort anniversary_compare @list;
print "Before:\n";
print "* $_\n" foreach (@list);
print "Reference date: $refdate\n";
print "After:\n";
print "* $_\n" foreach (@result);
显然,这并不是非常有效 - 为了提高效率,您需要计算一次date_on_or_after()值,然后对这些值进行排序。 Perl的比较有点奇怪 - 变量$ a和$ b都是魔术,看起来好像无处不在。
运行时,脚本会生成:
Before:
* 1980-04-14
* 2007-06-08
* 2008-12-25
* 1978-11-03
* 2008-10-04
* 2008-10-05
* 2008-10-06
* 2008-02-29
Reference date: 2008-10-05
After:
* 2008-10-05
* 2008-10-06
* 1978-11-03
* 2008-12-25
* 2008-02-29
* 1980-04-14
* 2007-06-08
* 2008-10-04
请注意,它很大程度上避免了2月29日发生的事情,因为它“有效”。基本上,它将生成'date'2009-02-29,它按顺序正确比较。 2000-02-28周年纪念日将在2008-02-29周年纪念日之前上市(如果2000-02-28被纳入数据)。
答案 2 :(得分:0)
所以我只想在任何比我目标月份少的月份加12。 现在正在发挥作用。
所以最后的功能
function cmp($a, $b)
{
$a_tmp = explode('-', $a['date']);
$b_tmp = explode('-', $b['date']);
if ($a_tmp[1] < date('m')) {
$a_tmp[1] += 12;
}
if ($b_tmp[1] < date('m')) {
$b_tmp[1] += 12;
}
return strcmp($a_tmp[1] . $a_tmp[2], $b_tmp[1] . $b_tmp[2]);
}
答案 3 :(得分:0)
在将所有日期添加到数组之前,使用strtotime()将所有日期转换为时间戳,然后您可以将数组排序为升序(也按时间顺序)。现在你所要做的就是处理过去的日期,这可以通过将它们与当前时间戳进行比较来轻松完成
即
for ($i=0; $i<count($a); $i++){
if ($currentTimestamp > $a[$i]){
unset($a[$i]);
}
}
答案 4 :(得分:0)
没有理由重新发明轮子。如果您不关心按键,可以使用它。
$a = array_combine(array_map('strtotime', $a), $a);
ksort($a);
或者如果你想定义自己的回调。
function dateCmp($date1, $date2) {
return (strtotime($date1) > strtotime($date2))?1:-1;
}
usort($a, 'dateCmp');
如果您想要正确关联密钥,请改为调用uasort。
uasort($a, 'dateCmp');
我进行了快速检查,回调函数的速度慢了很多。
答案 5 :(得分:-1)
不要比较字符串,而是使用自1970年以来的秒数(整数):
$date1 = split("-", $a);
$date2 = split("-", $b);
$seconds1 = mktime(0,0,0,$date1[1],$date1[2],$date1[0]);
$seconds2 = mktime(0,0,0,$date2[1],$date2[2],$date2[0]);
// eliminate years
$seconds1 %= 31536000;
$seconds2 %= 31536000;
return $seconds1 - $seconds2;
我也不知道PHP,但我认为要点是正确的。
编辑:比较功能被封装以执行比较,仅此而已。要订购有关原始问题的列表,请对包含今天日期的数组进行排序,在数组中找到今天的日期,然后按位置按升序将元素移动到该位置之前。