Blog coding and discussion of coding about JavaScript, PHP, CGI, general web building etc.

Saturday, October 8, 2016

Order dates by upcoming

Order dates by upcoming


So I build an array of various dates. Birthdays, anniversaries, and holidays. I'd like to order the array by which one is happening next, essentially sort October to September (wrapping to next year)

so if my array is

$a = ([0]=>"1980-04-14", [1]=>"2007-06-08",     [2]=>"2008-12-25", [3]=>"1978-11-03")  

I'd like to sort it so it is arranged

$a = ([0]=>"1978-11-03", [1]=>"2008-12-25",     [2]=>"1980-04-14", [3]=>"2007-06-08")  

because the november 'event' is the one that will happen next (based on it being october right now).

I'm trying usort where my cmp function is

function cmp($a, $b)  {    $a_tmp = split("-", $a);    $b_tmp = split("-", $b);    return strcmp($a_tmp[1], $b_tmp[1]);  }  

I am not sure how to modify this to get my desired effect.

Answer by cfeduke for Order dates by upcoming


Don't compare strings, instead use seconds since 1970 (ints):

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

Also I don't know PHP but I think the gist is correct.

Edit: The comparison function is encapsulated to perform comparison, nothing more. To order a list in regards to the original question sort an array with today's date included, locate today's date in the array, and then move the elements before that position to the end in ascending order by position.

Answer by Jonathan Leffler for Order dates by upcoming


I would be tempted to establish the original year of the event, and then add enough whole years to it to ensure that the value is greater than your reference date (normally today's date). Or, possibly, greater than or equal to the reference date. You can then sort in simple date order.

Edited to add:

I'm not fluent enough in PHP to give an answer in that, but here's a Perl solution.

#!/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);  

Clearly, this is not dreadfully efficient - to make it efficient, you'd calculate the date_on_or_after() value once, and then sort on those values. Perl's comparison is slightly peculiar - the variables $a and $b are magic, and appear as if out of nowhere.

When run, the script produces:

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  

Note that it largely ducks the issue of what happens with the 29th of February, because it 'works' to do so. Basically, it will generate the 'date' 2009-02-29, which compares correctly in sequence. The anniversary for 2000-02-28 would be listed before the anniversary for 2008-02-29 (if 2000-02-28 were included in the data).

Answer by Jack B Nimble for Order dates by upcoming


So it occured to me just to add 12 to any month that is less than my target month. Which is now working.

so the final function

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]);  }  

Answer by Neil Williams for Order dates by upcoming


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");  

Answer by JimmyJ for Order dates by upcoming


use strtotime() to convert the all dates to a timestamp before you add them to the array, then you can sort the array into ascending (also chronological) order. Now all you have to do is deal with the dates in the past which is easily done by comparing them against a current timestamp

i.e.

for ($i=0; $i $a[$i]){      unset($a[$i]);    }  }  

Answer by gradbot for Order dates by upcoming


No reason to reinvent the wheel. If you don't care about the keys you can use this.

$a = array_combine(array_map('strtotime', $a), $a);  ksort($a);  

Or if you want to define your own callback.

function dateCmp($date1, $date2) {    return (strtotime($date1) > strtotime($date2))?1:-1;  }    usort($a, 'dateCmp');  

If you want to keep the keys associated correctly just call uasort instead.

uasort($a, 'dateCmp');  

I did a quick speed check and the callback functions were over a magnitude slower.


Fatal error: Call to a member function getElementsByTagName() on a non-object in D:\XAMPP INSTALLASTION\xampp\htdocs\endunpratama9i\www-stackoverflow-info-proses.php on line 72

0 comments:

Post a Comment

Popular Posts

Powered by Blogger.