7

So, uh, ok. This might get mathematical, so hope you brought your scientific calculator with you ;)

This is my problem:

alt text

Given an initial date (timestamp), time period period (seconds) and today's date (timestamp), I need to find the nearest date which coincides with the period*n plus the original/initial date.

So far, I got some stuff working nicely, such as the amount of "periods" between the initial and final(today's) date, which would be "2" in the demo above:

$initial=strtotime('2 April 1991');
$time=time();
$period=strtotime('+10 years',0);

$periods=round(($time-$initial)/$period);

The next thing I did was:

$range=$periods*$period;

And finally:

echo date('d M Y',$initial+$range);

Which wrote '03 April 2011'. How did it get to 3? (I suspect it's a leap year issue?) You know that feeling when you're missing something small? I'm feeling it all over me right now....

Christian
  • 27,509
  • 17
  • 111
  • 155
  • Unlike you, I'm testing your code and I get `01 Apr 2011`! – ncuesta Dec 22 '10 at 12:33
  • What?! Perhaps you should watch your false accusations. As it is, 01 April 1991 is wrong as well... – Christian Dec 22 '10 at 12:34
  • The periods are they set? Will they always be years or is that dynamic as well? If you only work with years you can just work on the year segment and you are home safe. If you need to work with days, you will get this leap year issue. – Knubo Dec 22 '10 at 12:37
  • False accusations? I just ran your code and shared the results with you. – ncuesta Dec 22 '10 at 12:37
  • @ncuesta - I ran (*tested*) that code and got those results, I clearly stated so. I didn't just "invent" that date. @Knubo - Yes, that is why it is strtotime. In the future people are supposed to mix them up, eg, `+1 year 2 months`. – Christian Dec 22 '10 at 12:47
  • @ncuesta There may be other variables into play here. There's no need for accusations. – Russell Dias Dec 22 '10 at 12:51
  • I wasn't accusing no one, just said what were the results of running the script myself. Didn't say anything else. Sorry if Christian took it the wrong way, wasn't my intention. – ncuesta Dec 22 '10 at 12:55
  • That's ok, pardon accepted :) – Christian Dec 22 '10 at 13:21

4 Answers4

2

Ok so if I understood what you are asking, you want to know the next date that will occurs in a given period of time (in your case, every 10 years starting from 2 April 1991, when will be the next date : 2 april 2011).

So, you should take a deeper look at the DateTime class in PHP that is wayyyy better to use for the dates because it is more accurate. You mix it with DateInterval that match exactly what you need :

<?php
$interval = new DateInterval('P10Y'); // 10 years
$initial = new DateTime('1991-04-02');
$now = new DateTime('now');

while ($now->getTimestamp() > $initial->getTimestamp()) {
    $initial = $initial->add($interval);
}

echo $initial->format('d M Y'); // should return April 2, 2011 !
?>
Cyril N.
  • 38,875
  • 36
  • 142
  • 243
  • Same issue with the other guy's question, mathematical implementation vs looping. – Christian Dec 22 '10 at 12:43
  • 1
    Works great for me. Just one thing: on the last line, it should be `echo $initial->format('d M Y');`. – ncuesta Dec 22 '10 at 12:44
  • @Christian Sciberras : you can try to do your math system on the Date object : `round(($now-$initial)/$interval) * $interval`. I can't test it right now so I can't confirm it will work. OR, you'll have to add the `->getTimestamp()` in each vars for your mathematical way. (to test). Tell me if it works, I'll edit my answer. – Cyril N. Dec 22 '10 at 12:48
  • 2
    Note that this will find the closest date *before* now, rather than the closest before or after. This is like running `floor` rather than `round` in the original question. – lonesomeday Dec 22 '10 at 13:15
  • yeah, you're right @lonesomeday, I misinterpreted nearest and "closest after" – Cyril N. Dec 22 '10 at 13:19
1

Try this out:

$current = $initial = strtotime('2 April 1991');
$time_span = '+10 years';

while ($current < time())
{ 
  $current = strtotime($time_span, $current);
}

echo date('d M Y', $current);
ncuesta
  • 760
  • 4
  • 12
  • I got `2 April 1991`. I was making on a more mathematical approach than via loops (which tend to get costly on higher ranges). I'm supposed to get it working on monthly and weekly checks as well, making it quite slow. – Christian Dec 22 '10 at 12:38
1

What happened:

+10 years from Year 0 (1970) will include 3 leap years '72, '76 and '80, but from '91 till '11 there are only five leap years '92, '96, '00, '04 and '08. You added that period twice, so because there weren't 6 leap years you got one extra day.

What you need to do:

Ad the period with strtotime one step at a time.

$period = "+10 years";
$newTime = $startingTime;
while(<condition>){
    $newTime = strtotime($period, $newTime);
}
Alin Purcaru
  • 43,655
  • 12
  • 77
  • 90
  • AH! I get it. Should have been: strtotime('+1 years',0)*10 – Christian Dec 22 '10 at 12:41
  • @Christian Sciberras NO! :) Do a while and add using `strtotime`. I posted some mockup code. If you do `strtotime('+1 years',0)*3` you'll get 5 days short of what you need. (March 28, probably.) – Alin Purcaru Dec 22 '10 at 12:44
  • That `while` is exactly what I wrote, but Christian is looking for a mathematical approach on this problem. – ncuesta Dec 22 '10 at 12:45
0

As a fix to cx42net's answer:

<?php

$initial = new DateTime('2 April 1991');
$now = new DateTime('now');
$interval = new DateInterval('P10Y');

$curDate = $initial;

while (true) {
    $curDate = $curDate->add($interval);

    $curDiff = $curDate->diff($now)->days;

    if (isset($lastDiff) && ($curDiff > $lastDiff)) {
        echo $lastDate->format('d M Y');
        break;
    } else {
        $lastDate = clone $curDate;
        $lastDiff = $curDiff;
    }
}
Community
  • 1
  • 1
lonesomeday
  • 233,373
  • 50
  • 316
  • 318