Date.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. <?php
  2. /**
  3. * PHPExcel
  4. *
  5. * Copyright (c) 2006 - 2011 PHPExcel
  6. *
  7. * This library is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2.1 of the License, or (at your option) any later version.
  11. *
  12. * This library is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with this library; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. *
  21. * @category PHPExcel
  22. * @package PHPExcel_Shared
  23. * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
  24. * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
  25. * @version 1.7.6, 2011-02-27
  26. */
  27. /**
  28. * PHPExcel_Shared_Date
  29. *
  30. * @category PHPExcel
  31. * @package PHPExcel_Shared
  32. * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
  33. */
  34. class PHPExcel_Shared_Date
  35. {
  36. /** constants */
  37. const CALENDAR_WINDOWS_1900 = 1900; // Base date of 1st Jan 1900 = 1.0
  38. const CALENDAR_MAC_1904 = 1904; // Base date of 2nd Jan 1904 = 1.0
  39. private static $ExcelBaseDate = self::CALENDAR_WINDOWS_1900;
  40. public static $dateTimeObjectType = 'DateTime';
  41. /**
  42. * Set the Excel calendar (Windows 1900 or Mac 1904)
  43. *
  44. * @param integer $baseDate Excel base date
  45. * @return boolean Success or failure
  46. */
  47. public static function setExcelCalendar($baseDate) {
  48. if (($baseDate == self::CALENDAR_WINDOWS_1900) ||
  49. ($baseDate == self::CALENDAR_MAC_1904)) {
  50. self::$ExcelBaseDate = $baseDate;
  51. return True;
  52. }
  53. return False;
  54. } // function setExcelCalendar()
  55. /**
  56. * Return the Excel calendar (Windows 1900 or Mac 1904)
  57. *
  58. * @return integer $baseDate Excel base date
  59. */
  60. public static function getExcelCalendar() {
  61. return self::$ExcelBaseDate;
  62. } // function getExcelCalendar()
  63. /**
  64. * Convert a date from Excel to PHP
  65. *
  66. * @param long $dateValue Excel date/time value
  67. * @return long PHP serialized date/time
  68. */
  69. public static function ExcelToPHP($dateValue = 0) {
  70. if (self::$ExcelBaseDate == self::CALENDAR_WINDOWS_1900) {
  71. $myExcelBaseDate = 25569;
  72. // Adjust for the spurious 29-Feb-1900 (Day 60)
  73. if ($dateValue < 60) {
  74. --$myExcelBaseDate;
  75. }
  76. } else {
  77. $myExcelBaseDate = 24107;
  78. }
  79. // Perform conversion
  80. if ($dateValue >= 1) {
  81. $utcDays = $dateValue - $myExcelBaseDate;
  82. $returnValue = round($utcDays * 24 * 60 * 60);
  83. if (($returnValue <= PHP_INT_MAX) && ($returnValue >= -PHP_INT_MAX)) {
  84. $returnValue = (integer) $returnValue;
  85. }
  86. } else {
  87. $hours = round($dateValue * 24);
  88. $mins = round($dateValue * 24 * 60) - round($hours * 60);
  89. $secs = round($dateValue * 24 * 60 * 60) - round($hours * 60 * 60) - round($mins * 60);
  90. $returnValue = (integer) gmmktime($hours, $mins, $secs);
  91. }
  92. // Return
  93. return $returnValue;
  94. } // function ExcelToPHP()
  95. /**
  96. * Convert a date from Excel to a PHP Date/Time object
  97. *
  98. * @param long $dateValue Excel date/time value
  99. * @return long PHP date/time object
  100. */
  101. public static function ExcelToPHPObject($dateValue = 0) {
  102. $dateTime = self::ExcelToPHP($dateValue);
  103. $days = floor($dateTime / 86400);
  104. $time = round((($dateTime / 86400) - $days) * 86400);
  105. $hours = round($time / 3600);
  106. $minutes = round($time / 60) - ($hours * 60);
  107. $seconds = round($time) - ($hours * 3600) - ($minutes * 60);
  108. $dateObj = date_create('1-Jan-1970+'.$days.' days');
  109. $dateObj->setTime($hours,$minutes,$seconds);
  110. return $dateObj;
  111. } // function ExcelToPHPObject()
  112. /**
  113. * Convert a date from PHP to Excel
  114. *
  115. * @param mixed $dateValue PHP serialized date/time or date object
  116. * @return mixed Excel date/time value
  117. * or boolean False on failure
  118. */
  119. public static function PHPToExcel($dateValue = 0) {
  120. $saveTimeZone = date_default_timezone_get();
  121. date_default_timezone_set('UTC');
  122. $retValue = False;
  123. if ((is_object($dateValue)) && ($dateValue instanceof self::$dateTimeObjectType)) {
  124. $retValue = self::FormattedPHPToExcel( $dateValue->format('Y'), $dateValue->format('m'), $dateValue->format('d'),
  125. $dateValue->format('H'), $dateValue->format('i'), $dateValue->format('s')
  126. );
  127. } elseif (is_numeric($dateValue)) {
  128. $retValue = self::FormattedPHPToExcel( date('Y',$dateValue), date('m',$dateValue), date('d',$dateValue),
  129. date('H',$dateValue), date('i',$dateValue), date('s',$dateValue)
  130. );
  131. }
  132. date_default_timezone_set($saveTimeZone);
  133. return $retValue;
  134. } // function PHPToExcel()
  135. /**
  136. * FormattedPHPToExcel
  137. *
  138. * @param long $year
  139. * @param long $month
  140. * @param long $day
  141. * @param long $hours
  142. * @param long $minutes
  143. * @param long $seconds
  144. * @return long Excel date/time value
  145. */
  146. public static function FormattedPHPToExcel($year, $month, $day, $hours=0, $minutes=0, $seconds=0) {
  147. if (self::$ExcelBaseDate == self::CALENDAR_WINDOWS_1900) {
  148. //
  149. // Fudge factor for the erroneous fact that the year 1900 is treated as a Leap Year in MS Excel
  150. // This affects every date following 28th February 1900
  151. //
  152. $excel1900isLeapYear = True;
  153. if (($year == 1900) && ($month <= 2)) { $excel1900isLeapYear = False; }
  154. $myExcelBaseDate = 2415020;
  155. } else {
  156. $myExcelBaseDate = 2416481;
  157. $excel1900isLeapYear = False;
  158. }
  159. // Julian base date Adjustment
  160. if ($month > 2) {
  161. $month = $month - 3;
  162. } else {
  163. $month = $month + 9;
  164. --$year;
  165. }
  166. // Calculate the Julian Date, then subtract the Excel base date (JD 2415020 = 31-Dec-1899 Giving Excel Date of 0)
  167. $century = substr($year,0,2);
  168. $decade = substr($year,2,2);
  169. $excelDate = floor((146097 * $century) / 4) + floor((1461 * $decade) / 4) + floor((153 * $month + 2) / 5) + $day + 1721119 - $myExcelBaseDate + $excel1900isLeapYear;
  170. $excelTime = (($hours * 3600) + ($minutes * 60) + $seconds) / 86400;
  171. return (float) $excelDate + $excelTime;
  172. } // function FormattedPHPToExcel()
  173. /**
  174. * Is a given cell a date/time?
  175. *
  176. * @param PHPExcel_Cell $pCell
  177. * @return boolean
  178. */
  179. public static function isDateTime(PHPExcel_Cell $pCell) {
  180. return self::isDateTimeFormat($pCell->getParent()->getStyle($pCell->getCoordinate())->getNumberFormat());
  181. } // function isDateTime()
  182. /**
  183. * Is a given number format a date/time?
  184. *
  185. * @param PHPExcel_Style_NumberFormat $pFormat
  186. * @return boolean
  187. */
  188. public static function isDateTimeFormat(PHPExcel_Style_NumberFormat $pFormat) {
  189. return self::isDateTimeFormatCode($pFormat->getFormatCode());
  190. } // function isDateTimeFormat()
  191. private static $possibleDateFormatCharacters = 'ymdHs';
  192. /**
  193. * Is a given number format code a date/time?
  194. *
  195. * @param string $pFormatCode
  196. * @return boolean
  197. */
  198. public static function isDateTimeFormatCode($pFormatCode = '') {
  199. // Switch on formatcode
  200. switch ($pFormatCode) {
  201. case PHPExcel_Style_NumberFormat::FORMAT_DATE_YYYYMMDD:
  202. case PHPExcel_Style_NumberFormat::FORMAT_DATE_YYYYMMDD2:
  203. case PHPExcel_Style_NumberFormat::FORMAT_DATE_DDMMYYYY:
  204. case PHPExcel_Style_NumberFormat::FORMAT_DATE_DMYSLASH:
  205. case PHPExcel_Style_NumberFormat::FORMAT_DATE_DMYMINUS:
  206. case PHPExcel_Style_NumberFormat::FORMAT_DATE_DMMINUS:
  207. case PHPExcel_Style_NumberFormat::FORMAT_DATE_MYMINUS:
  208. case PHPExcel_Style_NumberFormat::FORMAT_DATE_DATETIME:
  209. case PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME1:
  210. case PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME2:
  211. case PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME3:
  212. case PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME4:
  213. case PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME5:
  214. case PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME6:
  215. case PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME7:
  216. case PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME8:
  217. case PHPExcel_Style_NumberFormat::FORMAT_DATE_YYYYMMDDSLASH:
  218. case PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX14:
  219. case PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX15:
  220. case PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX16:
  221. case PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX17:
  222. case PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX22:
  223. return true;
  224. }
  225. // Typically number, currency or accounting (or occasionally fraction) formats
  226. if ((substr($pFormatCode,0,1) == '_') || (substr($pFormatCode,0,2) == '0 ')) {
  227. return false;
  228. }
  229. // Try checking for any of the date formatting characters that don't appear within square braces
  230. if (preg_match('/(^|\])[^\[]*['.self::$possibleDateFormatCharacters.']/i',$pFormatCode)) {
  231. // We might also have a format mask containing quoted strings...
  232. // we don't want to test for any of our characters within the quoted blocks
  233. if (strpos($pFormatCode,'"') !== false) {
  234. $i = false;
  235. foreach(explode('"',$pFormatCode) as $subVal) {
  236. // Only test in alternate array entries (the non-quoted blocks)
  237. if (($i = !$i) && (preg_match('/(^|\])[^\[]*['.self::$possibleDateFormatCharacters.']/i',$subVal))) {
  238. return true;
  239. }
  240. }
  241. return false;
  242. }
  243. return true;
  244. }
  245. // No date...
  246. return false;
  247. } // function isDateTimeFormatCode()
  248. /**
  249. * Convert a date/time string to Excel time
  250. *
  251. * @param string $dateValue Examples: '2009-12-31', '2009-12-31 15:59', '2009-12-31 15:59:10'
  252. * @return float|false Excel date/time serial value
  253. */
  254. public static function stringToExcel($dateValue = '') {
  255. if (strlen($dateValue) < 2)
  256. return false;
  257. if (!preg_match('/^(\d{1,4}[ \.\/\-][A-Z]{3,9}([ \.\/\-]\d{1,4})?|[A-Z]{3,9}[ \.\/\-]\d{1,4}([ \.\/\-]\d{1,4})?|\d{1,4}[ \.\/\-]\d{1,4}([ \.\/\-]\d{1,4})?)( \d{1,2}:\d{1,2}(:\d{1,2})?)?$/iu', $dateValue))
  258. return false;
  259. $dateValueNew = PHPExcel_Calculation_DateTime::DATEVALUE($dateValue);
  260. if ($dateValueNew === PHPExcel_Calculation_Functions::VALUE()) {
  261. return false;
  262. } else {
  263. if (strpos($dateValue, ':') !== false) {
  264. $timeValue = PHPExcel_Calculation_DateTime::TIMEVALUE($dateValue);
  265. if ($timeValue === PHPExcel_Calculation_Functions::VALUE()) {
  266. return false;
  267. }
  268. $dateValueNew += $timeValue;
  269. }
  270. return $dateValueNew;
  271. }
  272. }
  273. }