[Solved] Date function showing incorrect future dates past the new year 2015

Hi all

I have a function which shows the dates and strings for future events, works very well. My problem is, any dates past 31st december 2014 shows as 340 day ago, instead of the date 1st January 2015 and so on… it seems to be referencing the past year of 2014 instead of the future year of 2015, haven’t teated 2016 or 2017 though I’m sure it will be the same.

Can anybody see what is causing this issue and how I can amend the function to print the correct string for any dates after 31st december 2014?

function dateString(DateTime $dt, $switch = false) { 
$dt->modify('midnight'); 
$now = new DateTime('midnight'); 
$diff = $now->diff($dt); 
$days = $diff->days; 
if ($now > $dt) { 
    $days *= -1; 
} 
 
switch (true) { 
    case $days === 0: 
        return 'Today'; 
    case $days === 1: 
        return 'Tomorrow'; 
    case $days === -1: 
        return 'Yesterday'; 
    case $days < -1:
        if(!$switch)
            return abs($days).' days ago';
    case $days > 1:
        if($switch)
            return $days.' days';
    default:
        return ($switch) ? abs($days).' days ago' : $dt->format('l, j F'); 
} }  

Thanks, Barry

Hmm seams to work OK for me?

This is what I did:

echo $calc = dateString(new DateTime('2016-01-01'), true);

Thanks Pepster, this is what I have:

$date = dateString(new DateTime(date("$setdate", strtotime($node->field_event_date_and_time['und'][0]['value']))));

Can you see any problems with the above snippet?

...
echo $date

Example:
Friday, 15 May, 2015 - 12:00 returns 205 days ago

Barry

Your example of “Friday, 15 May, 2015” is not one of the date and time formats that strtotime() accepts. Details of what is accepted can be found in the Supported Date and Time Formats manual pages.

That said, strtotime() does its best with what it is provided and gives a resulting timestamp for Friday, May 16th 2014 at 8:15pm. This is 205 days ago, today.

Your choices are either, use a date/time format that is accepted (see the above docs page for a comprehensive list) or, preferably, use DateTime::createFromFormat() to create the DateTime object with a particular, specified, format.

Detailed explanation: (you don’t have to read this bit really)

The subject string has three distinct date/time parts. “Friday”, “15 May” and “2015”. “Friday” is a relative date, so hold off on that initially [since ‘absolute’ parts are processed first, then ‘relative’ parts]. “15 May” sets the result date to 15 May this year (Thursday 15 May 2014). “2015” sets the time to 20:15 (Thursday 15 May 2014 8:15 pm). Now the relative part, “Friday” changes the date to the next Friday, which is the 16th (Friday 16th May 2014 8:15pm).

On the contrary, much appreciated the extra information.
At least now I know, this is down to the strtotime() capabilities, I’ll have to read and analyze what the best solution is. Not sure where to start creating a datetime object :dizzy:

Just wondering when I reach 2015, will everything work again for the 2015 events, 2016 events will start showing 230 days ago?

Thanks, Barry

I keep getting 6015 days or the Bug listed here
Anyway it’s been interesting reading about DateTime as I’ve not used this before. I probably would have built a dateString function around strtotime().

function dateString($date2, $switch = false) {
    $timestamp1 = strtotime(date('Y-m-d'));
    $timestamp2 = strtotime($date2);
    $days = ($timestamp2 - $timestamp1)/(60*60*24);
    switch (true) { 
        case $days === 0: 
            return 'Today'; 
        case $days === 1: 
            return 'Tomorrow'; 
        case $days === -1: 
            return 'Yesterday'; 
        case $days < -1:
            if(!$switch)
                return abs($days).' days ago';
        case $days > 1:
            if($switch)
                return $days.' days';
        default:
            return ($switch) ? abs($days).' days ago' : $days.' days';            
    }
}

echo dateString("2015-01-01", false);

As of today returns 25 days

Hey guys, thanks for all the input on this.
Its a new year and everything works as is for 2015, unchanged :smile:
I will come back to this another time.


The issue I’m having now, continuing this thread as everything is related.

If we look at the original switch cases, you’ll see we have today, tomorrow then number of days which outputs:

Today
Tomorrow
4 days
23 days
132 days

What I’d like and wondering how I can update our code is:

Today
Tomorrow
This Monday
This Friday
Week on Tuesday
Week on Friday
2 Weeks Away
7 Weeks Away
30 Weeks Away

We’ll need to some how calculate if where in the present week, 1 week ahead, else, show number of weeks.

Seems like a big job, would appreciate any feedback/guidance how to accomplish this.

Cheers, Barry

I’ve tired below for ‘This Weekday’ :

case $days === +2: 
        return '<span>This ' . date("l") . '</span>';
case $days === +3: 
        return '<span>This ' . date("l") . '</span>';

I thought everything worked, then realised I was print today’s day.
How do I attach the correct $variable for the +days to show the correct day?

I’ll need this to run up to +5, wondering is there way of combining +2 upto +5 inside one case?

Barry

@Pepster @Drummin @salathe

Not that big of a job really…

$targetdate = new DateTime("Feb 26, 2015");
$now = new DateTime("Today"); //Defaults to NOW. We want TODAY.
$nw = new DateTime("Next Week"); // I do this for easier "Next week" calculation. You -could- do it without this variable, but it'll make the ifs below more complex.
$diff = $now->diff($targetdate);
   if($diff->days == 0) { echo "Today"; }
   elseif($diff->days == 1) { echo "Tomorrow"; }
   elseif($now->format("WY") == $targetdate->format("WY")) { echo "This ".$targetdate->format("l"); }
   elseif($nw->format("WY") == $targetdate->format("WY")) { echo "Next ".$targetdate->format("l"); }
   else { echo floor($diff->days / 7)." weeks away."; }

EDIT: Being silly by having two separate checks. format(“WY”) is unique without needing to check W and Y separately.

Fantastic!
Thanks StarLion for taking a look.
You make it sound so easy :cold_sweat:

Ok, I’ve been looking at this and not too sure how I can replace my existing function. Will this snippet replace the full function I already have? No longer using the switch?

The function I have already is a 2 in 1 function, which displays different outputs depending if I have true or false (by default). I use this in two different contexts as shown below.

Example:

dateString(new DateTime(date('l, j F', $timestamp)), true)

Today
Tomorrow
3 Days
4 Days

. dateString(new DateTime(date('l, j F', $timestamp)))

Today
Tomorrow
Sunday, 22 February
Monday, 23 February

With this in mind, will things still work and how do we fix this so I can mirror what I have above?

And wondering about:

What is this used for, and what happens when we pass this date?

Also in the previous function we have:

function dateString(DateTime $dt, $switch = false) { 

Do we need parameters in your function?
You can see the switch in action as I mention above true/false.

Cheers, Barry
And the code comments much appreciated.

I put a value into $targetdate because i needed to test it. Based on your function call:

dateString(new DateTime(date(‘l, j F’, $timestamp)), true)

Your function definition would be:

function dateString($targetdate,$fulldate = false) {

and then omit the $targetdate = … line from my code, because you’ve already defined a DateTime object.

Change all the echos to returns, since you’re expecting the function to return a string instead of direct echoing (which is what you should be doing. Functions, with few exceptions, should never echo.)
I need a -little- more information as to how to adjust the rest of the code, because the two contexts you’ve listed above do not match what you asked for previously. (“3 days” was never an option; it would have been This Sunday or whatever.)

Great, I was only using this to show the example StarLion, with our update, the 3 days would be replaced with this Sunday or whatever day it was.

Ok, looking good so far, just done some testing, full code:

function dateStringWeeks($targetdate, $fulldate = false) {

 $now = new DateTime("Today");
  $nw = new DateTime("Next Week");
  $diff = $now->diff($targetdate);

if ($diff->days == 0) {
  return "Today";
}
elseif ($diff->days == 1) {
  return "Tomorrow";
}
elseif ($now->format("WY") == $targetdate->format("WY")) {
  return "This " . $targetdate->format("l");
}
elseif ($nw->format("WY") == $targetdate->format("WY")) {
  return "Next " . $targetdate->format("l");
}
else {
  return floor($diff->days / 7) . " weeks away.";
    }
}

Couple of issues:

  1. Not matter if I use true or false number of weeks or this day will always show, do I need the switch and default at the bottom like in the previous code.
  2. If I change a date to 2016 or 2017 the number of weeks still calculates for 2015, haven’t tried past dates yet.
  3. $fulldate is unused, how does this fit into everything.

And just a recap, function in action:

dateStringWeeks(new DateTime(date('l, j F', $timestamp)), false)

Appreciate the knowledge thanks,
Barry

Update: Just realised (3).

We need to add the below snippet into the mix, how do we do that? Another if else?

return ($fulldate).... $targetdate->format('l, j F');

1: So if i read your sentence correctly, the switch says: “Always today/tomorrow, but for all other times, if switch, return datestring.”

elseif ($now->format("WY") == $targetdate->format("WY")) {
  return "This " . $targetdate->format("l");
}

becomes

elseif ($now->format("WY") == $targetdate->format("WY")) {
  return ($fulldate) ? $targetdate->format("l, j F") : "This " . $targetdate->format("l");
}

and repeat for the other two changeable clauses.

2: The number of weeks should be correctly calculated from today’s date. You didnt mention needing to handle past dates, in fact you specified in your opening post for “future events”.

3.See #1.

Yes I should of mentioned, been working on this function for some time now StarLion, different versions on and off, just presumed you new what I was doing, sorry about the messing about I should of made it clear from the start.

The past weeks and yesterday are ‘nice to haves’, I’ll be storing lots of past events which will be stored and still available to see. Hence my need to code how past weeks functionality would work. If this is a easy update would be good to see this in action, else not a major issue be ok to exclude this.

Moving forward, the function at present is working really good with your latest update. Couple of small issues.

The default instance ‘false’ below, works perfect, shows exactly how its supposed to.

dateStringWeeks(new DateTime(date('l, j F', $timestamp)))

Today
Tomorrow
This Sunday
Next Saturday
1 Weeks Away
16 Weeks Away

The problem I’m seeing with ‘true’.

dateStringWeeks(new DateTime(date('l, j F', $timestamp)), true)

Today
Tomorrow
Sunday 22 February
Saturday 28 February
1 Weeks Away
16 Weeks Away

It seems that anything past the first week reverts back to showing weeks. Maybe I’ve coded something wrong, small glitch in the code that you can see?

The number of weeks should be correctly calculated from today’s date

This is also not showing correct weeks, an ongoing problem from previous threads.

Full code for reference after update:

function dateStringWeeks($targetdate, $fulldate = false) {

$now = new DateTime("Today");
$nw = new DateTime("Next Week");
$diff = $now->diff($targetdate);

if ($diff->days == 0) {
  return "Today";
}
elseif ($diff->days == 1) {
  return "Tomorrow";
}
elseif ($now->format("WY") == $targetdate->format("WY")) {
  return ($fulldate) ? $targetdate->format("l, j F") : "This " . $targetdate->format("l");
}
elseif ($nw->format("WY") == $targetdate->format("WY")) {
  return ($fulldate) ? $targetdate->format("l, j F") : "Next " . $targetdate->format("l");
}
else {
  return floor($diff->days / 7) . " weeks away.";
  }
}

Barry

You need to apply the change from my previous post to the final else clause as well (hence “the other two”).

As far as past dates: You can do this with a couple of methods. Here are the steps i would use for ease of readability.
1: Wrap the existing code in an if based on $diff->invert. (invert will be 1 if the date is in the past.)
2: If working with the past, the following conditions are true:
Today does not exist. (It will always be handled by invert = 0)
Yesterday is the same as Tomorrow.
This Week is the same as This Week.
Last Week can be determined using the same pattern as Next Week.
X Weeks Ago is the same as X Weeks Away, just with a word changed.

(You -could- handle all of this inside the return statements of the current code, but it’s gonna drop readability pretty harshly)

Appreciate the detailed pseudo information, feeling like a proper coder, hands on learning cheers :smile:

Ok, looking rather complex now, a powerful function in its own right, working great!
The only issue now StarLion, and then this will be complete.

The future and past years are still not showing the correct weeks, treats everything as the present year.
Example, last Tuesday in 2014 is showing as last Tuesday, January 2014 is showing as a few weeks ago.
Any ideas?

Updated function after your information, if I understood you correctly:

function dateStringWeeks($targetdate, $fulldate = false) {

  $now = new DateTime("Today");
  $nw = new DateTime("Next Week");
  $lw = new DateTime("Last Week");
  $diff = $now->diff($targetdate);
  
  if ($diff->invert) {

  // Yesterday and past events

  if ($diff->days == 1) {
    return "Yesterday";
  }
  elseif ($now->format("WY") == $targetdate->format("WY")) {
    return ($fulldate) ? $targetdate->format("l, j F") : "This " . $targetdate->format("l");
  }
  elseif ($lw->format("WY") == $targetdate->format("WY")) {
    return ($fulldate) ? $targetdate->format("l, j F") : "Last " . $targetdate->format("l");
  }
  else {
    return ($fulldate) ? $targetdate->format("l, j F") : floor($diff->days / 7) . " weeks ago.";
  }

  }  else {

  // Today and future dates

  if ($diff->days == 0) {
    return "Today";
  }
  elseif ($diff->days == 1) {
    return "Tomorrow";
  }
  elseif ($now->format("WY") == $targetdate->format("WY")) {
    return ($fulldate) ? $targetdate->format("l, j F") : "This " . $targetdate->format("l");
  }
  elseif ($nw->format("WY") == $targetdate->format("WY")) {
    return ($fulldate) ? $targetdate->format("l, j F") : "Next " . $targetdate->format("l");
  }
  else {
    return ($fulldate) ? $targetdate->format("l, j F") : floor($diff->days / 7) . " weeks away.";
  }
  }
}

Try var_dump($targetdate); just inside your function, and see what date your format has produced… (Hint: The function is correct at this point.)

Nice to hear :sunglasses:

Ok, they all seem to print the same format:

object(DateTime)#163 (3) {
  ["date"]=>
  string(26) "2015-01-25 00:00:00.000000"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(3) "UTC"
}
object(DateTime)#159 (3) {
  ["date"]=>
  string(26) "2015-02-03 00:00:00.000000"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(3) "UTC"
}
...

What do you think?

Barry

Okay, one more hint.

dateStringWeeks(new DateTime(date(‘l, j F’, $timestamp)))

If $timestamp is the unix timestamp for 2/20/2015 13:52:20, what string is produced by date(‘l, j F’,$timestamp) ? What would it be if i said the timestamp was for 2/20/2009 13:52:20?