Jump to content


Photo

Calendar Feed Block Start date Today


If you specify the filter start date as 'today' it doesn't factor in the users or server timezone when querying what to display.  So 'today' will only display events while it is still that date in GMT or before.

admin/applications_addon/ips/calendar/extensions/content/feed_block/calendar.php
  if( $config['filters']['filter_start'] OR $config['filters']['filter_end'] )
  {
   $timenow = $config['filters']['filter_start'] ? @strtotime( $config['filters']['filter_start'] ) : 0;
   $timethen = $config['filters']['filter_end'] ? @strtotime( $config['filters']['filter_end'] ) : 0;

Example: Event occurs at 8:00PM CST (-6) today.  It will show on the feed block until 6 PM CST (-6) then it will roll off as it is no longer 'today' in GMT.

Status: Fixed
Version: 2.3.1
Fixed In: 2.3.2


22 Comments

The event rolling off is still an issue... But it's not because it's not being accounted for...

   if( $timenow )
   {
    if( $this->memberData['member_id'] AND $this->memberData['time_offset'] )
    {
	 $timenow = $timenow - ( $this->memberData['time_offset'] * 3600 );
    }
    else if( !$this->memberData['member_id'] AND $this->settings['time_offset'] )
    {
	 $timenow = $timenow - ( $this->settings['time_offset'] * 3600 );
    }
   }

Trying to echo $this->memberData['time_offset'] in the feed block for me echo's '0' when in the DB it is -6... This may be an IP.Board cache issue...
Another difficult issue to test. Timezone issues like this are just so much fun. ;)

Can you give this change a shot? Basically adding the offset to the strtotime calls.

$timenow = $config['filters']['filter_start'] ? @strtotime( $config['filters']['filter_start'] ) + $this->registry->class_localization->getTimeOffset() : 0;
   $timethen = $config['filters']['filter_end'] ? @strtotime( $config['filters']['filter_end'] )+ $this->registry->class_localization->getTimeOffset() : 0;
Patch applied. I'll do testing this evening to see if that does the trick. But I noticed something else that has me scratching my head...

Here is where you apply the offset to the filter date.... Shouldn't that be $timenow + offset?
if( $timenow )
   {
    if( $this->memberData['member_id'] AND $this->memberData['time_offset'] )
    {
	 $timenow = $timenow - ( $this->memberData['time_offset'] * 3600 );
    }
    else if( !$this->memberData['member_id'] AND $this->settings['time_offset'] )
    {
	 $timenow = $timenow - ( $this->settings['time_offset'] * 3600 );
    }
   }


Further down you apply the offset to the event start date.. Already a +
$_startTime = strtotime( $r['event_start_date'] );

if( !$r['event_all_day'] )
   {
    if( $this->memberData['member_id'] AND $this->memberData['time_offset'] )
    {
	 $_startTime = $_startTime + ( $this->memberData['time_offset'] * 3600 );
    }
    else if( !$this->memberData['member_id'] AND $this->settings['time_offset'] )
    {
	 $_startTime = $_startTime + ( $this->settings['time_offset'] * 3600 );
    }
We should all just operate off of GMT. I'd be fine with it being sunny at 3 AM and dark at 5 PM every day.

Yes, you're right, it is already trying to account for the offset. Shouldn't need to be done twice obviously. Taking a closer look.
I'm still trying to wrap my head aroud this a bit..

The filter date is having the offset applied, then that time w/ offset is being used as is to query the DB which stores the event time in GMT...

I think there in lies the problem when the event date in GMT crosses a day mark.

You can't do that kind of logic in the SQL query to adjust the date being pulled from the DB.. You almost need to add a day to $timenow and then add further logic when building $events
And if you remove the offset from $timenow and query in GMT... If the event crosses the day mark.. without further logic, the event would remain in the list for an entire extra day. :) Kind of the opposite problem.
I think you're right about the addition vs subtraction. Keep in mind the offset being applied to the filter and the offset being applied to the result in the query while() loop are two different things.

I'm thinking this should work - care to test?

$timenow    = $config['filters']['filter_start'] ? @strtotime( $config['filters']['filter_start'] ) : 0;
            $timethen    = $config['filters']['filter_end'] ? @strtotime( $config['filters']['filter_end'] ) : 0;

            if( $timenow )
            {
                $timenow    += $this->registry->class_localization->getTimeOffset();
            }

            if( $timethen )
            {
                $timethen    += $this->registry->class_localization->getTimeOffset();
            }
(FWIW, the above seems correct locally - I'm in EST and it was initially showing "4/20/2012 05:00" and after the change shows "4/19/2012 20:00", which would be midnight of today in GMT.
Yeah, the first offset is to set up the query, the second offset is to get the right date for the event output...

That certainly simplifies the if statements a bit... After testing, thought, it should be a minus... You are shifting GMT the opposite direction so that 00:00 of 'today' in the users timezone would match the date you are querying in the DB that is stored in GMT... using getTimeOffset() puts in DST, which is not observed in GMT.. So it throws off the normalized date by an hour...

Code below works, which is basically the same thing you had before...... I'm going to scratch a hole in my head... I'm beginning to wonder if the issue I saw was a server issue... The clock went FUBAR or something. Because manually adjusting the offset below I can make the events appear and disappear when they are supposed to...
 
		    if( $timenow )
		    {
				    if( $this->memberData['member_id'] AND $this->memberData['time_offset'] )
	    {
			 $timenow -= ( $this->memberData['time_offset'] * 3600 );
	    }
	    else if( !$this->memberData['member_id'] AND $this->settings['time_offset'] )
	    {
			 $timenow -= ( $this->settings['time_offset'] * 3600 );
	    }
		    }
		    if( $timethen )
		    {
				    if( $this->memberData['member_id'] AND $this->memberData['time_offset'] )
	    {
			 $timethen -= ( $this->memberData['time_offset'] * 3600 );
	    }
	    else if( !$this->memberData['member_id'] AND $this->settings['time_offset'] )
	    {
			 $timethen -= ( $this->settings['time_offset'] * 3600 );
	    }
		    }

I think the reason I was getting 0 for time_offset was because of this..... I was calling it from inside the block template, though.
  $backup		  = $this->memberData['time_offset'];
  $backup1		 = $this->memberData['dst_in_use'];
  $backup2		 = $this->registry->class_localization->offset;
  $this->memberData['time_offset']   = 0;
  $this->memberData['dst_in_use']    = 0;
  $this->registry->class_localization->offset = 0;
  ob_start();
  $return = $this->registry->output->getTemplate('ccs')->$templateBit( $block['block_name'], $events );
  ob_end_clean();
  $this->memberData['time_offset']   = $backup;
  $this->memberData['dst_in_use']    = $backup1;
  $this->registry->class_localization->offset = $backup2;

It 'appears' to be working fine for me now, but I'll do more testing tonight when it's tomorrow GMT and see if I can duplicate it again.
Ok, so you are basically using the original code and it's working for you?

Ok, so you are basically using the original code and it's working for you?

:( Yes. I'm not crazy, I swear!

I'll do more testing tonight.
Ok, I will leave this on awaiting feedback for now.
Ok.. I knew I wasn't crazy...

I have event set up for 'today @ 7:00 PM CST... I have my start filter set for 'today'... The event is NOT showing in the feed block...

If I set the filter to '6 hours ago', the event shows up...If it's anything less than 6.. say 5,4,3,2, or 1.. The event does NOT show up.

Let me keep digging through the code to wrap my head around this now that it's reproduceable...
Ok, so here's the issue...

strtotime('today') currently returns 4/21 00:00.. $timenow is being normalized relative to GMT to 4/21 06:00... So 'today' isn't really 'today'... It is off by 24 hours.. My day today started at 4/20 06:00
The event that is today for me is 4/21 01:00 (GMT).. So it wouldn't get pulled by the DB query as the date occurs before 4/21 06:00 .

Same would hold true for GMT + when they crossed into tomorrow and GMT was yesterday... their use of 'today' would actually be 'yesterday'. So events would hold in the block longer than they are supposed to.

Since I ate so much of your time earlier... Here's how I have fixed it on my board... Code is self explanatory, but basically I'm comparing the dates... If the date in GMT is different than the date in the users/guests timezone, we need to add or remove 24 hours so 'today' is relative.
  if( $config['filters']['filter_start'] OR $config['filters']['filter_end'] )
  {
   $timenow = $config['filters']['filter_start'] ? @strtotime( $config['filters']['filter_start'] ) : 0;
   $timethen = $config['filters']['filter_end'] ? @strtotime( $config['filters']['filter_end'] ) : 0;
 
   if( $timenow )
   {
	$date1 = gmstrftime( "%Y-%m-%d", $timenow );
	$date2 = gmstrftime( "%Y-%m-%d", ($timenow + $this->registry->class_localization->getTimeOffset() ) );
	
	if( $date1 > $date2 )
	{
	 $timenow -= 86400;
	}
	if( $date1 < $date2 )
	{
	 $timenow += 86400;
	}
	if( $this->memberData['member_id'] AND $this->memberData['time_offset'] )
	{
	 $timenow = $timenow - ( $this->memberData['time_offset'] * 3600 );
	}
	else if( !$this->memberData['member_id'] AND $this->settings['time_offset'] )
	{
	 $timenow = $timenow - ( $this->settings['time_offset'] * 3600 );
	}
   }
   if( $timethen )
   {
	$date1 = gmstrftime( "%Y-%m-%d", $timethen );
	$date2 = gmstrftime( "%Y-%m-%d", ($timethen + $this->registry->class_localization->getTimeOffset() ) );
	
	if( $date1 > $date2 )
	{
	 $timethen -= 86400;
	}
	if( $date1 < $date2 )
	{
	 $timethen += 86400;
	}
   
	if( $this->memberData['member_id'] AND $this->memberData['time_offset'] )
	{
	 $timethen = $timethen - ( $this->memberData['time_offset'] * 3600 );
	}
	else if( !$this->memberData['member_id'] AND $this->settings['time_offset'] )
	{
	 $timethen = $timethen - ( $this->settings['time_offset'] * 3600 );
	}
   }
I haven't tested this... But it might be possible to simplify this further by just using the the $now var in strtotime...

int strtotime ( string $time [, int $now = time() ] )
$now = The timestamp which is used as a base for the calculation of relative dates.

Give $now the date with the correct offset and it might pull the correct date from the get go... I'm not all that familiar with that particular function..
As mentioned, it's hard to set up a scenario to properly test this. I've reviewed your changes and they make sense, and I don't immediately (without having access to duplicate this, which is of course dependent upon specific timing) see a better solution, so we'll go with what you've confirmed works for now.

The only other thing we need to watch out for is that this doesn't adversely affect non "today", "yesterday", etc. types of strings.

As mentioned, it's hard to set up a scenario to properly test this. I've reviewed your changes and they make sense, and I don't immediately (without having access to duplicate this, which is of course dependent upon specific timing) see a better solution, so we'll go with what you've confirmed works for now.The only other thing we need to watch out for is that this doesn't adversely affect non "today", "yesterday", etc. types of strings.

Crap, I hadn't taken into consideration anything other than today.

If it is relative, 6 hours ago, it wouldn't work.

This can be duplicated after 6 pm CST on any event that occurs after 6 pm CST of the current day and as long as your time zone and GMT have separate dates, ie it is tomorrow in GMT. That, unfortunately, doesn't provide a whole hell of a lot of time to poke around with tests.. I'll mess with it tonight to see if I can come up with a solution that will work for all cases.

We should all just operate off of GMT. I'd be fine with it being sunny at 3 AM and dark at 5 PM every day.

Amen... Good thing I'm bald or I'd have no hair right now...

Ok. So all that code I put in there.... Can be replaced by using the $now var...

Using your original code, change the $timenow and $timethen to the below.
   $timenow = $config['filters']['filter_start'] ? @strtotime( $config['filters']['filter_start'], @time() + $this->registry->class_localization->getTimeOffset() ) : 0;
   $timethen = $config['filters']['filter_end'] ? @strtotime( $config['filters']['filter_end'], @time() + $this->registry->class_localization->getTimeOffset() ) : 0;

This gives you the time relative to the users timezone... Which is great for 'today', 'yesterday', 'tomorrow', 'tomorrow noon'... But as soon as you throw in '6 hours ago', the time used to query the DB will be off relative to the offset that is used as the second param of the strtotime call.

Short of doing the below (which would be wrong exactly one second every hour) I don't see how to account for both static and relative dates and still normalize the data to GMT for the DB query...
if( !gmstrftime( "%M", $timenow) AND !gmstrftime( "%S", $timenow) )
{
  $timenow -= $this->registry->class_localization->getTimeOffset();
Bah, typos and no edit ability...

if( gmstrftime( "%M", $timenow) OR gmstrftime( "%S", $timenow) )
{
  $timenow -= $this->registry->class_localization->getTimeOffset();
}
Just adding in the time now fixes both static and relative... i would have thought the relative '6 hours ago' would have been messed up, but it's not... Which confuses me a bit, but your original code and replacing these two lines seems to fix it both 'today' and '6 hours ago' (I have tested those two)
$timenow = $config['filters']['filter_start'] ? @strtotime( $config['filters']['filter_start'], @time() + $this->registry->class_localization->getTimeOffset() ) : 0;  
$timethen = $config['filters']['filter_end'] ? @strtotime( $config['filters']['filter_end'], @time() + $this->registry->class_localization->getTimeOffset() ) :0;
So, the following is working then?

$timenow    = $config['filters']['filter_start'] ? @strtotime( $config['filters']['filter_start'], @time() + $this->registry->class_localization->getTimeOffset() ) : 0;
            $timethen    = $config['filters']['filter_end'] ? @strtotime( $config['filters']['filter_end'], @time() + $this->registry->class_localization->getTimeOffset() ) : 0;

            if( $timenow )
            {
                if( $this->memberData['member_id'] AND $this->memberData['time_offset'] )
                {
                    $timenow    = $timenow - ( $this->memberData['time_offset'] * 3600 );
                }
                else if( !$this->memberData['member_id'] AND $this->settings['time_offset'] )
                {
                    $timenow    = $timenow - ( $this->settings['time_offset'] * 3600 );
                }
            }

            if( $timethen )
            {
                if( $this->memberData['member_id'] AND $this->memberData['time_offset'] )
                {
                    $timethen    = $timethen - ( $this->memberData['time_offset'] * 3600 );
                }
                else if( !$this->memberData['member_id'] AND $this->settings['time_offset'] )
                {
                    $timethen    = $timethen - ( $this->settings['time_offset'] * 3600 );
                }
            }
Yes.