Skip to content

Commit

Permalink
Merge pull request #17 from oat-sa/Alroniks-microseconds
Browse files Browse the repository at this point in the history
Alroniks microseconds
  • Loading branch information
Jérôme Bogaerts committed Oct 13, 2015
2 parents 24dd4bb + 2016e3e commit 8617e85
Show file tree
Hide file tree
Showing 11 changed files with 167 additions and 100 deletions.
5 changes: 3 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "qtism/qtism",
"description": "OAT QTI Software Module Library",
"type": "library",
"version": "0.9.13",
"version": "0.9.14",
"authors": [
{
"name": "Open Assessment Technologies S.A.",
Expand All @@ -25,7 +25,8 @@
"GPL-2.0"
],
"require" : {
"php" : ">=5.3.0"
"php" : ">=5.3.0",
"alroniks/dtms": "0.5.2"
},
"require-dev": {
"phpunit/PHPUnit": ">=3.7.20"
Expand Down
101 changes: 75 additions & 26 deletions qtism/common/datatypes/Duration.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@
*/
namespace qtism\common\datatypes;

use qtism\common\enums\Cardinality;
use qtism\common\enums\BaseType;
use alroniks\dtms\DateInterval;
use alroniks\dtms\DateTime;
use DateTimeZone;
use Exception;
use InvalidArgumentException;
use qtism\common\Comparable;
use \DateInterval;
use \DateTimeZone;
use \DateTime;
use \Exception;
use \InvalidArgumentException;
use qtism\common\enums\BaseType;
use qtism\common\enums\Cardinality;

/**
* Implementation of the QTI duration datatype.
Expand Down Expand Up @@ -90,7 +90,8 @@ public function __construct($intervalSpec) {
try {
$tz = new DateTimeZone(self::TIMEZONE);
$d1 = new DateTime('now', $tz);
$d2 = new DateTime('now', $tz);
$d2 = clone $d1;

$d2->add(new DateInterval($intervalSpec));
$interval = $d2->diff($d1);
$interval->invert = ($interval->invert === 1) ? 0 : 1;
Expand All @@ -109,7 +110,7 @@ public function __construct($intervalSpec) {

}

static public function createFromDateInterval(DateInterval $interval) {
static public function createFromDateInterval(\DateInterval $interval) {
$duration = new Duration('PT0S');
$duration->setInterval($interval);
return $duration;
Expand All @@ -129,7 +130,7 @@ protected function getInterval() {
*
* @param DateInterval $interval A DateInterval PHP object.
*/
protected function setInterval(DateInterval $interval) {
protected function setInterval(\DateInterval $interval) {
$this->interval = $interval;
}

Expand Down Expand Up @@ -199,6 +200,25 @@ public function getSeconds($total = false) {

return $sYears + $sMonths + $sDays + $sHours + $sMinutes + $sSeconds;
}

/**
* Get the number of microseconds.
*
* @param bool|false $total Whether to get the total amount of microseconds, as a single integer, that represents the complete duration.
* @return int The value of the total duration in microseconds.
*/
public function getMicroseconds($total = false)
{
if (!property_exists($this->getInterval(), 'u')) {
return 0;
}

if ($total === false) {
return $this->getInterval()->u;
}

return $this->getSeconds(true) * 1e6 + $this->getMicroseconds();
}

public function __toString() {
$string = 'P';
Expand All @@ -215,7 +235,11 @@ public function __toString() {
$string .= $this->interval->d . 'D';
}

if ($this->interval->h > 0 || $this->interval->i > 0 || $this->interval->s > 0) {
if ($this->interval->h > 0
|| $this->interval->i > 0
|| $this->interval->s > 0
|| (property_exists($this->interval, 'u') && $this->interval->u > 0)
) {
$string .= 'T';

if ($this->interval->h > 0) {
Expand All @@ -229,6 +253,16 @@ public function __toString() {
if ($this->getSeconds() > 0) {
$string .= $this->interval->s . 'S';
}

if (property_exists($this->interval, 'u') && $this->getMicroseconds() > 0 ) {
$u = str_pad($this->interval->u, 6, 0, STR_PAD_LEFT);
if ($this->getSeconds() != 0) {
$string = str_replace('S', '.' . $u . 'S', $string);
} else {
$string .= '0.' . $u . 'S';
}

}
}

if ($string === 'P') {
Expand All @@ -246,9 +280,21 @@ public function __toString() {
* @return boolean Whether the equality is established.
*/
public function equals($obj) {
return (gettype($obj) === 'object' &&
$obj instanceof self &&
'' . $obj === '' . $this);
return (
is_object($obj)
&& $obj instanceof self
&& '' . $this === '' . $obj
);
}

public function round()
{
$seconds = round($this->getMicroseconds() / 1e6, 0, PHP_ROUND_HALF_UP);

$this->getInterval()->u = 0;
$this->getInterval()->s += $seconds;

return $this;
}

/**
Expand Down Expand Up @@ -277,6 +323,9 @@ public function shorterThan(Duration $duration) {
else if ($this->getSeconds() < $duration->getSeconds()) {
return true;
}
else if ($this->getMicroseconds() < $duration->getMicroseconds()) {
return true;
}
else {
return false;
}
Expand Down Expand Up @@ -308,6 +357,9 @@ public function longerThanOrEquals(Duration $duration) {
else if ($this->getSeconds() < $duration->getSeconds()) {
return false;
}
else if ($this->getMicroseconds() < $duration->getMicroseconds()) {
return false;
}
else {
return true;
}
Expand All @@ -326,17 +378,16 @@ public function add($duration) {

if ($duration instanceof Duration) {
$toAdd = $duration;
}
else {
} else {
$toAdd = new Duration('PT0S');
$toAdd->setInterval($duration);
}

$d2->add(new DateInterval($this->__toString()));
$d2->add(new DateInterval($toAdd->__toString()));

$interval = $d2->diff($d1);
$this->interval = $interval;
$this->setInterval($interval);
}

/**
Expand All @@ -346,16 +397,14 @@ public function add($duration) {
* For instance P2S - P1S = P1S
*/
public function sub(Duration $duration) {

if ($duration->longerThanOrEquals($this) === true) {
$this->setInterval(new DateInterval('PT0S'));
}
else {
$this->setInterval(new DateInterval('PT0.0S'));
} else {
$refStrDate = '@0';
$tz = new DateTimeZone(self::TIMEZONE);
$d1 = new DateTime($refStrDate, $tz);
$d2 = new DateTime($refStrDate, $tz);
$d2 = clone $d1;

$d1->add(new DateInterval($this->__toString()));
$d2->add(new DateInterval($duration->__toString()));

Expand All @@ -368,7 +417,7 @@ public function __clone() {
// ... :'( ... https://bugs.php.net/bug.php?id=50559
$tz = new DateTimeZone(self::TIMEZONE);
$d1 = new DateTime('now', $tz);
$d2 = new DateTime('now', $tz);
$d2 = clone $d1;
$d2->add(new DateInterval($this->__toString()));
$interval = $d2->diff($d1);
$interval->invert = ($interval->invert === 1) ? 0 : 1;
Expand All @@ -386,4 +435,4 @@ public function getBaseType() {
public function getCardinality() {
return Cardinality::SINGLE;
}
}
}
16 changes: 7 additions & 9 deletions qtism/runtime/tests/AssessmentItemSession.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,8 @@
use qtism\common\enums\BaseType;
use qtism\common\enums\Cardinality;
use qtism\runtime\common\ResponseVariable;
use qtism\runtime\tests\AssessmentItemSessionState;
use qtism\runtime\common\State;
use \DateTime;
use alroniks\dtms\DateTime;
use \DateTimeZone;
use \InvalidArgumentException;

Expand Down Expand Up @@ -334,7 +333,7 @@ public function getTimeLimits() {
*
* @param DateTime $timeReference A DateTime object.
*/
public function setTimeReference(DateTime $timeReference) {
public function setTimeReference(\DateTime $timeReference) {
$this->timeReference = $timeReference;
}

Expand Down Expand Up @@ -619,11 +618,10 @@ public function endAttempt(State $responses = null, $responseProcessing = true,

// Is timeLimits in force.
if ($this->hasTimeLimits() === true) {

// As per QTI 2.1 Spec, Minimum times are only applicable to assessmentSections and
// assessmentItems only when linear navigation mode is in effect.
if ($this->isNavigationLinear() === true && $this->timeLimits->hasMinTime() === true) {

if ($this->mustConsiderMinTime() === true && $this['duration']->getSeconds(true) <= $this->timeLimits->getMinTime()->getSeconds(true)) {
// An exception is thrown to prevent the numAttempts to be incremented.
// Suspend and wait for a next attempt.
Expand Down Expand Up @@ -791,7 +789,7 @@ public function interact() {
$this->setState(AssessmentItemSessionState::INTERACTING);

// Reset the time reference. If not, the time spent in SUSPENDED mode will be taken into account!
$this->setTimeReference(new DateTime('now', new DateTimeZone('UTC')));
$this->setTimeReference(new \DateTime('now', new DateTimeZone('UTC')));
$this->runCallback('interact');
}
}
Expand All @@ -806,9 +804,9 @@ public function updateDuration() {
if ($this->getState() === AssessmentItemSessionState::INTERACTING) {
$timeRef = $this->getTimeReference();
$now = new DateTime('now', new DateTimeZone('UTC'));

$data = &$this->getDataPlaceHolder();
$diff = $timeRef->diff($now);
$diff = $now->diff($timeRef);
$data['duration']->getValue()->add($diff);

$this->setTimeReference($now);
Expand Down Expand Up @@ -1177,4 +1175,4 @@ public function __clone() {

$this->setDataPlaceHolder($newData);
}
}
}
10 changes: 5 additions & 5 deletions qtism/runtime/tests/AssessmentTestSession.php
Original file line number Diff line number Diff line change
Expand Up @@ -1277,7 +1277,7 @@ public function endAttempt(State $responses, $allowLateSubmission = false) {
$this->submitItemResults($this->getAssessmentItemSessionStore()->getAssessmentItemSession($currentItem, $currentOccurence), $currentOccurence);
}
catch (AssessmentTestSessionException $e) {
$msg = "An error occured while transmitting item results to the appropriate data source at deffered responses processing time.";
$msg = "An error occurred while transmitting item results to the appropriate data source at deferred responses processing time.";
throw new AssessmentTestSessionException($msg, AssessmentTestSessionException::RESULT_SUBMISSION_ERROR, $e);
}

Expand Down Expand Up @@ -2128,22 +2128,22 @@ public function checkTimeLimits($includeMinTime = false, $includeAssessmentItem

if ($includeMinTime === true) {
$minRemainingTime = $constraint->getMinimumRemainingTime();

if ($acceptableLatency === true) {
$minRemainingTime->add($this->getAcceptableLatency());
}
}

if ($includeMaxTime === true) {
$maxRemainingTime = $constraint->getMaximumRemainingTime();

if ($acceptableLatency === true) {
$maxRemainingTime->add($this->getAcceptableLatency());
}
}

$minTimeRespected = !($includeMinTime === true && $minRemainingTime->getSeconds(true) > 0);
$maxTimeRespected = !($includeMaxTime === true && $maxRemainingTime->getSeconds(true) === 0);
$minTimeRespected = !($includeMinTime === true && $minRemainingTime->round()->getSeconds(true) > 0);
$maxTimeRespected = !($includeMaxTime === true && $maxRemainingTime->round()->getSeconds(true) === 0);

if ($minTimeRespected === false || $maxTimeRespected === false) {

Expand Down
1 change: 0 additions & 1 deletion test/QtiSmTestCase.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<?php
require_once(dirname(__FILE__) . '/../qtism/qtism.php');

use qtism\data\AssessmentTest;
use qtism\data\storage\xml\marshalling\MarshallerFactory;

abstract class QtiSmTestCase extends PHPUnit_Framework_TestCase {
Expand Down
Loading

0 comments on commit 8617e85

Please sign in to comment.