Source for file Duration.class.php

Documentation is available at Duration.class.php

  1. <?php
  2. /**
  3. * @since 5/2/05
  4. * @package harmoni.primitives.chronology
  5. *
  6. * @copyright Copyright &copy; 2005, Middlebury College
  7. * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License (GPL)
  8. *
  9. * @version $Id: Duration.class.php,v 1.5 2007/09/04 20:25:25 adamfranco Exp $
  10. *
  11. * @link http://harmoni.sourceforge.net/
  12. * @author Adam Franco <adam AT adamfranco DOT com> <afranco AT middlebury DOT edu>
  13. */
  14. require_once(dirname(__FILE__)."/ChronologyConstants.class.php");
  15. require_once(dirname(__FILE__)."/../Magnitudes/Magnitude.class.php");
  16.  
  17. /**
  18. * I represent a duration of time. I have been tested to support durations of
  19. * up to 4 billion (4,000,000,000) years with second precision and up to
  20. * 50 billion (50,000,000) years with hour precision. Durations beyond 50 billion
  21. * years have not been tested.
  22. *
  23. * To create new Duration instances, <b>use one of the static instance-creation
  24. * methods</b>, NOT 'new Duration':
  25. * - {@link fromString Duration::fromString($aString)}
  26. * - {@link fromString Duration::fromString($aString)}
  27. * - {@link withDays Duration::withDays($days)}
  28. * - {@link withDaysHoursMinutesSeconds Duration::withDaysHoursMinutesSeconds($days,}
  29. * $hours, $minutes, $seconds)}
  30. * - {@link withHours Duration::withHours($hours)}
  31. * - {@link withMinutes Duration::withMinutes($minutes)}
  32. * - {@link withMonth Duration::withMonth($anIntOrStrMonth)}
  33. * - {@link withSeconds Duration::withSeconds($seconds)}
  34. * - {@link withWeeks Duration::withWeeks($weeks)}
  35. * - {@link zero Duration::zero()}
  36. *
  37. * @since 5/2/05
  38. * @package harmoni.primitives.chronology
  39. *
  40. * @copyright Copyright &copy; 2005, Middlebury College
  41. * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License (GPL)
  42. *
  43. * @version $Id: Duration.class.php,v 1.5 2007/09/04 20:25:25 adamfranco Exp $
  44. *
  45. * @link http://harmoni.sourceforge.net/
  46. * @author Adam Franco <adam AT adamfranco DOT com> <afranco AT middlebury DOT edu>
  47. */
  48. class Duration
  49. extends Magnitude
  50. {
  51. /*******************************************************
  52. * Class methods - Instance Creation
  53. *********************************************************/
  54.  
  55. /**
  56. * Formatted as per ANSI 5.8.2.16: [-]D:HH:MM:SS[.S]
  57. *
  58. * @param string $aString
  59. * @return object Duration
  60. * @access public
  61. * @since 5/13/05
  62. * @static
  63. */
  64. function fromString ( $aString ) {
  65. $parser = new ANSI58216StringParser ($aString);
  66. if (!is_string($aString) || !preg_match('/[^\W]/', $aString) || !$parser) {
  67. $null = null;
  68. return $null;
  69. // die("'".$aString."' is not in a valid format.");
  70. }
  71. $obj = Duration::withDaysHoursMinutesSeconds(
  72. $parser->day(), $parser->hour(), $parser->minute(), $parser->second());
  73. return $obj;
  74. }
  75. /**
  76. * Create a new instance of days...
  77. *
  78. * @param integer $days
  79. * @return object Duration
  80. * @access public
  81. * @static
  82. * @since 5/3/05
  83. */
  84. function withDays ( $days ) {
  85. $obj = Duration::withDaysHoursMinutesSeconds ( $days, 0, 0, 0 );
  86. return $obj;
  87. }
  88. /**
  89. * Create a new instance with.
  90. *
  91. * @param integer $days
  92. * @param integer $hours
  93. * @param integer $minutes
  94. * @param integer $seconds
  95. * @return object Duration
  96. * @access public
  97. * @static
  98. * @since 5/3/05
  99. */
  100. function withDaysHoursMinutesSeconds ( $days, $hours, $minutes, $seconds ) {
  101. $obj = new Duration (
  102. ($days * ChronologyConstants::SecondsInDay())
  103. + ($hours * ChronologyConstants::SecondsInHour())
  104. + ($minutes * ChronologyConstants::SecondsInMinute())
  105. + $seconds);
  106. return $obj;
  107. }
  108. /**
  109. * Create a new Duration of hours...
  110. *
  111. * @param integer $hours
  112. * @return object Duration
  113. * @access public
  114. * @static
  115. * @since 5/3/05
  116. */
  117. function withHours ( $hours ) {
  118. $obj = Duration::withDaysHoursMinutesSeconds ( 0, $hours, 0, 0 );
  119. return $obj;
  120. }
  121. /**
  122. * Create a new instance of minutes...
  123. *
  124. * @param integer $minutes
  125. * @return object Duration
  126. * @access public
  127. * @static
  128. * @since 5/3/05
  129. */
  130. function withMinutes ( $minutes ) {
  131. $obj = Duration::withDaysHoursMinutesSeconds ( 0, 0, $minutes, 0 );
  132. return $obj;
  133. }
  134. /**
  135. * Create a new instance. aMonth is an Integer or a String
  136. *
  137. * @param string $anIntOrStrMonth
  138. * @return object Duration
  139. * @access public
  140. * @since 5/13/05
  141. * @static
  142. */
  143. function withMonth ( $anIntOrStrMonth ) {
  144. $currentYear = Year::current();
  145. $month = Month::withMonthYear($anIntOrStrMonth, $currentYear->startYear());
  146. $obj =$month->duration();
  147. return $obj;
  148. }
  149. /**
  150. * Create a new instance of seconds...
  151. *
  152. * @param integer $seconds
  153. * @return object Duration
  154. * @access public
  155. * @static
  156. * @since 5/3/05
  157. */
  158. function withSeconds ( $seconds ) {
  159. $obj = Duration::withDaysHoursMinutesSeconds ( 0, 0, 0, $seconds );
  160. return $obj;
  161. }
  162. /**
  163. * Create a new instance of a number of weeks
  164. *
  165. * @param float $aNumber
  166. * @return object Duration
  167. * @access public
  168. * @since 5/13/05
  169. */
  170. function withWeeks ( $aNumber ) {
  171. $obj = Duration::withDaysHoursMinutesSeconds(($aNumber * 7), 0, 0, 0);
  172. return $obj;
  173. }
  174. /**
  175. * Create a new Duration of zero length
  176. *
  177. * @return object Duration
  178. * @access public
  179. * @since 5/5/05
  180. * @static
  181. */
  182. function zero () {
  183. $obj = Duration::withDays(0);
  184. return $obj;
  185. }
  186. /*******************************************************
  187. * Instance methods - Private
  188. *********************************************************/
  189.  
  190. /**
  191. * Initialize this Duration.
  192. *
  193. * @param integer seconds
  194. * @return object Duration
  195. * @access private
  196. * @since 5/3/05
  197. */
  198. function Duration ($seconds = 0) {
  199. $this->seconds = $seconds;
  200. }
  201. /**
  202. * Answer an array {days. seconds. nanoSeconds}. Used by DateAndTime and Time
  203. *
  204. * @return array
  205. * @access private
  206. * @since 5/2/05
  207. */
  208. function ticks () {
  209. return array(
  210. $this->days(),
  211. (($this->hours() * 3600) + ($this->minutes() * 60) + floor($this->seconds()))
  212. );
  213. }
  214. /*******************************************************
  215. * Instance methods - Accessing
  216. *********************************************************/
  217.  
  218. /**
  219. * Answer the number of days the receiver represents.
  220. *
  221. * @return integer
  222. * @access public
  223. * @since 5/3/05
  224. */
  225. function days () {
  226. if ($this->isPositive())
  227. return floor($this->seconds/ChronologyConstants::SecondsInDay());
  228. else {
  229. return 0 - floor(abs($this->seconds)/ChronologyConstants::SecondsInDay());
  230. }
  231. }
  232. /**
  233. * Answer the number of hours the receiver represents.
  234. *
  235. * @return integer
  236. * @access public
  237. * @since 5/3/05
  238. */
  239. function hours () {
  240. // Above 2^31 seconds, (amost exactly 100 years), PHP converts the
  241. // variable from an integer to a float to allow it to grow larger.
  242. // While addition and subraction work fine with floats, float modulos
  243. // and divisions loose precision. This precision loss does not affect
  244. // the proper value of days up to the maximum duration tested, 50billion
  245. // years.
  246. if (abs($this->seconds) > pow(2, 31)) {
  247. $remainderDuration =$this->minus(Duration::withDays($this->days()));
  248. return $remainderDuration->hours();
  249. } else {
  250. if (!$this->isNegative())
  251. return floor(
  252. ($this->seconds % ChronologyConstants::SecondsInDay())
  253. / ChronologyConstants::SecondsInHour());
  254. else
  255. return 0 - floor(
  256. (abs($this->seconds) % ChronologyConstants::SecondsInDay())
  257. / ChronologyConstants::SecondsInHour());
  258. }
  259. }
  260. /**
  261. * Answer the number of minutes the receiver represents.
  262. *
  263. * @return integer
  264. * @access public
  265. * @since 5/3/05
  266. */
  267. function minutes () {
  268. // Above 2^31 seconds, (amost exactly 100 years), PHP converts the
  269. // variable from an integer to a float to allow it to grow larger.
  270. // While addition and subraction work fine with floats, float modulos
  271. // and divisions loose precision. This precision loss does not affect
  272. // the proper value of days up to the maximum duration tested, 50billion
  273. // years.
  274. if (abs($this->seconds) > pow(2, 31)) {
  275. $remainderDuration =$this->minus(Duration::withDays($this->days()));
  276. return $remainderDuration->minutes();
  277. } else {
  278. if (!$this->isNegative())
  279. return floor(
  280. ($this->seconds % ChronologyConstants::SecondsInHour())
  281. / ChronologyConstants::SecondsInMinute());
  282. else
  283. return 0 - floor(
  284. (abs($this->seconds) % ChronologyConstants::SecondsInHour())
  285. / ChronologyConstants::SecondsInMinute());
  286. }
  287. }
  288. /**
  289. * Format as per ANSI 5.8.2.16: [-]D:HH:MM:SS[.S]
  290. *
  291. * @return string
  292. * @access public
  293. * @since 5/3/05
  294. */
  295. function printableString () {
  296. $result = '';
  297. if ($this->isNegative())
  298. $result .= '-';
  299. $result .= abs($this->days()).':';
  300. $result .= str_pad(abs($this->hours()), 2, '0', STR_PAD_LEFT).':';
  301. $result .= str_pad(abs($this->minutes()), 2, '0', STR_PAD_LEFT).':';
  302. $result .= str_pad(abs($this->seconds()), 2, '0', STR_PAD_LEFT);
  303. return $result;
  304. }
  305. /**
  306. * Answer the number of seconds the receiver represents.
  307. *
  308. * @return integer
  309. * @access public
  310. * @since 5/3/05
  311. */
  312. function seconds () {
  313. // Above 2^31 seconds, (amost exactly 100 years), PHP converts the
  314. // variable from an integer to a float to allow it to grow larger.
  315. // While addition and subraction work fine with floats, float modulos
  316. // and divisions loose precision. This precision loss does not affect
  317. // the proper value of days up to the maximum duration tested, 50billion
  318. // years.
  319. if (abs($this->seconds) > pow(2, 31)) {
  320. $remainderDuration =$this->minus(Duration::withDays($this->days()));
  321. return $remainderDuration->seconds();
  322. } else {
  323. if ($this->isPositive())
  324. return floor($this->seconds % ChronologyConstants::SecondsInMinute());
  325. else
  326. return 0 - floor(
  327. abs($this->seconds) % ChronologyConstants::SecondsInMinute());
  328. }
  329. }
  330. /*******************************************************
  331. * Instance methods - Comparing/Testing
  332. *********************************************************/
  333.  
  334. /**
  335. * Return true if this Duration is negative.
  336. *
  337. * @return boolean
  338. * @access public
  339. * @since 5/3/05
  340. */
  341. function isNegative () {
  342. return ($this->asSeconds() < 0);
  343. }
  344. /**
  345. * Return true if this Duration is positive.
  346. *
  347. * @return boolean
  348. * @access public
  349. * @since 5/3/05
  350. */
  351. function isPositive () {
  352. return !($this->isNegative());
  353. }
  354. /**
  355. * Test if this Duration is equal to aDuration.
  356. *
  357. * @param object Duration $aDuration
  358. * @return boolean
  359. * @access public
  360. * @since 5/3/05
  361. */
  362. function isEqualTo ( $aDuration ) {
  363. return ($this->asSeconds() == $aDuration->asSeconds());
  364. }
  365. /**
  366. * Test if this Duration is less than aDuration.
  367. *
  368. * @param object Duration $aDuration
  369. * @return boolean
  370. * @access public
  371. * @since 5/3/05
  372. */
  373. function isLessThan ( $aDuration ) {
  374. return ($this->asSeconds() < $aDuration->asSeconds());
  375. }
  376. /*******************************************************
  377. * Instance methods - Operations
  378. *********************************************************/
  379.  
  380. /**
  381. * Return the absolute value of this duration.
  382. *
  383. * @return object Duration
  384. * @access public
  385. * @since 5/3/05
  386. */
  387. function abs () {
  388. $obj = new Duration (abs($this->seconds));
  389. return $obj;
  390. }
  391. /**
  392. * Divide a Duration. Operand is a Duration or a Number
  393. *
  394. * @param object Duration $aDuration
  395. * @return object Duration The result
  396. * @access public
  397. * @since 5/12/05
  398. */
  399. function dividedBy ( $operand ) {
  400. if (is_numeric($operand)) {
  401. $obj = new Duration (intval($this->asSeconds() / $operand));
  402. return $obj;
  403. } else {
  404. $denominator =$operand->asDuration();
  405. $obj = new Duration (intval($this->asSeconds() / $denominator->asSeconds()));
  406. return $obj;
  407. }
  408. }
  409. /**
  410. * Subtract a Duration.
  411. *
  412. * @param object Duration $aDuration
  413. * @return object Duration The result
  414. * @access public
  415. * @since 5/3/05
  416. */
  417. function minus ( $aDuration ) {
  418. $obj =$this->plus($aDuration->negated());
  419. return $obj;
  420. }
  421. /**
  422. * Multiply a Duration. Operand is a Duration or a Number
  423. *
  424. * @param object Duration $aDuration
  425. * @return object Duration The result
  426. * @access public
  427. * @since 5/12/05
  428. */
  429. function multipliedBy ( $operand ) {
  430. if (is_numeric($operand)) {
  431. $obj = new Duration (intval($this->asSeconds() * $operand));
  432. return $obj;
  433. } else {
  434. $duration =$operand->asDuration();
  435. $obj = new Duration (intval($this->asSeconds() * $duration->asSeconds()));
  436. return $obj;
  437. }
  438. }
  439. /**
  440. * Return the negative of this duration
  441. *
  442. * @return object Duration
  443. * @access public
  444. * @since 5/10/05
  445. */
  446. function negated () {
  447. $obj = new Duration(0 - $this->seconds);
  448. return $obj;
  449. }
  450. /**
  451. * Add a Duration.
  452. *
  453. * @param object Duration $aDuration
  454. * @return object Duration The result.
  455. * @access public
  456. * @since 5/3/05
  457. */
  458. function plus ( $aDuration ) {
  459. $obj = new Duration ($this->asSeconds() + $aDuration->asSeconds());
  460. return $obj;
  461. }
  462. /**
  463. * Round to a Duration.
  464. *
  465. * @param object Duration $aDuration
  466. * @return object Duration The result.
  467. * @access public
  468. * @since 5/3/05
  469. */
  470. function roundTo ( $aDuration ) {
  471. $obj = new Duration (
  472. intval(
  473. round(
  474. $this->asSeconds() / $aDuration->asSeconds()))
  475. * $aDuration->asSeconds());
  476. return $obj;
  477. }
  478. /**
  479. * Truncate.
  480. * e.g. if the receiver is 5 minutes, 37 seconds, and aDuration is 2 minutes,
  481. * answer 4 minutes.
  482. *
  483. * @param object Duration $aDuration
  484. * @return object Duration
  485. * @access public
  486. * @since 5/13/05
  487. */
  488. function truncateTo ( $aDuration ) {
  489. $obj = new Duration (
  490. intval($this->asSeconds() / $aDuration->asSeconds())
  491. * $aDuration->asSeconds());
  492. return $obj;
  493. }
  494. /*******************************************************
  495. * Instance methods - Converting
  496. *********************************************************/
  497.  
  498. /**
  499. * Answer the duration in seconds.
  500. *
  501. * @return integer
  502. * @access public
  503. * @since 5/3/05
  504. */
  505. function asSeconds () {
  506. return $this->seconds;
  507. }
  508. /**
  509. * Answer a Duration that represents this object.
  510. *
  511. * @return object Duration
  512. * @access public
  513. * @since 5/4/05
  514. */
  515. function asDuration () {
  516. return $this;
  517. }
  518. }
  519.  
  520. // Require the StringParser instead of the ANSI58216StringParser directly so
  521. // as to make sure that all classes are included in the appropriate order.
  522.  
  523. require_once(dirname(__FILE__)."/StringParser/StringParser.class.php");
  524.  
  525.  
  526. ?>

Documentation generated on Wed, 19 Sep 2007 10:22:51 -0400 by phpDocumentor 1.3.0RC3