PageRenderTime 46ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/wp-content/plugins/the-events-calendar/src/Tribe/Timezones.php

https://gitlab.com/Suhailgit/Project
PHP | 472 lines | 213 code | 68 blank | 191 comment | 38 complexity | 9703323e2d5493a6aa75732e521bff8d MD5 | raw file
  1. <?php
  2. /**
  3. * Helpers for handling timezone based event datetimes.
  4. *
  5. * In our timezone logic, the term "local" refers to the locality of an event
  6. * rather than the local WordPress timezone.
  7. */
  8. class Tribe__Events__Timezones extends Tribe__Timezones {
  9. public static function init() {
  10. self::display_timezones();
  11. parent::init();
  12. }
  13. /**
  14. * Takes care of appending timezone information to the display of
  15. * event date/times.
  16. */
  17. protected static function display_timezones() {
  18. if ( tribe_get_option( 'tribe_events_timezones_show_zone' ) ) {
  19. add_filter( 'tribe_events_event_schedule_details_inner', array( __CLASS__, 'append_timezone' ), 10, 2 );
  20. }
  21. }
  22. /**
  23. * Adds the timezone to the event schedule information.
  24. *
  25. * @param string $schedule_text
  26. * @param int|null $event_id
  27. *
  28. * @return string
  29. */
  30. public static function append_timezone( $schedule_text, $event_id = null ) {
  31. static $hide_for_all_day;
  32. if ( ! isset( $hide_for_all_day ) ) {
  33. $hide_for_all_day = apply_filters( 'tribe_events_hide_timezone_for_all_day_events', true );
  34. }
  35. if ( tribe_event_is_all_day( $event_id ) && $hide_for_all_day ) {
  36. return $schedule_text;
  37. }
  38. $timezone = self::is_mode( 'site' )
  39. ? self::wp_timezone_abbr( tribe_get_start_date( $event_id, true, Tribe__Date_Utils::DBDATETIMEFORMAT ) )
  40. : self::get_event_timezone_abbr( $event_id );
  41. if ( ! empty( $timezone ) ) {
  42. $timezone_text = " <span class='timezone'> $timezone </span>";
  43. $schedule_text = $schedule_text . $timezone_text;
  44. }
  45. return $schedule_text;
  46. }
  47. /**
  48. * Returns the timezone string for the specified event (if null it assumes the
  49. * current event where that can be determined).
  50. *
  51. * If no timezone has explicitly been set for the event, it returns the global
  52. * WordPress timezone string.
  53. *
  54. * @param int|null $event_id
  55. *
  56. * @return string
  57. */
  58. public static function get_event_timezone_string( $event_id = null ) {
  59. $event_id = Tribe__Events__Main::postIdHelper( $event_id );
  60. $tzstring = get_post_meta( $event_id, '_EventTimezone', true );
  61. return $tzstring ? $tzstring : self::wp_timezone_string();
  62. }
  63. /**
  64. * Returns the event's timezone abbreviation if it can be determined, or else
  65. * falls back on the full timezone string/offset text (again, if known - if it
  66. * is not it will assume the global WP timezone setting).
  67. *
  68. * @param int|null $event_id
  69. *
  70. * @return string
  71. */
  72. public static function get_event_timezone_abbr( $event_id = null ) {
  73. $abbr = get_post_meta( $event_id, '_EventTimezoneAbbr', true );
  74. if ( empty( $abbr ) ) {
  75. $timezone_string = self::get_event_timezone_string( $event_id );
  76. $date = tribe_get_start_date( $event_id, true, Tribe__Date_Utils::DBDATETIMEFORMAT );
  77. $abbr = self::abbr( $date, $timezone_string );
  78. }
  79. return empty( $abbr )
  80. ? $timezone_string
  81. : $abbr;
  82. }
  83. /**
  84. * Returns the current site-wide timezone string.
  85. *
  86. * Based on the core WP code found in wp-admin/options-general.php.
  87. *
  88. * @return string
  89. */
  90. public static function wp_timezone_string() {
  91. $current_offset = get_option( 'gmt_offset' );
  92. $tzstring = get_option( 'timezone_string' );
  93. // Return the timezone string if already set
  94. if ( ! empty( $tzstring ) ) {
  95. return $tzstring;
  96. }
  97. // Otherwise return the UTC offset
  98. if ( 0 == $current_offset ) {
  99. return 'UTC+0';
  100. } elseif ( $current_offset < 0 ) {
  101. return 'UTC' . $current_offset;
  102. }
  103. return 'UTC+' . $current_offset;
  104. }
  105. /**
  106. * Returns the current site-wide timezone string abbreviation, if it can be
  107. * determined or falls back on the full timezone string/offset text.
  108. *
  109. * @param string $date
  110. *
  111. * @return string
  112. */
  113. public static function wp_timezone_abbr( $date ) {
  114. $abbr = get_transient( 'tribe_events_wp_timezone_abbr' );
  115. if ( empty( $abbr ) ) {
  116. $timezone_string = self::wp_timezone_string();
  117. $abbr = self::abbr( $date, $timezone_string );
  118. set_transient( 'tribe_events_wp_timezone_abbr', $abbr );
  119. }
  120. return empty( $abbr )
  121. ? $timezone_string
  122. : $abbr;
  123. }
  124. /**
  125. * Tried to convert the provided $datetime to UTC from the timezone represented by $tzstring.
  126. *
  127. * Though the usual range of formats are allowed, $datetime ordinarily ought to be something
  128. * like the "Y-m-d H:i:s" format (ie, no timezone information). If it itself contains timezone
  129. * data, the results may be unexpected.
  130. *
  131. * In those cases where the conversion fails to take place, the $datetime string will be
  132. * returned untouched.
  133. *
  134. * @param string $datetime
  135. * @param string $tzstring
  136. *
  137. * @return string
  138. */
  139. public static function to_utc( $datetime, $tzstring ) {
  140. if ( self::is_utc_offset( $tzstring ) ) {
  141. return self::apply_offset( $datetime, $tzstring, true );
  142. }
  143. $local = self::get_timezone( $tzstring );
  144. $utc = self::get_timezone( 'UTC' );
  145. $new_datetime = date_create( $datetime, $local );
  146. if ( $new_datetime && $new_datetime->setTimezone( $utc ) ) {
  147. return $new_datetime->format( Tribe__Date_Utils::DBDATETIMEFORMAT );
  148. }
  149. // Fallback to the unmodified datetime if there was a failure during conversion
  150. return $datetime;
  151. }
  152. /**
  153. * Tries to convert the provided $datetime to the timezone represented by $tzstring.
  154. *
  155. * This is the sister function of self::to_utc() - please review the docs for that method
  156. * for more information.
  157. *
  158. * @param string $datetime
  159. * @param string $tzstring
  160. *
  161. * @return string
  162. */
  163. public static function to_tz( $datetime, $tzstring ) {
  164. if ( self::is_utc_offset( $tzstring ) ) {
  165. return self::apply_offset( $datetime, $tzstring );
  166. }
  167. $local = self::get_timezone( $tzstring );
  168. $utc = self::get_timezone( 'UTC' );
  169. $new_datetime = date_create( $datetime, $utc );
  170. if ( $new_datetime && $new_datetime->setTimezone( $local ) ) {
  171. return $new_datetime->format( Tribe__Date_Utils::DBDATETIMEFORMAT );
  172. }
  173. // Fallback to the unmodified datetime if there was a failure during conversion
  174. return $datetime;
  175. }
  176. /**
  177. * Tests to see if the timezone string is a UTC offset, ie "UTC+2".
  178. *
  179. * @param string $timezone
  180. *
  181. * @return bool
  182. */
  183. public static function is_utc_offset( $timezone ) {
  184. $timezone = trim( $timezone );
  185. return ( 0 === strpos( $timezone, 'UTC' ) && strlen( $timezone ) > 3 );
  186. }
  187. /**
  188. * @param string $datetime
  189. * @param mixed $offset (string or numeric offset)
  190. * @param bool $invert = false
  191. *
  192. * @return string
  193. */
  194. public static function apply_offset( $datetime, $offset, $invert = false ) {
  195. // Normalize
  196. $offset = strtolower( trim( $offset ) );
  197. // Strip any leading "utc" text if set
  198. if ( 0 === strpos( $offset, 'utc' ) ) {
  199. $offset = substr( $offset, 3 );
  200. }
  201. // It's possible no adjustment will be needed
  202. if ( 0 === $offset ) {
  203. return $datetime;
  204. }
  205. // Convert the offset to minutes for easier handling of fractional offsets
  206. $offset = (int) ( $offset * 60 );
  207. // Invert the offset? Useful for stripping an offset that has already been applied
  208. if ( $invert ) {
  209. $offset *= -1;
  210. }
  211. if ( $offset > 0 ) {
  212. $offset = '+' . $offset;
  213. }
  214. $offset = $offset . ' minutes';
  215. $offset_datetime = date_create( $datetime );
  216. if ( $offset_datetime && $offset_datetime->modify( $offset ) ) {
  217. return $offset_datetime->format( Tribe__Date_Utils::DBDATETIMEFORMAT );
  218. }
  219. return $datetime;
  220. }
  221. /**
  222. * Returns a timestamp for the event start date that can be passed to tribe_format_date()
  223. * in order to produce the time in the correct timezone.
  224. *
  225. * @param int $event_id
  226. * @param string $timezone
  227. *
  228. * @return int
  229. */
  230. public static function event_start_timestamp( $event_id, $timezone = null ) {
  231. return self::get_event_timestamp( $event_id, 'Start', $timezone );
  232. }
  233. /**
  234. * Returns a timestamp for the event end date that can be passed to tribe_format_date()
  235. * in order to produce the time in the correct timezone.
  236. *
  237. * @param int $event_id
  238. * @param string $timezone
  239. *
  240. * @return int
  241. */
  242. public static function event_end_timestamp( $event_id, $timezone = null ) {
  243. return self::get_event_timestamp( $event_id, 'End', $timezone );
  244. }
  245. /**
  246. * Returns a timestamp for the event date that can be passed to tribe_format_date()
  247. * in order to produce the time in the correct timezone.
  248. *
  249. * @param int $event_id
  250. * @param string $type (expected to be 'Start' or 'End')
  251. * @param string $timezone
  252. *
  253. * @return int
  254. */
  255. protected static function get_event_timestamp( $event_id, $type = 'Start', $timezone = null ) {
  256. $event = get_post( Tribe__Events__Main::postIdHelper( $event_id ) );
  257. $event_tz = get_post_meta( $event->ID, '_EventTimezone', true );
  258. $site_tz = self::wp_timezone_string();
  259. if ( null === $timezone ) {
  260. $timezone = self::mode();
  261. }
  262. // Should we use the event specific timezone or the site-wide timezone?
  263. $use_event_tz = self::EVENT_TIMEZONE === $timezone;
  264. $use_site_tz = self::SITE_TIMEZONE === $timezone;
  265. // Determine if the event timezone and site timezone the same *or* if the event does not have timezone
  266. // information (in which case, we'll assume the event time inherits the site timezone)
  267. $site_zone_is_event_zone = ( $event_tz === $site_tz || empty( $event_tz ) );
  268. // If the event-specific timezone is suitable, we can obtain it without any conversion work
  269. if ( $use_event_tz || ( $use_site_tz && $site_zone_is_event_zone ) ) {
  270. $datetime = get_post_meta( $event->ID, "_Event{$type}Date", true );
  271. return strtotime( $datetime );
  272. }
  273. // Otherwise lets load the event's UTC time and convert it
  274. $datetime = isset( $event->{"Event{$type}DateUTC"} )
  275. ? $event->{"Event{$type}DateUTC"}
  276. : get_post_meta( $event->ID, "_Event{$type}DateUTC", true );
  277. $tzstring = ( self::SITE_TIMEZONE === $timezone )
  278. ? self::wp_timezone_string()
  279. : $timezone;
  280. $localized = self::to_tz( $datetime, $tzstring );
  281. return strtotime( $localized );
  282. }
  283. /**
  284. * Accepts a unix timestamp and adjusts it so that when it is used to consitute
  285. * a new datetime string, that string reflects the designated timezone.
  286. *
  287. * @param string $unix_timestamp
  288. * @param string $tzstring
  289. *
  290. * @return string
  291. */
  292. public static function adjust_timestamp( $unix_timestamp, $tzstring ) {
  293. try {
  294. $local = self::get_timezone( $tzstring );
  295. $datetime = date_create_from_format( 'U', $unix_timestamp )->format( Tribe__Date_Utils::DBDATETIMEFORMAT );
  296. return date_create_from_format( 'Y-m-d H:i:s', $datetime, $local )->getTimestamp();
  297. }
  298. catch( Exception $e ) {
  299. return $unix_timestamp;
  300. }
  301. }
  302. /**
  303. * Returns a DateTimeZone object matching the representation in $tzstring where
  304. * possible, or else representing UTC (or, in the worst case, false).
  305. *
  306. * If optional parameter $with_fallback is true, which is the default, then in
  307. * the event it cannot find/create the desired timezone it will try to return the
  308. * UTC DateTimeZone before bailing.
  309. *
  310. * @param string $tzstring
  311. * @param bool $with_fallback = true
  312. *
  313. * @return DateTimeZone|false
  314. */
  315. public static function get_timezone( $tzstring, $with_fallback = true ) {
  316. if ( isset( self::$timezones[ $tzstring ] ) ) {
  317. return self::$timezones[ $tzstring ];
  318. }
  319. try {
  320. self::$timezones[ $tzstring ] = new DateTimeZone( $tzstring );
  321. return self::$timezones[ $tzstring ];
  322. }
  323. catch ( Exception $e ) {
  324. if ( $with_fallback ) {
  325. return self::get_timezone( 'UTC', true );
  326. }
  327. }
  328. return false;
  329. }
  330. /**
  331. * Returns a string representing the timezone/offset currently desired for
  332. * the display of dates and times.
  333. *
  334. * @return string
  335. */
  336. public static function mode() {
  337. $mode = self::EVENT_TIMEZONE;
  338. if ( 'site' === tribe_get_option( 'tribe_events_timezone_mode' ) ) {
  339. $mode = self::SITE_TIMEZONE;
  340. }
  341. return apply_filters( 'tribe_events_current_display_timezone', $mode );
  342. }
  343. /**
  344. * Confirms if the current timezone mode matches the $possible_mode.
  345. *
  346. * @param string $possible_mode
  347. *
  348. * @return bool
  349. */
  350. public static function is_mode( $possible_mode ) {
  351. return $possible_mode === self::mode();
  352. }
  353. /**
  354. * Attempts to provide the correct timezone abbreviation for the provided timezone string
  355. * on the date given (and so should account for daylight saving time, etc).
  356. *
  357. * @param string $date
  358. * @param string $timezone_string
  359. *
  360. * @return string
  361. */
  362. public static function abbr( $date, $timezone_string ) {
  363. try {
  364. $tz_date = date_create( $date, new DateTimeZone( $timezone_string ) );
  365. return $tz_date->format( 'T' );
  366. }
  367. catch ( Exception $e ) {
  368. return '';
  369. }
  370. }
  371. /**
  372. * Try to figure out the Timezone name base on offset
  373. *
  374. * @since 4.0.7
  375. * @param string|int|float $timezone The timezone
  376. *
  377. * @return string The Guessed Timezone String
  378. */
  379. public static function maybe_get_tz_name( $timezone ) {
  380. if ( ! self::is_utc_offset( $timezone ) && ! is_numeric( $timezone ) ) {
  381. return $timezone;
  382. }
  383. if ( ! is_numeric( $timezone ) ) {
  384. $offset = str_replace( 'utc', '', trim( strtolower( $timezone ) ) );
  385. } else {
  386. $offset = $timezone;
  387. }
  388. // try to get timezone from gmt_offset, respecting daylight savings
  389. $timezone = timezone_name_from_abbr( null, $offset * 3600, true );
  390. // if that didn't work, maybe they don't have daylight savings
  391. if ( false === $timezone ) {
  392. $timezone = timezone_name_from_abbr( null, $offset * 3600, false );
  393. }
  394. // and if THAT didn't work, round the gmt_offset down and then try to get the timezone respecting daylight savings
  395. if ( false === $timezone ) {
  396. $timezone = timezone_name_from_abbr( null, (int) $offset * 3600, true );
  397. }
  398. // lastly if that didn't work, round the gmt_offset down and maybe that TZ doesn't do daylight savings
  399. if ( false === $timezone ) {
  400. $timezone = timezone_name_from_abbr( null, (int) $offset * 3600, false );
  401. }
  402. return $timezone;
  403. }
  404. }