DateHelper.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532
  1. <?php
  2. namespace Drupal\Core\Datetime;
  3. /**
  4. * Defines Gregorian Calendar date values.
  5. *
  6. * Lots of helpful functions for use in massaging dates, specific to the
  7. * Gregorian calendar system. The values include both translated and
  8. * untranslated values.
  9. *
  10. * Untranslated values are useful as array keys and as css identifiers, and
  11. * should be listed in English.
  12. *
  13. * Translated values are useful for display to the user. All values that need
  14. * translation should be hard-coded and wrapped in t() so the translation system
  15. * will be able to process them.
  16. */
  17. class DateHelper {
  18. /**
  19. * Constructs an untranslated array of month names.
  20. *
  21. * @return array
  22. * An array of month names.
  23. */
  24. public static function monthNamesUntranslated() {
  25. // Force the key to use the correct month value, rather than
  26. // starting with zero.
  27. return [
  28. 1 => 'January',
  29. 2 => 'February',
  30. 3 => 'March',
  31. 4 => 'April',
  32. 5 => 'May',
  33. 6 => 'June',
  34. 7 => 'July',
  35. 8 => 'August',
  36. 9 => 'September',
  37. 10 => 'October',
  38. 11 => 'November',
  39. 12 => 'December',
  40. ];
  41. }
  42. /**
  43. * Constructs an untranslated array of abbreviated month names.
  44. *
  45. * @return array
  46. * An array of month names.
  47. */
  48. public static function monthNamesAbbrUntranslated() {
  49. // Force the key to use the correct month value, rather than
  50. // starting with zero.
  51. return [
  52. 1 => 'Jan',
  53. 2 => 'Feb',
  54. 3 => 'Mar',
  55. 4 => 'Apr',
  56. 5 => 'May',
  57. 6 => 'Jun',
  58. 7 => 'Jul',
  59. 8 => 'Aug',
  60. 9 => 'Sep',
  61. 10 => 'Oct',
  62. 11 => 'Nov',
  63. 12 => 'Dec',
  64. ];
  65. }
  66. /**
  67. * Returns a translated array of month names.
  68. *
  69. * @param bool $required
  70. * (optional) If FALSE, the returned array will include a blank value.
  71. * Defaults to FALSE.
  72. *
  73. * @return array
  74. * An array of month names.
  75. */
  76. public static function monthNames($required = FALSE) {
  77. // Force the key to use the correct month value, rather than
  78. // starting with zero.
  79. $monthnames = [
  80. 1 => t('January', [], ['context' => 'Long month name']),
  81. 2 => t('February', [], ['context' => 'Long month name']),
  82. 3 => t('March', [], ['context' => 'Long month name']),
  83. 4 => t('April', [], ['context' => 'Long month name']),
  84. 5 => t('May', [], ['context' => 'Long month name']),
  85. 6 => t('June', [], ['context' => 'Long month name']),
  86. 7 => t('July', [], ['context' => 'Long month name']),
  87. 8 => t('August', [], ['context' => 'Long month name']),
  88. 9 => t('September', [], ['context' => 'Long month name']),
  89. 10 => t('October', [], ['context' => 'Long month name']),
  90. 11 => t('November', [], ['context' => 'Long month name']),
  91. 12 => t('December', [], ['context' => 'Long month name']),
  92. ];
  93. $none = ['' => ''];
  94. return !$required ? $none + $monthnames : $monthnames;
  95. }
  96. /**
  97. * Constructs a translated array of month name abbreviations
  98. *
  99. * @param bool $required
  100. * (optional) If FALSE, the returned array will include a blank value.
  101. * Defaults to FALSE.
  102. *
  103. * @return array
  104. * An array of month abbreviations.
  105. */
  106. public static function monthNamesAbbr($required = FALSE) {
  107. // Force the key to use the correct month value, rather than
  108. // starting with zero.
  109. $monthnames = [
  110. 1 => t('Jan', [], ['context' => 'Abbreviated month name']),
  111. 2 => t('Feb', [], ['context' => 'Abbreviated month name']),
  112. 3 => t('Mar', [], ['context' => 'Abbreviated month name']),
  113. 4 => t('Apr', [], ['context' => 'Abbreviated month name']),
  114. 5 => t('May', [], ['context' => 'Abbreviated month name']),
  115. 6 => t('Jun', [], ['context' => 'Abbreviated month name']),
  116. 7 => t('Jul', [], ['context' => 'Abbreviated month name']),
  117. 8 => t('Aug', [], ['context' => 'Abbreviated month name']),
  118. 9 => t('Sep', [], ['context' => 'Abbreviated month name']),
  119. 10 => t('Oct', [], ['context' => 'Abbreviated month name']),
  120. 11 => t('Nov', [], ['context' => 'Abbreviated month name']),
  121. 12 => t('Dec', [], ['context' => 'Abbreviated month name']),
  122. ];
  123. $none = ['' => ''];
  124. return !$required ? $none + $monthnames : $monthnames;
  125. }
  126. /**
  127. * Constructs an untranslated array of week days.
  128. *
  129. * @return array
  130. * An array of week day names
  131. */
  132. public static function weekDaysUntranslated() {
  133. return [
  134. 'Sunday',
  135. 'Monday',
  136. 'Tuesday',
  137. 'Wednesday',
  138. 'Thursday',
  139. 'Friday',
  140. 'Saturday',
  141. ];
  142. }
  143. /**
  144. * Returns a translated array of week names.
  145. *
  146. * @param bool $required
  147. * (optional) If FALSE, the returned array will include a blank value.
  148. * Defaults to FALSE.
  149. *
  150. * @return array
  151. * An array of week day names
  152. */
  153. public static function weekDays($required = FALSE) {
  154. $weekdays = [
  155. t('Sunday'),
  156. t('Monday'),
  157. t('Tuesday'),
  158. t('Wednesday'),
  159. t('Thursday'),
  160. t('Friday'),
  161. t('Saturday'),
  162. ];
  163. $none = ['' => ''];
  164. return !$required ? $none + $weekdays : $weekdays;
  165. }
  166. /**
  167. * Constructs a translated array of week day abbreviations.
  168. *
  169. * @param bool $required
  170. * (optional) If FALSE, the returned array will include a blank value.
  171. * Defaults to FALSE.
  172. *
  173. * @return array
  174. * An array of week day abbreviations
  175. */
  176. public static function weekDaysAbbr($required = FALSE) {
  177. $weekdays = [
  178. t('Sun', [], ['context' => 'Abbreviated weekday']),
  179. t('Mon', [], ['context' => 'Abbreviated weekday']),
  180. t('Tue', [], ['context' => 'Abbreviated weekday']),
  181. t('Wed', [], ['context' => 'Abbreviated weekday']),
  182. t('Thu', [], ['context' => 'Abbreviated weekday']),
  183. t('Fri', [], ['context' => 'Abbreviated weekday']),
  184. t('Sat', [], ['context' => 'Abbreviated weekday']),
  185. ];
  186. $none = ['' => ''];
  187. return !$required ? $none + $weekdays : $weekdays;
  188. }
  189. /**
  190. * Constructs a translated array of 2-letter week day abbreviations.
  191. *
  192. * @param bool $required
  193. * (optional) If FALSE, the returned array will include a blank value.
  194. * Defaults to FALSE.
  195. *
  196. * @return array
  197. * An array of week day 2 letter abbreviations
  198. */
  199. public static function weekDaysAbbr2($required = FALSE) {
  200. $weekdays = [
  201. t('Su', [], ['context' => 'Abbreviated weekday']),
  202. t('Mo', [], ['context' => 'Abbreviated weekday']),
  203. t('Tu', [], ['context' => 'Abbreviated weekday']),
  204. t('We', [], ['context' => 'Abbreviated weekday']),
  205. t('Th', [], ['context' => 'Abbreviated weekday']),
  206. t('Fr', [], ['context' => 'Abbreviated weekday']),
  207. t('Sa', [], ['context' => 'Abbreviated weekday']),
  208. ];
  209. $none = ['' => ''];
  210. return !$required ? $none + $weekdays : $weekdays;
  211. }
  212. /**
  213. * Constructs a translated array of 1-letter week day abbreviations.
  214. *
  215. * @param bool $required
  216. * (optional) If FALSE, the returned array will include a blank value.
  217. * Defaults to FALSE.
  218. *
  219. * @return array
  220. * An array of week day 1 letter abbreviations
  221. */
  222. public static function weekDaysAbbr1($required = FALSE) {
  223. $weekdays = [
  224. t('S', [], ['context' => 'Abbreviated 1 letter weekday Sunday']),
  225. t('M', [], ['context' => 'Abbreviated 1 letter weekday Monday']),
  226. t('T', [], ['context' => 'Abbreviated 1 letter weekday Tuesday']),
  227. t('W', [], ['context' => 'Abbreviated 1 letter weekday Wednesday']),
  228. t('T', [], ['context' => 'Abbreviated 1 letter weekday Thursday']),
  229. t('F', [], ['context' => 'Abbreviated 1 letter weekday Friday']),
  230. t('S', [], ['context' => 'Abbreviated 1 letter weekday Saturday']),
  231. ];
  232. $none = ['' => ''];
  233. return !$required ? $none + $weekdays : $weekdays;
  234. }
  235. /**
  236. * Reorders weekdays to match the first day of the week.
  237. *
  238. * @param array $weekdays
  239. * An array of weekdays.
  240. *
  241. * @return array
  242. * An array of weekdays reordered to match the first day of the week. The
  243. * keys will remain unchanged. For example, if the first day of the week is
  244. * set to be Monday, the array keys will be [1, 2, 3, 4, 5, 6, 0].
  245. */
  246. public static function weekDaysOrdered($weekdays) {
  247. $first_day = \Drupal::config('system.date')->get('first_day');
  248. if ($first_day > 0) {
  249. for ($i = 1; $i <= $first_day; $i++) {
  250. // Reset the array to the first element.
  251. reset($weekdays);
  252. // Retrieve the first week day value.
  253. $last = current($weekdays);
  254. // Store the corresponding key.
  255. $key = key($weekdays);
  256. // Remove this week day from the beginning of the array.
  257. unset($weekdays[$key]);
  258. // Add this week day to the end of the array.
  259. $weekdays[$key] = $last;
  260. }
  261. }
  262. return $weekdays;
  263. }
  264. /**
  265. * Constructs an array of years in a specified range.
  266. *
  267. * @param int $min
  268. * (optional) The minimum year in the array. Defaults to zero.
  269. * @param int $max
  270. * (optional) The maximum year in the array. Defaults to zero.
  271. * @param bool $required
  272. * (optional) If FALSE, the returned array will include a blank value.
  273. * Defaults to FALSE.
  274. *
  275. * @return array
  276. * An array of years in the selected range.
  277. */
  278. public static function years($min = 0, $max = 0, $required = FALSE) {
  279. // Ensure $min and $max are valid values.
  280. if (empty($min)) {
  281. $min = intval(date('Y', REQUEST_TIME) - 3);
  282. }
  283. if (empty($max)) {
  284. $max = intval(date('Y', REQUEST_TIME) + 3);
  285. }
  286. $none = ['' => ''];
  287. $range = range($min, $max);
  288. $range = array_combine($range, $range);
  289. return !$required ? $none + $range : $range;
  290. }
  291. /**
  292. * Constructs an array of days in a month.
  293. *
  294. * @param bool $required
  295. * (optional) If FALSE, the returned array will include a blank value.
  296. * Defaults to FALSE.
  297. * @param int $month
  298. * (optional) The month in which to find the number of days. Defaults to
  299. * NULL.
  300. * @param int $year
  301. * (optional) The year in which to find the number of days. Defaults to
  302. * NULL.
  303. *
  304. * @return array
  305. * An array of days for the selected month.
  306. */
  307. public static function days($required = FALSE, $month = NULL, $year = NULL) {
  308. // If we have a month and year, find the right last day of the month.
  309. if (!empty($month) && !empty($year)) {
  310. $date = new DrupalDateTime($year . '-' . $month . '-01 00:00:00', 'UTC');
  311. $max = $date->format('t');
  312. }
  313. // If there is no month and year given, default to 31.
  314. if (empty($max)) {
  315. $max = 31;
  316. }
  317. $none = ['' => ''];
  318. $range = range(1, $max);
  319. $range = array_combine($range, $range);
  320. return !$required ? $none + $range : $range;
  321. }
  322. /**
  323. * Constructs an array of hours.
  324. *
  325. * @param string $format
  326. * (optional) A date format string that indicates the format to use for the
  327. * hours. Defaults to 'H'.
  328. * @param bool $required
  329. * (optional) If FALSE, the returned array will include a blank value.
  330. * Defaults to FALSE.
  331. *
  332. * @return array
  333. * An array of hours in the selected format.
  334. */
  335. public static function hours($format = 'H', $required = FALSE) {
  336. $hours = [];
  337. if ($format == 'h' || $format == 'g') {
  338. $min = 1;
  339. $max = 12;
  340. }
  341. else {
  342. $min = 0;
  343. $max = 23;
  344. }
  345. for ($i = $min; $i <= $max; $i++) {
  346. $formatted = ($format == 'H' || $format == 'h') ? DrupalDateTime::datePad($i) : $i;
  347. $hours[$i] = $formatted;
  348. }
  349. $none = ['' => ''];
  350. return !$required ? $none + $hours : $hours;
  351. }
  352. /**
  353. * Constructs an array of minutes.
  354. *
  355. * @param string $format
  356. * (optional) A date format string that indicates the format to use for the
  357. * minutes. Defaults to 'i'.
  358. * @param bool $required
  359. * (optional) If FALSE, the returned array will include a blank value.
  360. * Defaults to FALSE.
  361. * @param int $increment
  362. * An integer value to increment the values. Defaults to 1.
  363. *
  364. * @return array
  365. * An array of minutes in the selected format.
  366. */
  367. public static function minutes($format = 'i', $required = FALSE, $increment = 1) {
  368. $minutes = [];
  369. // Ensure $increment has a value so we don't loop endlessly.
  370. if (empty($increment)) {
  371. $increment = 1;
  372. }
  373. for ($i = 0; $i < 60; $i += $increment) {
  374. $formatted = $format == 'i' ? DrupalDateTime::datePad($i) : $i;
  375. $minutes[$i] = $formatted;
  376. }
  377. $none = ['' => ''];
  378. return !$required ? $none + $minutes : $minutes;
  379. }
  380. /**
  381. * Constructs an array of seconds.
  382. *
  383. * @param string $format
  384. * (optional) A date format string that indicates the format to use for the
  385. * seconds. Defaults to 's'.
  386. * @param bool $required
  387. * (optional) If FALSE, the returned array will include a blank value.
  388. * Defaults to FALSE.
  389. * @param int $increment
  390. * An integer value to increment the values. Defaults to 1.
  391. *
  392. * @return array
  393. * An array of seconds in the selected format.
  394. */
  395. public static function seconds($format = 's', $required = FALSE, $increment = 1) {
  396. $seconds = [];
  397. // Ensure $increment has a value so we don't loop endlessly.
  398. if (empty($increment)) {
  399. $increment = 1;
  400. }
  401. for ($i = 0; $i < 60; $i += $increment) {
  402. $formatted = $format == 's' ? DrupalDateTime::datePad($i) : $i;
  403. $seconds[$i] = $formatted;
  404. }
  405. $none = ['' => ''];
  406. return !$required ? $none + $seconds : $seconds;
  407. }
  408. /**
  409. * Constructs an array of AM and PM options.
  410. *
  411. * @param bool $required
  412. * (optional) If FALSE, the returned array will include a blank value.
  413. * Defaults to FALSE.
  414. *
  415. * @return array
  416. * An array of AM and PM options.
  417. */
  418. public static function ampm($required = FALSE) {
  419. $none = ['' => ''];
  420. $ampm = [
  421. 'am' => t('am', [], ['context' => 'ampm']),
  422. 'pm' => t('pm', [], ['context' => 'ampm']),
  423. ];
  424. return !$required ? $none + $ampm : $ampm;
  425. }
  426. /**
  427. * Identifies the number of days in a month for a date.
  428. *
  429. * @param mixed $date
  430. * (optional) A DrupalDateTime object or a date string.
  431. * Defaults to NULL, which means to use the current date.
  432. *
  433. * @return int
  434. * The number of days in the month.
  435. */
  436. public static function daysInMonth($date = NULL) {
  437. if (!$date instanceof DrupalDateTime) {
  438. $date = new DrupalDateTime($date);
  439. }
  440. if (!$date->hasErrors()) {
  441. return $date->format('t');
  442. }
  443. return NULL;
  444. }
  445. /**
  446. * Identifies the number of days in a year for a date.
  447. *
  448. * @param mixed $date
  449. * (optional) A DrupalDateTime object or a date string.
  450. * Defaults to NULL, which means to use the current date.
  451. *
  452. * @return int
  453. * The number of days in the year.
  454. */
  455. public static function daysInYear($date = NULL) {
  456. if (!$date instanceof DrupalDateTime) {
  457. $date = new DrupalDateTime($date);
  458. }
  459. if (!$date->hasErrors()) {
  460. if ($date->format('L')) {
  461. return 366;
  462. }
  463. else {
  464. return 365;
  465. }
  466. }
  467. return NULL;
  468. }
  469. /**
  470. * Returns day of week for a given date (0 = Sunday).
  471. *
  472. * @param mixed $date
  473. * (optional) A DrupalDateTime object or a date string.
  474. * Defaults to NULL, which means use the current date.
  475. *
  476. * @return int
  477. * The number of the day in the week.
  478. */
  479. public static function dayOfWeek($date = NULL) {
  480. if (!$date instanceof DrupalDateTime) {
  481. $date = new DrupalDateTime($date);
  482. }
  483. if (!$date->hasErrors()) {
  484. return $date->format('w');
  485. }
  486. return NULL;
  487. }
  488. /**
  489. * Returns translated name of the day of week for a given date.
  490. *
  491. * @param mixed $date
  492. * (optional) A DrupalDateTime object or a date string.
  493. * Defaults to NULL, which means use the current date.
  494. * @param string $abbr
  495. * (optional) Whether to return the abbreviated name for that day.
  496. * Defaults to TRUE.
  497. *
  498. * @return string
  499. * The name of the day in the week for that date.
  500. */
  501. public static function dayOfWeekName($date = NULL, $abbr = TRUE) {
  502. if (!$date instanceof DrupalDateTime) {
  503. $date = new DrupalDateTime($date);
  504. }
  505. $dow = self::dayOfWeek($date);
  506. $days = $abbr ? self::weekDaysAbbr() : self::weekDays();
  507. return $days[$dow];
  508. }
  509. }