#!/usr/bin/php dbg = array(); require_once("RRule.php"); require_once('AwlQuery.php'); # Check database timezone $qry = new AwlQuery(); $qry->QDo("SHOW TIMEZONE"); $row = $qry->Fetch(); $initial_tz = $row->TimeZone; echo "Database Time Zone: $initial_tz\n"; @header("Content-Type: text/plain; charset=UTF-8"); echo <<description = $description; $this->dtstart = $start; $this->recur = $recur; $this->result_description = $result_description; $this->result_limit = 30; if ( preg_match('/^.*? (.*)$/', $this->dtstart, $matches) ) { $this->tz = $matches[1]; } } function PHPTest() { $result = ''; $start = microtime(true); $rule = new RepeatRule( $this->dtstart, $this->recur ); $i = 0; while( $date = $rule->next() ) { if ( ($i++ % 4) == 0 ) $result .= "\n"; $result .= " " . $date->format('Y-m-d H:i:s'); if ( $i >= $this->result_limit ) break; } $this->PHP_time = microtime(true) - $start; return $result; } function SQLTest() { $qry = new AwlQuery; global $initial_tz; # This is a hack to get the output time to be in "local time" so that we # get the same time out of the PHP code to allow the diff between the # results to work. $changed_tz = 0; if (isset($this->tz) && $this->tz != $initial_tz) { echo "Setting database time zone to: $this->tz\n"; $qry->QDo("SET TIMEZONE TO :tz", array( ':tz' => $this->tz )); $changed_tz = 1; } $result = ''; $sql = "SELECT event_instances::timestamp AS event_date FROM event_instances(:dtstart,:rrule) LIMIT ".$this->result_limit; $start = microtime(true); $qry->SetSql($sql); $qry->Bind(array( ':dtstart' => $this->dtstart, ':rrule' => $this->recur) ); // printf( "%s\n", $qry->querystring); if ( $qry->Exec("test") && $qry->rows() > 0 ) { $i = 0; while( $row = $qry->Fetch() ) { if ( ($i++ % 4) == 0 ) $result .= "\n"; $result .= " " . $row->event_date; } } $this->SQL_time = microtime(true) - $start; if ($changed_tz) { $qry->QDo("SET TIMEZONE TO '$initial_tz'"); } return $result; } } $tests = array( new RRuleTest( "Daily for 7 days", "20061103T073000", "RRULE:FREQ=DAILY;COUNT=7" ) , new RRuleTest( "Weekly for 26 weeks", "20061102T100000", "RRULE:FREQ=WEEKLY;COUNT=26;INTERVAL=1;BYDAY=TH" ) , new RRuleTest( "Fortnightly for 4 events", "20061103T160000", "RRULE:FREQ=WEEKLY;INTERVAL=2;COUNT=4" ) , new RRuleTest( "Fortnightly for 28 events", "20061103T160000", "RRULE:FREQ=WEEKLY;INTERVAL=2;UNTIL=20071122T235900" ) , new RRuleTest( "3/wk for 5 weeks", "20081101T160000", "RRULE:FREQ=WEEKLY;COUNT=15;INTERVAL=1;BYDAY=MO,WE,FR" ) , new RRuleTest( "Monthly forever", "20061104T073000", "RRULE:FREQ=MONTHLY" ) , new RRuleTest( "Monthly, on the 1st monday, 2nd wednesday, 3rd friday and last sunday, forever", "20061117T073000", "RRULE:FREQ=MONTHLY;BYDAY=1MO,2WE,3FR,-1SU" ) , new RRuleTest( "The working days of each month", "20061107T113000", "RRULE:FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;UNTIL=20070101T000000" ) , new RRuleTest( "The last working day of each month", "20061107T113000", "RRULE:FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-1;COUNT=30" ) , new RRuleTest( "Every working day", "20081020T103000", "RRULE:FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;COUNT=30" ) , new RRuleTest( "Every working day", "20081020T110000", "RRULE:FREQ=DAILY;INTERVAL=1;BYDAY=MO,TU,WE,TH,FR;COUNT=30" ) , new RRuleTest( "The last day of each month", "20110831", "RRULE:FREQ=MONTHLY;BYMONTHDAY=-1" ) , new RRuleTest( "1st Tuesday, 2nd Wednesday, 3rd Thursday & 4th Friday, every March, June, September, October and December (SQL is wrong)", "20081001T133000", "RRULE:FREQ=MONTHLY;INTERVAL=1;BYDAY=1TU,2WE,3TH,4FR;BYMONTH=3,6,9,10,12" ) , new RRuleTest( "Every tuesday and friday", "20081017T084500", "RRULE:FREQ=MONTHLY;INTERVAL=1;BYDAY=TU,FR;COUNT=30" ) , new RRuleTest( "Every tuesday and friday", "20081017T084500", "RRULE:FREQ=WEEKLY;INTERVAL=1;BYDAY=TU,FR;COUNT=30" ) , new RRuleTest( "Every tuesday and friday", "20081017T084500", "RRULE:FREQ=DAILY;INTERVAL=1;BYDAY=TU,FR;COUNT=30" ) , new RRuleTest( "Time zone 1", "19700315T030000 Pacific/Auckland", "FREQ=YEARLY;INTERVAL=1;BYDAY=3SU;BYMONTH=3" ) , new RRuleTest( "Time zone 2", "19700927T020000", "FREQ=YEARLY;INTERVAL=1;BYDAY=-1SU;BYMONTH=9" ) , new RRuleTest( "Time zone 3", "19810329T030000", "FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU" ) , new RRuleTest( "Time zone 4", "20000404T010000", "FREQ=YEARLY;BYDAY=1SU;BYMONTH=4;COUNT=15" ) , new RRuleTest( "Six Working Days", "20110905", "FREQ=DAILY;BYDAY=MO,TU,WE,TH,FR;COUNT=6" ) , new RRuleTest( "Six Working Days", "20110905", "FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR;COUNT=6" ) , new RRuleTest( "31st of each month", "20110831", "RRULE:FREQ=MONTHLY;BYMONTHDAY=31;COUNT=12" ) , new RRuleTest( "Expand over daylight savings change day forward - but no time change (2020-09-27)", "20200925T011500 Pacific/Auckland", "RRULE:FREQ=DAILY;COUNT=12" ) , new RRuleTest( "Expand over daylight savings change forward - time jump (2020-09-27) - According to RFC 5545, because 02:15 doesn't exist on 2020-09-27, that day should be skipped", "20200925T021500 Pacific/Auckland", "RRULE:FREQ=DAILY;COUNT=12" ) , new RRuleTest( "Monthly, from the 29th of Feb", "20120229", "RRULE:FREQ=MONTHLY;COUNT=12" ) ); foreach( $tests AS $k => $test ) { echo "=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=\n"; echo "$test->dtstart - $test->recur\n"; echo "$test->description\n"; $php_result = $test->PHPTest(); $sql_result = $test->SQLTest(); if ( $php_result == $sql_result ) { printf( 'PHP & SQL results are identical (-: P: %6.4lf & S: %6.4lf'."\n", $test->PHP_time, $test->SQL_time); echo "PHP Result:\n$php_result\n\n"; echo "SQL Result:\n$sql_result\n\n"; } else { printf( 'PHP & SQL results differ :-( P: %6.4lf & S: %6.4lf'."\n", $test->PHP_time, $test->SQL_time); echo "PHP Result:\n$php_result\n\n"; echo "SQL Result:\n$sql_result\n\n"; // Still under development } } exit(0);