Completed
Branch BUG/11233/timezone-offsets (51b4f3)
by
unknown
74:31 queued 63:01
created
espresso.php 1 patch
Indentation   +192 added lines, -192 removed lines patch added patch discarded remove patch
@@ -38,217 +38,217 @@
 block discarded – undo
38 38
  * @since       4.0
39 39
  */
40 40
 if (function_exists('espresso_version')) {
41
-    if (! function_exists('espresso_duplicate_plugin_error')) {
42
-        /**
43
-         *    espresso_duplicate_plugin_error
44
-         *    displays if more than one version of EE is activated at the same time
45
-         */
46
-        function espresso_duplicate_plugin_error()
47
-        {
48
-            ?>
41
+	if (! function_exists('espresso_duplicate_plugin_error')) {
42
+		/**
43
+		 *    espresso_duplicate_plugin_error
44
+		 *    displays if more than one version of EE is activated at the same time
45
+		 */
46
+		function espresso_duplicate_plugin_error()
47
+		{
48
+			?>
49 49
             <div class="error">
50 50
                 <p>
51 51
                     <?php
52
-                    echo esc_html__(
53
-                        'Can not run multiple versions of Event Espresso! One version has been automatically deactivated. Please verify that you have the correct version you want still active.',
54
-                        'event_espresso'
55
-                    ); ?>
52
+					echo esc_html__(
53
+						'Can not run multiple versions of Event Espresso! One version has been automatically deactivated. Please verify that you have the correct version you want still active.',
54
+						'event_espresso'
55
+					); ?>
56 56
                 </p>
57 57
             </div>
58 58
             <?php
59
-            espresso_deactivate_plugin(plugin_basename(__FILE__));
60
-        }
61
-    }
62
-    add_action('admin_notices', 'espresso_duplicate_plugin_error', 1);
59
+			espresso_deactivate_plugin(plugin_basename(__FILE__));
60
+		}
61
+	}
62
+	add_action('admin_notices', 'espresso_duplicate_plugin_error', 1);
63 63
 
64 64
 } else {
65
-    define('EE_MIN_PHP_VER_REQUIRED', '5.3.9');
66
-    if (! version_compare(PHP_VERSION, EE_MIN_PHP_VER_REQUIRED, '>=')) {
67
-        /**
68
-         * espresso_minimum_php_version_error
69
-         *
70
-         * @return void
71
-         */
72
-        function espresso_minimum_php_version_error()
73
-        {
74
-            ?>
65
+	define('EE_MIN_PHP_VER_REQUIRED', '5.3.9');
66
+	if (! version_compare(PHP_VERSION, EE_MIN_PHP_VER_REQUIRED, '>=')) {
67
+		/**
68
+		 * espresso_minimum_php_version_error
69
+		 *
70
+		 * @return void
71
+		 */
72
+		function espresso_minimum_php_version_error()
73
+		{
74
+			?>
75 75
             <div class="error">
76 76
                 <p>
77 77
                     <?php
78
-                    printf(
79
-                        esc_html__(
80
-                            'We\'re sorry, but Event Espresso requires PHP version %1$s or greater in order to operate. You are currently running version %2$s.%3$sIn order to update your version of PHP, you will need to contact your current hosting provider.%3$sFor information on stable PHP versions, please go to %4$s.',
81
-                            'event_espresso'
82
-                        ),
83
-                        EE_MIN_PHP_VER_REQUIRED,
84
-                        PHP_VERSION,
85
-                        '<br/>',
86
-                        '<a href="http://php.net/downloads.php">http://php.net/downloads.php</a>'
87
-                    );
88
-                    ?>
78
+					printf(
79
+						esc_html__(
80
+							'We\'re sorry, but Event Espresso requires PHP version %1$s or greater in order to operate. You are currently running version %2$s.%3$sIn order to update your version of PHP, you will need to contact your current hosting provider.%3$sFor information on stable PHP versions, please go to %4$s.',
81
+							'event_espresso'
82
+						),
83
+						EE_MIN_PHP_VER_REQUIRED,
84
+						PHP_VERSION,
85
+						'<br/>',
86
+						'<a href="http://php.net/downloads.php">http://php.net/downloads.php</a>'
87
+					);
88
+					?>
89 89
                 </p>
90 90
             </div>
91 91
             <?php
92
-            espresso_deactivate_plugin(plugin_basename(__FILE__));
93
-        }
92
+			espresso_deactivate_plugin(plugin_basename(__FILE__));
93
+		}
94 94
 
95
-        add_action('admin_notices', 'espresso_minimum_php_version_error', 1);
96
-    } else {
97
-        define('EVENT_ESPRESSO_MAIN_FILE', __FILE__);
98
-        /**
99
-         * espresso_version
100
-         * Returns the plugin version
101
-         *
102
-         * @return string
103
-         */
104
-        function espresso_version()
105
-        {
106
-            return apply_filters('FHEE__espresso__espresso_version', '4.9.54.rc.010');
107
-        }
95
+		add_action('admin_notices', 'espresso_minimum_php_version_error', 1);
96
+	} else {
97
+		define('EVENT_ESPRESSO_MAIN_FILE', __FILE__);
98
+		/**
99
+		 * espresso_version
100
+		 * Returns the plugin version
101
+		 *
102
+		 * @return string
103
+		 */
104
+		function espresso_version()
105
+		{
106
+			return apply_filters('FHEE__espresso__espresso_version', '4.9.54.rc.010');
107
+		}
108 108
 
109
-        /**
110
-         * espresso_plugin_activation
111
-         * adds a wp-option to indicate that EE has been activated via the WP admin plugins page
112
-         */
113
-        function espresso_plugin_activation()
114
-        {
115
-            update_option('ee_espresso_activation', true);
116
-        }
109
+		/**
110
+		 * espresso_plugin_activation
111
+		 * adds a wp-option to indicate that EE has been activated via the WP admin plugins page
112
+		 */
113
+		function espresso_plugin_activation()
114
+		{
115
+			update_option('ee_espresso_activation', true);
116
+		}
117 117
 
118
-        register_activation_hook(EVENT_ESPRESSO_MAIN_FILE, 'espresso_plugin_activation');
119
-        /**
120
-         *    espresso_load_error_handling
121
-         *    this function loads EE's class for handling exceptions and errors
122
-         */
123
-        function espresso_load_error_handling()
124
-        {
125
-            static $error_handling_loaded = false;
126
-            if ($error_handling_loaded) {
127
-                return;
128
-            }
129
-            // load debugging tools
130
-            if (WP_DEBUG === true && is_readable(EE_HELPERS . 'EEH_Debug_Tools.helper.php')) {
131
-                require_once   EE_HELPERS . 'EEH_Debug_Tools.helper.php';
132
-                \EEH_Debug_Tools::instance();
133
-            }
134
-            // load error handling
135
-            if (is_readable(EE_CORE . 'EE_Error.core.php')) {
136
-                require_once EE_CORE . 'EE_Error.core.php';
137
-            } else {
138
-                wp_die(esc_html__('The EE_Error core class could not be loaded.', 'event_espresso'));
139
-            }
140
-            $error_handling_loaded = true;
141
-        }
118
+		register_activation_hook(EVENT_ESPRESSO_MAIN_FILE, 'espresso_plugin_activation');
119
+		/**
120
+		 *    espresso_load_error_handling
121
+		 *    this function loads EE's class for handling exceptions and errors
122
+		 */
123
+		function espresso_load_error_handling()
124
+		{
125
+			static $error_handling_loaded = false;
126
+			if ($error_handling_loaded) {
127
+				return;
128
+			}
129
+			// load debugging tools
130
+			if (WP_DEBUG === true && is_readable(EE_HELPERS . 'EEH_Debug_Tools.helper.php')) {
131
+				require_once   EE_HELPERS . 'EEH_Debug_Tools.helper.php';
132
+				\EEH_Debug_Tools::instance();
133
+			}
134
+			// load error handling
135
+			if (is_readable(EE_CORE . 'EE_Error.core.php')) {
136
+				require_once EE_CORE . 'EE_Error.core.php';
137
+			} else {
138
+				wp_die(esc_html__('The EE_Error core class could not be loaded.', 'event_espresso'));
139
+			}
140
+			$error_handling_loaded = true;
141
+		}
142 142
 
143
-        /**
144
-         *    espresso_load_required
145
-         *    given a class name and path, this function will load that file or throw an exception
146
-         *
147
-         * @param    string $classname
148
-         * @param    string $full_path_to_file
149
-         * @throws    EE_Error
150
-         */
151
-        function espresso_load_required($classname, $full_path_to_file)
152
-        {
153
-            if (is_readable($full_path_to_file)) {
154
-                require_once $full_path_to_file;
155
-            } else {
156
-                throw new \EE_Error (
157
-                    sprintf(
158
-                        esc_html__(
159
-                            'The %s class file could not be located or is not readable due to file permissions.',
160
-                            'event_espresso'
161
-                        ),
162
-                        $classname
163
-                    )
164
-                );
165
-            }
166
-        }
143
+		/**
144
+		 *    espresso_load_required
145
+		 *    given a class name and path, this function will load that file or throw an exception
146
+		 *
147
+		 * @param    string $classname
148
+		 * @param    string $full_path_to_file
149
+		 * @throws    EE_Error
150
+		 */
151
+		function espresso_load_required($classname, $full_path_to_file)
152
+		{
153
+			if (is_readable($full_path_to_file)) {
154
+				require_once $full_path_to_file;
155
+			} else {
156
+				throw new \EE_Error (
157
+					sprintf(
158
+						esc_html__(
159
+							'The %s class file could not be located or is not readable due to file permissions.',
160
+							'event_espresso'
161
+						),
162
+						$classname
163
+					)
164
+				);
165
+			}
166
+		}
167 167
 
168
-        /**
169
-         * @since 4.9.27
170
-         * @throws \EE_Error
171
-         * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
172
-         * @throws \EventEspresso\core\exceptions\InvalidEntityException
173
-         * @throws \EventEspresso\core\exceptions\InvalidIdentifierException
174
-         * @throws \EventEspresso\core\exceptions\InvalidClassException
175
-         * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
176
-         * @throws \EventEspresso\core\services\container\exceptions\ServiceExistsException
177
-         * @throws \EventEspresso\core\services\container\exceptions\ServiceNotFoundException
178
-         * @throws \OutOfBoundsException
179
-         */
180
-        function bootstrap_espresso()
181
-        {
182
-            require_once __DIR__ . '/core/espresso_definitions.php';
183
-            try {
184
-                espresso_load_error_handling();
185
-                espresso_load_required(
186
-                    'EEH_Base',
187
-                    EE_CORE . 'helpers' . DS . 'EEH_Base.helper.php'
188
-                );
189
-                espresso_load_required(
190
-                    'EEH_File',
191
-                    EE_CORE . 'interfaces' . DS . 'EEHI_File.interface.php'
192
-                );
193
-                espresso_load_required(
194
-                    'EEH_File',
195
-                    EE_CORE . 'helpers' . DS . 'EEH_File.helper.php'
196
-                );
197
-                espresso_load_required(
198
-                    'EEH_Array',
199
-                    EE_CORE . 'helpers' . DS . 'EEH_Array.helper.php'
200
-                );
201
-                // instantiate and configure PSR4 autoloader
202
-                espresso_load_required(
203
-                    'Psr4Autoloader',
204
-                    EE_CORE . 'Psr4Autoloader.php'
205
-                );
206
-                espresso_load_required(
207
-                    'EE_Psr4AutoloaderInit',
208
-                    EE_CORE . 'EE_Psr4AutoloaderInit.core.php'
209
-                );
210
-                $AutoloaderInit = new EE_Psr4AutoloaderInit();
211
-                $AutoloaderInit->initializeAutoloader();
212
-                espresso_load_required(
213
-                    'EE_Request',
214
-                    EE_CORE . 'request_stack' . DS . 'EE_Request.core.php'
215
-                );
216
-                espresso_load_required(
217
-                    'EE_Response',
218
-                    EE_CORE . 'request_stack' . DS . 'EE_Response.core.php'
219
-                );
220
-                espresso_load_required(
221
-                    'EE_Bootstrap',
222
-                    EE_CORE . 'EE_Bootstrap.core.php'
223
-                );
224
-                // bootstrap EE and the request stack
225
-                new EE_Bootstrap(
226
-                    new EE_Request($_GET, $_POST, $_COOKIE),
227
-                    new EE_Response()
228
-                );
229
-            } catch (Exception $e) {
230
-                require_once EE_CORE . 'exceptions' . DS . 'ExceptionStackTraceDisplay.php';
231
-                new EventEspresso\core\exceptions\ExceptionStackTraceDisplay($e);
232
-            }
233
-        }
234
-        bootstrap_espresso();
235
-    }
168
+		/**
169
+		 * @since 4.9.27
170
+		 * @throws \EE_Error
171
+		 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
172
+		 * @throws \EventEspresso\core\exceptions\InvalidEntityException
173
+		 * @throws \EventEspresso\core\exceptions\InvalidIdentifierException
174
+		 * @throws \EventEspresso\core\exceptions\InvalidClassException
175
+		 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
176
+		 * @throws \EventEspresso\core\services\container\exceptions\ServiceExistsException
177
+		 * @throws \EventEspresso\core\services\container\exceptions\ServiceNotFoundException
178
+		 * @throws \OutOfBoundsException
179
+		 */
180
+		function bootstrap_espresso()
181
+		{
182
+			require_once __DIR__ . '/core/espresso_definitions.php';
183
+			try {
184
+				espresso_load_error_handling();
185
+				espresso_load_required(
186
+					'EEH_Base',
187
+					EE_CORE . 'helpers' . DS . 'EEH_Base.helper.php'
188
+				);
189
+				espresso_load_required(
190
+					'EEH_File',
191
+					EE_CORE . 'interfaces' . DS . 'EEHI_File.interface.php'
192
+				);
193
+				espresso_load_required(
194
+					'EEH_File',
195
+					EE_CORE . 'helpers' . DS . 'EEH_File.helper.php'
196
+				);
197
+				espresso_load_required(
198
+					'EEH_Array',
199
+					EE_CORE . 'helpers' . DS . 'EEH_Array.helper.php'
200
+				);
201
+				// instantiate and configure PSR4 autoloader
202
+				espresso_load_required(
203
+					'Psr4Autoloader',
204
+					EE_CORE . 'Psr4Autoloader.php'
205
+				);
206
+				espresso_load_required(
207
+					'EE_Psr4AutoloaderInit',
208
+					EE_CORE . 'EE_Psr4AutoloaderInit.core.php'
209
+				);
210
+				$AutoloaderInit = new EE_Psr4AutoloaderInit();
211
+				$AutoloaderInit->initializeAutoloader();
212
+				espresso_load_required(
213
+					'EE_Request',
214
+					EE_CORE . 'request_stack' . DS . 'EE_Request.core.php'
215
+				);
216
+				espresso_load_required(
217
+					'EE_Response',
218
+					EE_CORE . 'request_stack' . DS . 'EE_Response.core.php'
219
+				);
220
+				espresso_load_required(
221
+					'EE_Bootstrap',
222
+					EE_CORE . 'EE_Bootstrap.core.php'
223
+				);
224
+				// bootstrap EE and the request stack
225
+				new EE_Bootstrap(
226
+					new EE_Request($_GET, $_POST, $_COOKIE),
227
+					new EE_Response()
228
+				);
229
+			} catch (Exception $e) {
230
+				require_once EE_CORE . 'exceptions' . DS . 'ExceptionStackTraceDisplay.php';
231
+				new EventEspresso\core\exceptions\ExceptionStackTraceDisplay($e);
232
+			}
233
+		}
234
+		bootstrap_espresso();
235
+	}
236 236
 }
237 237
 if (! function_exists('espresso_deactivate_plugin')) {
238
-    /**
239
-     *    deactivate_plugin
240
-     * usage:  espresso_deactivate_plugin( plugin_basename( __FILE__ ));
241
-     *
242
-     * @access public
243
-     * @param string $plugin_basename - the results of plugin_basename( __FILE__ ) for the plugin's main file
244
-     * @return    void
245
-     */
246
-    function espresso_deactivate_plugin($plugin_basename = '')
247
-    {
248
-        if (! function_exists('deactivate_plugins')) {
249
-            require_once ABSPATH . 'wp-admin/includes/plugin.php';
250
-        }
251
-        unset($_GET['activate'], $_REQUEST['activate']);
252
-        deactivate_plugins($plugin_basename);
253
-    }
238
+	/**
239
+	 *    deactivate_plugin
240
+	 * usage:  espresso_deactivate_plugin( plugin_basename( __FILE__ ));
241
+	 *
242
+	 * @access public
243
+	 * @param string $plugin_basename - the results of plugin_basename( __FILE__ ) for the plugin's main file
244
+	 * @return    void
245
+	 */
246
+	function espresso_deactivate_plugin($plugin_basename = '')
247
+	{
248
+		if (! function_exists('deactivate_plugins')) {
249
+			require_once ABSPATH . 'wp-admin/includes/plugin.php';
250
+		}
251
+		unset($_GET['activate'], $_REQUEST['activate']);
252
+		deactivate_plugins($plugin_basename);
253
+	}
254 254
 }
Please login to merge, or discard this patch.
core/helpers/EEH_DTT_Helper.helper.php 1 patch
Indentation   +1221 added lines, -1221 removed lines patch added patch discarded remove patch
@@ -15,382 +15,382 @@  discard block
 block discarded – undo
15 15
 {
16 16
 
17 17
 
18
-    /**
19
-     * return the timezone set for the WP install
20
-     *
21
-     * @return string valid timezone string for PHP DateTimeZone() class
22
-     * @throws EE_Error
23
-     */
24
-    public static function get_timezone()
25
-    {
26
-        return EEH_DTT_Helper::get_valid_timezone_string();
27
-    }
28
-
29
-
30
-    /**
31
-     * get_valid_timezone_string
32
-     *    ensures that a valid timezone string is returned
33
-     *
34
-     * @param string $timezone_string
35
-     * @return string
36
-     * @throws EE_Error
37
-     */
38
-    public static function get_valid_timezone_string($timezone_string = '')
39
-    {
40
-        // if passed a value, then use that, else get WP option
41
-        $timezone_string = ! empty($timezone_string) ? $timezone_string : (string) get_option('timezone_string');
42
-        // value from above exists, use that, else get timezone string from gmt_offset
43
-        $timezone_string = ! empty($timezone_string)
44
-            ? $timezone_string
45
-            : EEH_DTT_Helper::get_timezone_string_from_gmt_offset();
46
-        EEH_DTT_Helper::validate_timezone($timezone_string);
47
-        return $timezone_string;
48
-    }
49
-
50
-
51
-    /**
52
-     * This only purpose for this static method is to validate that the incoming timezone is a valid php timezone.
53
-     *
54
-     * @static
55
-     * @param  string $timezone_string Timezone string to check
56
-     * @param bool    $throw_error
57
-     * @return bool
58
-     * @throws EE_Error
59
-     */
60
-    public static function validate_timezone($timezone_string, $throw_error = true)
61
-    {
62
-        // easiest way to test a timezone string is just see if it throws an error when you try to create a DateTimeZone object with it
63
-        try {
64
-            new DateTimeZone($timezone_string);
65
-        } catch (Exception $e) {
66
-            // sometimes we take exception to exceptions
67
-            if (! $throw_error) {
68
-                return false;
69
-            }
70
-            throw new EE_Error(
71
-                sprintf(
72
-                    esc_html__(
73
-                        'The timezone given (%1$s), is invalid, please check with %2$sthis list%3$s for what valid timezones can be used',
74
-                        'event_espresso'
75
-                    ),
76
-                    $timezone_string,
77
-                    '<a href="http://www.php.net/manual/en/timezones.php">',
78
-                    '</a>'
79
-                )
80
-            );
81
-        }
82
-        return true;
83
-    }
84
-
85
-
86
-    /**
87
-     * _create_timezone_object_from_timezone_name
88
-     *
89
-     * @param float|string $gmt_offset
90
-     * @return string
91
-     * @throws EE_Error
92
-     */
93
-    public static function get_timezone_string_from_gmt_offset($gmt_offset = '')
94
-    {
95
-        $timezone_string = 'UTC';
96
-        //if there is no incoming gmt_offset, then because WP hooks in on timezone_string, we need to see if that is
97
-        //set because it will override `gmt_offset` via `pre_get_option` filter.  If that's set, then let's just use
98
-        //that!  Otherwise we'll leave timezone_string at the default of 'UTC' before doing other logic.
99
-        if ($gmt_offset === '') {
100
-            //autoloaded so no need to set to a variable.  There will not be multiple hits to the db.
101
-            if (get_option('timezone_string')) {
102
-                return (string) get_option('timezone_string');
103
-            }
104
-        }
105
-        $gmt_offset = $gmt_offset !== '' ? $gmt_offset : (string) get_option('gmt_offset');
106
-        $gmt_offset = (float) $gmt_offset;
107
-        //if $gmt_offset is 0, then just return UTC
108
-        if ($gmt_offset === (float) 0) {
109
-            return $timezone_string;
110
-        }
111
-        if ($gmt_offset !== '') {
112
-            // convert GMT offset to seconds
113
-            $gmt_offset *= HOUR_IN_SECONDS;
114
-            // although we don't know the TZ abbreviation, we know the UTC offset
115
-            $timezone_string = timezone_name_from_abbr(null, $gmt_offset);
116
-            //only use this timezone_string IF it's current offset matches the given offset
117
-            if(! empty($timezone_string)) {
118
-                $offset  = null;
119
-                try {
120
-                    $offset = self::get_timezone_offset(new DateTimeZone($timezone_string));
121
-                    if ($offset !== $gmt_offset) {
122
-                        $timezone_string = false;
123
-                    }
124
-                } catch (Exception $e) {
125
-                    $timezone_string = false;
126
-                }
127
-            }
128
-        }
129
-        // better have a valid timezone string by now, but if not, sigh... loop thru  the timezone_abbreviations_list()...
130
-        $timezone_string = $timezone_string !== false
131
-            ? $timezone_string
132
-            : EEH_DTT_Helper::get_timezone_string_from_abbreviations_list($gmt_offset);
133
-        return $timezone_string;
134
-    }
135
-
136
-
137
-    /**
138
-     * Gets the site's GMT offset based on either the timezone string
139
-     * (in which case teh gmt offset will vary depending on the location's
140
-     * observance of daylight savings time) or the gmt_offset wp option
141
-     *
142
-     * @return int seconds offset
143
-     */
144
-    public static function get_site_timezone_gmt_offset()
145
-    {
146
-        $timezone_string = (string) get_option('timezone_string');
147
-        if ($timezone_string) {
148
-            try {
149
-                $timezone = new DateTimeZone($timezone_string);
150
-                return $timezone->getOffset(new DateTime()); //in WordPress DateTime defaults to UTC
151
-            } catch (Exception $e) {
152
-            }
153
-        }
154
-        $offset = get_option('gmt_offset');
155
-        return (int) ($offset * HOUR_IN_SECONDS);
156
-    }
157
-
158
-
159
-    /**
160
-     * Depending on PHP version,
161
-     * there might not be valid current timezone strings to match these gmt_offsets in its timezone tables.
162
-     * To get around that, for these fringe timezones we bump them to a known valid offset.
163
-     * This method should ONLY be called after first verifying an timezone_string cannot be retrieved for the offset.
164
-     *
165
-     * @param int $gmt_offset
166
-     * @return int
167
-     */
168
-    public static function adjust_invalid_gmt_offsets($gmt_offset = 0)
169
-    {
170
-        //make sure $gmt_offset is int
171
-        $gmt_offset = (int) $gmt_offset;
172
-        switch ($gmt_offset) {
173
-            //-12
174
-            case -43200:
175
-                $gmt_offset = -39600;
176
-                break;
177
-            //-11.5
178
-            case -41400:
179
-                $gmt_offset = -39600;
180
-                break;
181
-            //-10.5
182
-            case -37800:
183
-                $gmt_offset = -39600;
184
-                break;
185
-            //-9.5
186
-            case -34200:
187
-                $gmt_offset = -32400;
188
-                break;
189
-            //-8.5
190
-            case -30600:
191
-                $gmt_offset = -28800;
192
-                break;
193
-            //-7.5
194
-            case -27000:
195
-                $gmt_offset = -25200;
196
-                break;
197
-            //-6.5
198
-            case -23400:
199
-                $gmt_offset = -21600;
200
-                break;
201
-            //-5.5
202
-            case -19800:
203
-                $gmt_offset = -18000;
204
-                break;
205
-            //-4.5
206
-            case -16200:
207
-                $gmt_offset = -14400;
208
-                break;
209
-            //-3.5
210
-            case -12600:
211
-                $gmt_offset = -10800;
212
-                break;
213
-            //-2.5
214
-            case -9000:
215
-                $gmt_offset = -7200;
216
-                break;
217
-            //-1.5
218
-            case -5400:
219
-                $gmt_offset = -7200;
220
-                break;
221
-            //-1
222
-            case -3600:
223
-                $gmt_offset = 0;
224
-                break;
225
-            //-0.5
226
-            case -1800:
227
-                $gmt_offset = 0;
228
-                break;
229
-            //.5
230
-            case 1800:
231
-                $gmt_offset = 3600;
232
-                break;
233
-            //1.5
234
-            case 5400:
235
-                $gmt_offset = 7200;
236
-                break;
237
-            //2.5
238
-            case 9000:
239
-                $gmt_offset = 10800;
240
-                break;
241
-            //3.5
242
-            case 12600:
243
-                $gmt_offset = 14400;
244
-                break;
245
-            //7.5
246
-            case 27000:
247
-                $gmt_offset = 28800;
248
-                break;
249
-            //8.5
250
-            case 30600:
251
-                $gmt_offset = 31500;
252
-                break;
253
-            //10.5
254
-            case 37800:
255
-                $gmt_offset = 39600;
256
-                break;
257
-            //11.5
258
-            case 41400:
259
-                $gmt_offset = 43200;
260
-                break;
261
-            //12.75
262
-            case 45900:
263
-                $gmt_offset = 46800;
264
-                break;
265
-            //13.75
266
-            case 49500:
267
-                $gmt_offset = 50400;
268
-                break;
269
-        }
270
-        return $gmt_offset;
271
-    }
272
-
273
-
274
-    /**
275
-     * get_timezone_string_from_abbreviations_list
276
-     *
277
-     * @param int  $gmt_offset
278
-     * @param bool $coerce If true, we attempt to coerce with our adjustment table @see self::adjust_invalid_gmt_offset.
279
-     * @return string
280
-     * @throws EE_Error
281
-     */
282
-    public static function get_timezone_string_from_abbreviations_list($gmt_offset = 0, $coerce = true)
283
-    {
284
-        $gmt_offset =  (int) $gmt_offset;
285
-        /** @var array[] $abbreviations */
286
-        $abbreviations = DateTimeZone::listAbbreviations();
287
-        foreach ($abbreviations as $abbreviation) {
288
-            foreach ($abbreviation as $timezone) {
289
-                if ((int) $timezone['offset'] === $gmt_offset && (bool) $timezone['dst'] === false) {
290
-                    try {
291
-                        $offset = self::get_timezone_offset(new DateTimeZone($timezone['timezone_id']));
292
-                        if ($offset !== $gmt_offset) {
293
-                            continue;
294
-                        }
295
-                        return $timezone['timezone_id'];
296
-                    } catch (Exception $e) {
297
-                        continue;
298
-                    }
299
-                }
300
-            }
301
-        }
302
-        //if $coerce is true, let's see if we can get a timezone string after the offset is adjusted
303
-        if ($coerce === true) {
304
-            $timezone_string = self::get_timezone_string_from_abbreviations_list(
305
-                self::adjust_invalid_gmt_offsets($gmt_offset),
306
-                false
307
-            );
308
-            if ($timezone_string) {
309
-                return $timezone_string;
310
-            }
311
-        }
312
-        throw new EE_Error(
313
-            sprintf(
314
-                esc_html__(
315
-                    'The provided GMT offset (%1$s), is invalid, please check with %2$sthis list%3$s for what valid timezones can be used',
316
-                    'event_espresso'
317
-                ),
318
-                $gmt_offset / HOUR_IN_SECONDS,
319
-                '<a href="http://www.php.net/manual/en/timezones.php">',
320
-                '</a>'
321
-            )
322
-        );
323
-    }
324
-
325
-
326
-
327
-    /**
328
-     * Get Timezone Transitions
329
-     *
330
-     * @param DateTimeZone $date_time_zone
331
-     * @param int|null     $time
332
-     * @param bool         $first_only
333
-     * @return array|mixed
334
-     */
335
-    public static function get_timezone_transitions(DateTimeZone $date_time_zone, $time = null, $first_only = true)
336
-    {
337
-        $time        = is_int($time) || $time === null ? $time : (int) strtotime($time);
338
-        $time        = preg_match(EE_Datetime_Field::unix_timestamp_regex, $time) ? $time : time();
339
-        $transitions = $date_time_zone->getTransitions($time);
340
-        return $first_only && ! isset($transitions['ts']) ? reset($transitions) : $transitions;
341
-    }
342
-
343
-
344
-    /**
345
-     * Get Timezone Offset for given timezone object.
346
-     *
347
-     * @param DateTimeZone $date_time_zone
348
-     * @param null         $time
349
-     * @return mixed
350
-     * @throws DomainException
351
-     */
352
-    public static function get_timezone_offset(DateTimeZone $date_time_zone, $time = null)
353
-    {
354
-        $transition = self::get_timezone_transitions($date_time_zone, $time);
355
-        if (! isset($transition['offset'])) {
356
-            throw new DomainException(
357
-                sprintf(
358
-                    esc_html__('An invalid timezone transition was received %1$s', 'event_espresso'),
359
-                    print_r($transition, true)
360
-                )
361
-            );
362
-        }
363
-        return $transition['offset'];
364
-    }
365
-
366
-
367
-    /**
368
-     * @param string $timezone_string
369
-     * @throws EE_Error
370
-     */
371
-    public static function timezone_select_input($timezone_string = '')
372
-    {
373
-        // get WP date time format
374
-        $datetime_format = get_option('date_format') . ' ' . get_option('time_format');
375
-        // if passed a value, then use that, else get WP option
376
-        $timezone_string = ! empty($timezone_string) ? $timezone_string : (string) get_option('timezone_string');
377
-        // check if the timezone is valid but don't throw any errors if it isn't
378
-        $timezone_string = EEH_DTT_Helper::validate_timezone($timezone_string, false)
379
-            ? $timezone_string
380
-            : '';
381
-        $gmt_offset      = get_option('gmt_offset');
382
-        $check_zone_info = true;
383
-        if (empty($timezone_string)) {
384
-            // Create a UTC+- zone if no timezone string exists
385
-            $timezone_string = 'UTC';
386
-            $check_zone_info = false;
387
-            if ($gmt_offset > 0) {
388
-                $timezone_string = 'UTC+' . $gmt_offset;
389
-            } elseif ($gmt_offset < 0) {
390
-                $timezone_string = 'UTC' . $gmt_offset;
391
-            }
392
-        }
393
-        ?>
18
+	/**
19
+	 * return the timezone set for the WP install
20
+	 *
21
+	 * @return string valid timezone string for PHP DateTimeZone() class
22
+	 * @throws EE_Error
23
+	 */
24
+	public static function get_timezone()
25
+	{
26
+		return EEH_DTT_Helper::get_valid_timezone_string();
27
+	}
28
+
29
+
30
+	/**
31
+	 * get_valid_timezone_string
32
+	 *    ensures that a valid timezone string is returned
33
+	 *
34
+	 * @param string $timezone_string
35
+	 * @return string
36
+	 * @throws EE_Error
37
+	 */
38
+	public static function get_valid_timezone_string($timezone_string = '')
39
+	{
40
+		// if passed a value, then use that, else get WP option
41
+		$timezone_string = ! empty($timezone_string) ? $timezone_string : (string) get_option('timezone_string');
42
+		// value from above exists, use that, else get timezone string from gmt_offset
43
+		$timezone_string = ! empty($timezone_string)
44
+			? $timezone_string
45
+			: EEH_DTT_Helper::get_timezone_string_from_gmt_offset();
46
+		EEH_DTT_Helper::validate_timezone($timezone_string);
47
+		return $timezone_string;
48
+	}
49
+
50
+
51
+	/**
52
+	 * This only purpose for this static method is to validate that the incoming timezone is a valid php timezone.
53
+	 *
54
+	 * @static
55
+	 * @param  string $timezone_string Timezone string to check
56
+	 * @param bool    $throw_error
57
+	 * @return bool
58
+	 * @throws EE_Error
59
+	 */
60
+	public static function validate_timezone($timezone_string, $throw_error = true)
61
+	{
62
+		// easiest way to test a timezone string is just see if it throws an error when you try to create a DateTimeZone object with it
63
+		try {
64
+			new DateTimeZone($timezone_string);
65
+		} catch (Exception $e) {
66
+			// sometimes we take exception to exceptions
67
+			if (! $throw_error) {
68
+				return false;
69
+			}
70
+			throw new EE_Error(
71
+				sprintf(
72
+					esc_html__(
73
+						'The timezone given (%1$s), is invalid, please check with %2$sthis list%3$s for what valid timezones can be used',
74
+						'event_espresso'
75
+					),
76
+					$timezone_string,
77
+					'<a href="http://www.php.net/manual/en/timezones.php">',
78
+					'</a>'
79
+				)
80
+			);
81
+		}
82
+		return true;
83
+	}
84
+
85
+
86
+	/**
87
+	 * _create_timezone_object_from_timezone_name
88
+	 *
89
+	 * @param float|string $gmt_offset
90
+	 * @return string
91
+	 * @throws EE_Error
92
+	 */
93
+	public static function get_timezone_string_from_gmt_offset($gmt_offset = '')
94
+	{
95
+		$timezone_string = 'UTC';
96
+		//if there is no incoming gmt_offset, then because WP hooks in on timezone_string, we need to see if that is
97
+		//set because it will override `gmt_offset` via `pre_get_option` filter.  If that's set, then let's just use
98
+		//that!  Otherwise we'll leave timezone_string at the default of 'UTC' before doing other logic.
99
+		if ($gmt_offset === '') {
100
+			//autoloaded so no need to set to a variable.  There will not be multiple hits to the db.
101
+			if (get_option('timezone_string')) {
102
+				return (string) get_option('timezone_string');
103
+			}
104
+		}
105
+		$gmt_offset = $gmt_offset !== '' ? $gmt_offset : (string) get_option('gmt_offset');
106
+		$gmt_offset = (float) $gmt_offset;
107
+		//if $gmt_offset is 0, then just return UTC
108
+		if ($gmt_offset === (float) 0) {
109
+			return $timezone_string;
110
+		}
111
+		if ($gmt_offset !== '') {
112
+			// convert GMT offset to seconds
113
+			$gmt_offset *= HOUR_IN_SECONDS;
114
+			// although we don't know the TZ abbreviation, we know the UTC offset
115
+			$timezone_string = timezone_name_from_abbr(null, $gmt_offset);
116
+			//only use this timezone_string IF it's current offset matches the given offset
117
+			if(! empty($timezone_string)) {
118
+				$offset  = null;
119
+				try {
120
+					$offset = self::get_timezone_offset(new DateTimeZone($timezone_string));
121
+					if ($offset !== $gmt_offset) {
122
+						$timezone_string = false;
123
+					}
124
+				} catch (Exception $e) {
125
+					$timezone_string = false;
126
+				}
127
+			}
128
+		}
129
+		// better have a valid timezone string by now, but if not, sigh... loop thru  the timezone_abbreviations_list()...
130
+		$timezone_string = $timezone_string !== false
131
+			? $timezone_string
132
+			: EEH_DTT_Helper::get_timezone_string_from_abbreviations_list($gmt_offset);
133
+		return $timezone_string;
134
+	}
135
+
136
+
137
+	/**
138
+	 * Gets the site's GMT offset based on either the timezone string
139
+	 * (in which case teh gmt offset will vary depending on the location's
140
+	 * observance of daylight savings time) or the gmt_offset wp option
141
+	 *
142
+	 * @return int seconds offset
143
+	 */
144
+	public static function get_site_timezone_gmt_offset()
145
+	{
146
+		$timezone_string = (string) get_option('timezone_string');
147
+		if ($timezone_string) {
148
+			try {
149
+				$timezone = new DateTimeZone($timezone_string);
150
+				return $timezone->getOffset(new DateTime()); //in WordPress DateTime defaults to UTC
151
+			} catch (Exception $e) {
152
+			}
153
+		}
154
+		$offset = get_option('gmt_offset');
155
+		return (int) ($offset * HOUR_IN_SECONDS);
156
+	}
157
+
158
+
159
+	/**
160
+	 * Depending on PHP version,
161
+	 * there might not be valid current timezone strings to match these gmt_offsets in its timezone tables.
162
+	 * To get around that, for these fringe timezones we bump them to a known valid offset.
163
+	 * This method should ONLY be called after first verifying an timezone_string cannot be retrieved for the offset.
164
+	 *
165
+	 * @param int $gmt_offset
166
+	 * @return int
167
+	 */
168
+	public static function adjust_invalid_gmt_offsets($gmt_offset = 0)
169
+	{
170
+		//make sure $gmt_offset is int
171
+		$gmt_offset = (int) $gmt_offset;
172
+		switch ($gmt_offset) {
173
+			//-12
174
+			case -43200:
175
+				$gmt_offset = -39600;
176
+				break;
177
+			//-11.5
178
+			case -41400:
179
+				$gmt_offset = -39600;
180
+				break;
181
+			//-10.5
182
+			case -37800:
183
+				$gmt_offset = -39600;
184
+				break;
185
+			//-9.5
186
+			case -34200:
187
+				$gmt_offset = -32400;
188
+				break;
189
+			//-8.5
190
+			case -30600:
191
+				$gmt_offset = -28800;
192
+				break;
193
+			//-7.5
194
+			case -27000:
195
+				$gmt_offset = -25200;
196
+				break;
197
+			//-6.5
198
+			case -23400:
199
+				$gmt_offset = -21600;
200
+				break;
201
+			//-5.5
202
+			case -19800:
203
+				$gmt_offset = -18000;
204
+				break;
205
+			//-4.5
206
+			case -16200:
207
+				$gmt_offset = -14400;
208
+				break;
209
+			//-3.5
210
+			case -12600:
211
+				$gmt_offset = -10800;
212
+				break;
213
+			//-2.5
214
+			case -9000:
215
+				$gmt_offset = -7200;
216
+				break;
217
+			//-1.5
218
+			case -5400:
219
+				$gmt_offset = -7200;
220
+				break;
221
+			//-1
222
+			case -3600:
223
+				$gmt_offset = 0;
224
+				break;
225
+			//-0.5
226
+			case -1800:
227
+				$gmt_offset = 0;
228
+				break;
229
+			//.5
230
+			case 1800:
231
+				$gmt_offset = 3600;
232
+				break;
233
+			//1.5
234
+			case 5400:
235
+				$gmt_offset = 7200;
236
+				break;
237
+			//2.5
238
+			case 9000:
239
+				$gmt_offset = 10800;
240
+				break;
241
+			//3.5
242
+			case 12600:
243
+				$gmt_offset = 14400;
244
+				break;
245
+			//7.5
246
+			case 27000:
247
+				$gmt_offset = 28800;
248
+				break;
249
+			//8.5
250
+			case 30600:
251
+				$gmt_offset = 31500;
252
+				break;
253
+			//10.5
254
+			case 37800:
255
+				$gmt_offset = 39600;
256
+				break;
257
+			//11.5
258
+			case 41400:
259
+				$gmt_offset = 43200;
260
+				break;
261
+			//12.75
262
+			case 45900:
263
+				$gmt_offset = 46800;
264
+				break;
265
+			//13.75
266
+			case 49500:
267
+				$gmt_offset = 50400;
268
+				break;
269
+		}
270
+		return $gmt_offset;
271
+	}
272
+
273
+
274
+	/**
275
+	 * get_timezone_string_from_abbreviations_list
276
+	 *
277
+	 * @param int  $gmt_offset
278
+	 * @param bool $coerce If true, we attempt to coerce with our adjustment table @see self::adjust_invalid_gmt_offset.
279
+	 * @return string
280
+	 * @throws EE_Error
281
+	 */
282
+	public static function get_timezone_string_from_abbreviations_list($gmt_offset = 0, $coerce = true)
283
+	{
284
+		$gmt_offset =  (int) $gmt_offset;
285
+		/** @var array[] $abbreviations */
286
+		$abbreviations = DateTimeZone::listAbbreviations();
287
+		foreach ($abbreviations as $abbreviation) {
288
+			foreach ($abbreviation as $timezone) {
289
+				if ((int) $timezone['offset'] === $gmt_offset && (bool) $timezone['dst'] === false) {
290
+					try {
291
+						$offset = self::get_timezone_offset(new DateTimeZone($timezone['timezone_id']));
292
+						if ($offset !== $gmt_offset) {
293
+							continue;
294
+						}
295
+						return $timezone['timezone_id'];
296
+					} catch (Exception $e) {
297
+						continue;
298
+					}
299
+				}
300
+			}
301
+		}
302
+		//if $coerce is true, let's see if we can get a timezone string after the offset is adjusted
303
+		if ($coerce === true) {
304
+			$timezone_string = self::get_timezone_string_from_abbreviations_list(
305
+				self::adjust_invalid_gmt_offsets($gmt_offset),
306
+				false
307
+			);
308
+			if ($timezone_string) {
309
+				return $timezone_string;
310
+			}
311
+		}
312
+		throw new EE_Error(
313
+			sprintf(
314
+				esc_html__(
315
+					'The provided GMT offset (%1$s), is invalid, please check with %2$sthis list%3$s for what valid timezones can be used',
316
+					'event_espresso'
317
+				),
318
+				$gmt_offset / HOUR_IN_SECONDS,
319
+				'<a href="http://www.php.net/manual/en/timezones.php">',
320
+				'</a>'
321
+			)
322
+		);
323
+	}
324
+
325
+
326
+
327
+	/**
328
+	 * Get Timezone Transitions
329
+	 *
330
+	 * @param DateTimeZone $date_time_zone
331
+	 * @param int|null     $time
332
+	 * @param bool         $first_only
333
+	 * @return array|mixed
334
+	 */
335
+	public static function get_timezone_transitions(DateTimeZone $date_time_zone, $time = null, $first_only = true)
336
+	{
337
+		$time        = is_int($time) || $time === null ? $time : (int) strtotime($time);
338
+		$time        = preg_match(EE_Datetime_Field::unix_timestamp_regex, $time) ? $time : time();
339
+		$transitions = $date_time_zone->getTransitions($time);
340
+		return $first_only && ! isset($transitions['ts']) ? reset($transitions) : $transitions;
341
+	}
342
+
343
+
344
+	/**
345
+	 * Get Timezone Offset for given timezone object.
346
+	 *
347
+	 * @param DateTimeZone $date_time_zone
348
+	 * @param null         $time
349
+	 * @return mixed
350
+	 * @throws DomainException
351
+	 */
352
+	public static function get_timezone_offset(DateTimeZone $date_time_zone, $time = null)
353
+	{
354
+		$transition = self::get_timezone_transitions($date_time_zone, $time);
355
+		if (! isset($transition['offset'])) {
356
+			throw new DomainException(
357
+				sprintf(
358
+					esc_html__('An invalid timezone transition was received %1$s', 'event_espresso'),
359
+					print_r($transition, true)
360
+				)
361
+			);
362
+		}
363
+		return $transition['offset'];
364
+	}
365
+
366
+
367
+	/**
368
+	 * @param string $timezone_string
369
+	 * @throws EE_Error
370
+	 */
371
+	public static function timezone_select_input($timezone_string = '')
372
+	{
373
+		// get WP date time format
374
+		$datetime_format = get_option('date_format') . ' ' . get_option('time_format');
375
+		// if passed a value, then use that, else get WP option
376
+		$timezone_string = ! empty($timezone_string) ? $timezone_string : (string) get_option('timezone_string');
377
+		// check if the timezone is valid but don't throw any errors if it isn't
378
+		$timezone_string = EEH_DTT_Helper::validate_timezone($timezone_string, false)
379
+			? $timezone_string
380
+			: '';
381
+		$gmt_offset      = get_option('gmt_offset');
382
+		$check_zone_info = true;
383
+		if (empty($timezone_string)) {
384
+			// Create a UTC+- zone if no timezone string exists
385
+			$timezone_string = 'UTC';
386
+			$check_zone_info = false;
387
+			if ($gmt_offset > 0) {
388
+				$timezone_string = 'UTC+' . $gmt_offset;
389
+			} elseif ($gmt_offset < 0) {
390
+				$timezone_string = 'UTC' . $gmt_offset;
391
+			}
392
+		}
393
+		?>
394 394
 
395 395
         <p>
396 396
             <label for="timezone_string"><?php _e('timezone'); ?></label>
@@ -403,13 +403,13 @@  discard block
 block discarded – undo
403 403
 
404 404
         <p>
405 405
         <span><?php
406
-            printf(
407
-                __('%1$sUTC%2$s time is %3$s'),
408
-                '<abbr title="Coordinated Universal Time">',
409
-                '</abbr>',
410
-                '<code>' . date_i18n($datetime_format, false, true) . '</code>'
411
-            );
412
-            ?></span>
406
+			printf(
407
+				__('%1$sUTC%2$s time is %3$s'),
408
+				'<abbr title="Coordinated Universal Time">',
409
+				'</abbr>',
410
+				'<code>' . date_i18n($datetime_format, false, true) . '</code>'
411
+			);
412
+			?></span>
413 413
         <?php if (! empty($timezone_string) || ! empty($gmt_offset)) : ?>
414 414
         <br/><span><?php printf(__('Local time is %1$s'), '<code>' . date_i18n($datetime_format) . '</code>'); ?></span>
415 415
     <?php endif; ?>
@@ -418,847 +418,847 @@  discard block
 block discarded – undo
418 418
         <br/>
419 419
         <span>
420 420
 					<?php
421
-                    // Set TZ so localtime works.
422
-                    date_default_timezone_set($timezone_string);
423
-                    $now = localtime(time(), true);
424
-                    if ($now['tm_isdst']) {
425
-                        _e('This timezone is currently in daylight saving time.');
426
-                    } else {
427
-                        _e('This timezone is currently in standard time.');
428
-                    }
429
-                    ?>
421
+					// Set TZ so localtime works.
422
+					date_default_timezone_set($timezone_string);
423
+					$now = localtime(time(), true);
424
+					if ($now['tm_isdst']) {
425
+						_e('This timezone is currently in daylight saving time.');
426
+					} else {
427
+						_e('This timezone is currently in standard time.');
428
+					}
429
+					?>
430 430
             <br/>
431 431
             <?php
432
-            if (function_exists('timezone_transitions_get')) {
433
-                $found                   = false;
434
-                $date_time_zone_selected = new DateTimeZone($timezone_string);
435
-                $tz_offset               = timezone_offset_get($date_time_zone_selected, date_create());
436
-                $right_now               = time();
437
-                $tr['isdst']             = false;
438
-                foreach (timezone_transitions_get($date_time_zone_selected) as $tr) {
439
-                    if ($tr['ts'] > $right_now) {
440
-                        $found = true;
441
-                        break;
442
-                    }
443
-                }
444
-                if ($found) {
445
-                    $message = $tr['isdst']
446
-                        ?
447
-                        __(' Daylight saving time begins on: %s.')
448
-                        :
449
-                        __(' Standard time begins  on: %s.');
450
-                    // Add the difference between the current offset and the new offset to ts to get the correct transition time from date_i18n().
451
-                    printf(
452
-                        $message,
453
-                        '<code >' . date_i18n($datetime_format, $tr['ts'] + ($tz_offset - $tr['offset'])) . '</code >'
454
-                    );
455
-                } else {
456
-                    _e('This timezone does not observe daylight saving time.');
457
-                }
458
-            }
459
-            // Set back to UTC.
460
-            date_default_timezone_set('UTC');
461
-            ?>
432
+			if (function_exists('timezone_transitions_get')) {
433
+				$found                   = false;
434
+				$date_time_zone_selected = new DateTimeZone($timezone_string);
435
+				$tz_offset               = timezone_offset_get($date_time_zone_selected, date_create());
436
+				$right_now               = time();
437
+				$tr['isdst']             = false;
438
+				foreach (timezone_transitions_get($date_time_zone_selected) as $tr) {
439
+					if ($tr['ts'] > $right_now) {
440
+						$found = true;
441
+						break;
442
+					}
443
+				}
444
+				if ($found) {
445
+					$message = $tr['isdst']
446
+						?
447
+						__(' Daylight saving time begins on: %s.')
448
+						:
449
+						__(' Standard time begins  on: %s.');
450
+					// Add the difference between the current offset and the new offset to ts to get the correct transition time from date_i18n().
451
+					printf(
452
+						$message,
453
+						'<code >' . date_i18n($datetime_format, $tr['ts'] + ($tz_offset - $tr['offset'])) . '</code >'
454
+					);
455
+				} else {
456
+					_e('This timezone does not observe daylight saving time.');
457
+				}
458
+			}
459
+			// Set back to UTC.
460
+			date_default_timezone_set('UTC');
461
+			?>
462 462
 				</span></p>
463 463
         <?php
464
-    endif;
465
-    }
466
-
467
-
468
-    /**
469
-     * This method will take an incoming unix timestamp and add the offset to it for the given timezone_string.
470
-     * If no unix timestamp is given then time() is used.  If no timezone is given then the set timezone string for
471
-     * the site is used.
472
-     * This is used typically when using a Unix timestamp any core WP functions that expect their specially
473
-     * computed timestamp (i.e. date_i18n() )
474
-     *
475
-     * @param int    $unix_timestamp                  if 0, then time() will be used.
476
-     * @param string $timezone_string                 timezone_string. If empty, then the current set timezone for the
477
-     *                                                site will be used.
478
-     * @return int $unix_timestamp with the offset applied for the given timezone.
479
-     * @throws EE_Error
480
-     */
481
-    public static function get_timestamp_with_offset($unix_timestamp = 0, $timezone_string = '')
482
-    {
483
-        $unix_timestamp  = $unix_timestamp === 0 ? time() : (int) $unix_timestamp;
484
-        $timezone_string = self::get_valid_timezone_string($timezone_string);
485
-        $TimeZone        = new DateTimeZone($timezone_string);
486
-        $DateTime        = new DateTime('@' . $unix_timestamp, $TimeZone);
487
-        $offset          = timezone_offset_get($TimeZone, $DateTime);
488
-        return (int) $DateTime->format('U') + (int) $offset;
489
-    }
490
-
491
-
492
-    /**
493
-     *    _set_date_time_field
494
-     *    modifies EE_Base_Class EE_Datetime_Field objects
495
-     *
496
-     * @param  EE_Base_Class $obj                 EE_Base_Class object
497
-     * @param    DateTime    $DateTime            PHP DateTime object
498
-     * @param  string        $datetime_field_name the datetime fieldname to be manipulated
499
-     * @return EE_Base_Class
500
-     * @throws EE_Error
501
-     */
502
-    protected static function _set_date_time_field(EE_Base_Class $obj, DateTime $DateTime, $datetime_field_name)
503
-    {
504
-        // grab current datetime format
505
-        $current_format = $obj->get_format();
506
-        // set new full timestamp format
507
-        $obj->set_date_format(EE_Datetime_Field::mysql_date_format);
508
-        $obj->set_time_format(EE_Datetime_Field::mysql_time_format);
509
-        // set the new date value using a full timestamp format so that no data is lost
510
-        $obj->set($datetime_field_name, $DateTime->format(EE_Datetime_Field::mysql_timestamp_format));
511
-        // reset datetime formats
512
-        $obj->set_date_format($current_format[0]);
513
-        $obj->set_time_format($current_format[1]);
514
-        return $obj;
515
-    }
516
-
517
-
518
-    /**
519
-     *    date_time_add
520
-     *    helper for doing simple datetime calculations on a given datetime from EE_Base_Class
521
-     *    and modifying it IN the EE_Base_Class so you don't have to do anything else.
522
-     *
523
-     * @param  EE_Base_Class $obj                 EE_Base_Class object
524
-     * @param  string        $datetime_field_name name of the EE_Datetime_Filed datatype db column to be manipulated
525
-     * @param  string        $period              what you are adding. The options are (years, months, days, hours,
526
-     *                                            minutes, seconds) defaults to years
527
-     * @param  integer       $value               what you want to increment the time by
528
-     * @return EE_Base_Class return the EE_Base_Class object so right away you can do something with it
529
-     *                                            (chaining)
530
-     * @throws EE_Error
531
-     * @throws Exception
532
-     */
533
-    public static function date_time_add(EE_Base_Class $obj, $datetime_field_name, $period = 'years', $value = 1)
534
-    {
535
-        //get the raw UTC date.
536
-        $DateTime = $obj->get_DateTime_object($datetime_field_name);
537
-        $DateTime = EEH_DTT_Helper::calc_date($DateTime, $period, $value);
538
-        return EEH_DTT_Helper::_set_date_time_field($obj, $DateTime, $datetime_field_name);
539
-    }
540
-
541
-
542
-    /**
543
-     *    date_time_subtract
544
-     *    same as date_time_add except subtracting value instead of adding.
545
-     *
546
-     * @param EE_Base_Class $obj
547
-     * @param  string       $datetime_field_name name of the EE_Datetime_Filed datatype db column to be manipulated
548
-     * @param string        $period
549
-     * @param int           $value
550
-     * @return EE_Base_Class
551
-     * @throws EE_Error
552
-     * @throws Exception
553
-     */
554
-    public static function date_time_subtract(EE_Base_Class $obj, $datetime_field_name, $period = 'years', $value = 1)
555
-    {
556
-        //get the raw UTC date
557
-        $DateTime = $obj->get_DateTime_object($datetime_field_name);
558
-        $DateTime = EEH_DTT_Helper::calc_date($DateTime, $period, $value, '-');
559
-        return EEH_DTT_Helper::_set_date_time_field($obj, $DateTime, $datetime_field_name);
560
-    }
561
-
562
-
563
-    /**
564
-     * Simply takes an incoming DateTime object and does calculations on it based on the incoming parameters
565
-     *
566
-     * @param  DateTime   $DateTime DateTime object
567
-     * @param  string     $period   a value to indicate what interval is being used in the calculation. The options are
568
-     *                              'years', 'months', 'days', 'hours', 'minutes', 'seconds'. Defaults to years.
569
-     * @param  int|string $value    What you want to increment the date by
570
-     * @param  string     $operand  What operand you wish to use for the calculation
571
-     * @return DateTime return whatever type came in.
572
-     * @throws Exception
573
-     * @throws EE_Error
574
-     */
575
-    protected static function _modify_datetime_object(DateTime $DateTime, $period = 'years', $value = 1, $operand = '+')
576
-    {
577
-        if (! $DateTime instanceof DateTime) {
578
-            throw new EE_Error(
579
-                sprintf(
580
-                    esc_html__('Expected a PHP DateTime object, but instead received %1$s', 'event_espresso'),
581
-                    print_r($DateTime, true)
582
-                )
583
-            );
584
-        }
585
-        switch ($period) {
586
-            case 'years' :
587
-                $value = 'P' . $value . 'Y';
588
-                break;
589
-            case 'months' :
590
-                $value = 'P' . $value . 'M';
591
-                break;
592
-            case 'weeks' :
593
-                $value = 'P' . $value . 'W';
594
-                break;
595
-            case 'days' :
596
-                $value = 'P' . $value . 'D';
597
-                break;
598
-            case 'hours' :
599
-                $value = 'PT' . $value . 'H';
600
-                break;
601
-            case 'minutes' :
602
-                $value = 'PT' . $value . 'M';
603
-                break;
604
-            case 'seconds' :
605
-                $value = 'PT' . $value . 'S';
606
-                break;
607
-        }
608
-        switch ($operand) {
609
-            case '+':
610
-                $DateTime->add(new DateInterval($value));
611
-                break;
612
-            case '-':
613
-                $DateTime->sub(new DateInterval($value));
614
-                break;
615
-        }
616
-        return $DateTime;
617
-    }
618
-
619
-
620
-    /**
621
-     * Simply takes an incoming Unix timestamp and does calculations on it based on the incoming parameters
622
-     *
623
-     * @param  int     $timestamp Unix timestamp
624
-     * @param  string  $period    a value to indicate what interval is being used in the calculation. The options are
625
-     *                            'years', 'months', 'days', 'hours', 'minutes', 'seconds'. Defaults to years.
626
-     * @param  integer $value     What you want to increment the date by
627
-     * @param  string  $operand   What operand you wish to use for the calculation
628
-     * @return int
629
-     * @throws EE_Error
630
-     */
631
-    protected static function _modify_timestamp($timestamp, $period = 'years', $value = 1, $operand = '+')
632
-    {
633
-        if (! preg_match(EE_Datetime_Field::unix_timestamp_regex, $timestamp)) {
634
-            throw new EE_Error(
635
-                sprintf(
636
-                    esc_html__('Expected a Unix timestamp, but instead received %1$s', 'event_espresso'),
637
-                    print_r($timestamp, true)
638
-                )
639
-            );
640
-        }
641
-        switch ($period) {
642
-            case 'years' :
643
-                $value = YEAR_IN_SECONDS * $value;
644
-                break;
645
-            case 'months' :
646
-                $value = YEAR_IN_SECONDS / 12 * $value;
647
-                break;
648
-            case 'weeks' :
649
-                $value = WEEK_IN_SECONDS * $value;
650
-                break;
651
-            case 'days' :
652
-                $value = DAY_IN_SECONDS * $value;
653
-                break;
654
-            case 'hours' :
655
-                $value = HOUR_IN_SECONDS * $value;
656
-                break;
657
-            case 'minutes' :
658
-                $value = MINUTE_IN_SECONDS * $value;
659
-                break;
660
-        }
661
-        switch ($operand) {
662
-            case '+':
663
-                $timestamp += $value;
664
-                break;
665
-            case '-':
666
-                $timestamp -= $value;
667
-                break;
668
-        }
669
-        return $timestamp;
670
-    }
671
-
672
-
673
-    /**
674
-     * Simply takes an incoming UTC timestamp or DateTime object and does calculations on it based on the incoming
675
-     * parameters and returns the new timestamp or DateTime.
676
-     *
677
-     * @param  int | DateTime $DateTime_or_timestamp DateTime object or Unix timestamp
678
-     * @param  string         $period                a value to indicate what interval is being used in the
679
-     *                                               calculation. The options are 'years', 'months', 'days', 'hours',
680
-     *                                               'minutes', 'seconds'. Defaults to years.
681
-     * @param  integer        $value                 What you want to increment the date by
682
-     * @param  string         $operand               What operand you wish to use for the calculation
683
-     * @return mixed string|DateTime          return whatever type came in.
684
-     * @throws Exception
685
-     * @throws EE_Error
686
-     */
687
-    public static function calc_date($DateTime_or_timestamp, $period = 'years', $value = 1, $operand = '+')
688
-    {
689
-        if ($DateTime_or_timestamp instanceof DateTime) {
690
-            return EEH_DTT_Helper::_modify_datetime_object(
691
-                $DateTime_or_timestamp,
692
-                $period,
693
-                $value,
694
-                $operand
695
-            );
696
-        }
697
-        if (preg_match(EE_Datetime_Field::unix_timestamp_regex, $DateTime_or_timestamp)) {
698
-            return EEH_DTT_Helper::_modify_timestamp(
699
-                $DateTime_or_timestamp,
700
-                $period,
701
-                $value,
702
-                $operand
703
-            );
704
-        }
705
-        //error
706
-        return $DateTime_or_timestamp;
707
-    }
708
-
709
-
710
-    /**
711
-     * The purpose of this helper method is to receive an incoming format string in php date/time format
712
-     * and spit out the js and moment.js equivalent formats.
713
-     * Note, if no format string is given, then it is assumed the user wants what is set for WP.
714
-     * Note, js date and time formats are those used by the jquery-ui datepicker and the jquery-ui date-
715
-     * time picker.
716
-     *
717
-     * @see http://stackoverflow.com/posts/16725290/ for the code inspiration.
718
-     * @param string $date_format_string
719
-     * @param string $time_format_string
720
-     * @return array
721
-     *              array(
722
-     *              'js' => array (
723
-     *              'date' => //date format
724
-     *              'time' => //time format
725
-     *              ),
726
-     *              'moment' => //date and time format.
727
-     *              )
728
-     */
729
-    public static function convert_php_to_js_and_moment_date_formats(
730
-        $date_format_string = null,
731
-        $time_format_string = null
732
-    ) {
733
-        if ($date_format_string === null) {
734
-            $date_format_string = (string) get_option('date_format');
735
-        }
736
-        if ($time_format_string === null) {
737
-            $time_format_string = (string) get_option('time_format');
738
-        }
739
-        $date_format = self::_php_to_js_moment_converter($date_format_string);
740
-        $time_format = self::_php_to_js_moment_converter($time_format_string);
741
-        return array(
742
-            'js'     => array(
743
-                'date' => $date_format['js'],
744
-                'time' => $time_format['js'],
745
-            ),
746
-            'moment' => $date_format['moment'] . ' ' . $time_format['moment'],
747
-        );
748
-    }
749
-
750
-
751
-    /**
752
-     * This converts incoming format string into js and moment variations.
753
-     *
754
-     * @param string $format_string incoming php format string
755
-     * @return array js and moment formats.
756
-     */
757
-    protected static function _php_to_js_moment_converter($format_string)
758
-    {
759
-        /**
760
-         * This is a map of symbols for formats.
761
-         * The index is the php symbol, the equivalent values are in the array.
762
-         *
763
-         * @var array
764
-         */
765
-        $symbols_map          = array(
766
-            // Day
767
-            //01
768
-            'd' => array(
769
-                'js'     => 'dd',
770
-                'moment' => 'DD',
771
-            ),
772
-            //Mon
773
-            'D' => array(
774
-                'js'     => 'D',
775
-                'moment' => 'ddd',
776
-            ),
777
-            //1,2,...31
778
-            'j' => array(
779
-                'js'     => 'd',
780
-                'moment' => 'D',
781
-            ),
782
-            //Monday
783
-            'l' => array(
784
-                'js'     => 'DD',
785
-                'moment' => 'dddd',
786
-            ),
787
-            //ISO numeric representation of the day of the week (1-6)
788
-            'N' => array(
789
-                'js'     => '',
790
-                'moment' => 'E',
791
-            ),
792
-            //st,nd.rd
793
-            'S' => array(
794
-                'js'     => '',
795
-                'moment' => 'o',
796
-            ),
797
-            //numeric representation of day of week (0-6)
798
-            'w' => array(
799
-                'js'     => '',
800
-                'moment' => 'd',
801
-            ),
802
-            //day of year starting from 0 (0-365)
803
-            'z' => array(
804
-                'js'     => 'o',
805
-                'moment' => 'DDD' //note moment does not start with 0 so will need to modify by subtracting 1
806
-            ),
807
-            // Week
808
-            //ISO-8601 week number of year (weeks starting on monday)
809
-            'W' => array(
810
-                'js'     => '',
811
-                'moment' => 'w',
812
-            ),
813
-            // Month
814
-            // January...December
815
-            'F' => array(
816
-                'js'     => 'MM',
817
-                'moment' => 'MMMM',
818
-            ),
819
-            //01...12
820
-            'm' => array(
821
-                'js'     => 'mm',
822
-                'moment' => 'MM',
823
-            ),
824
-            //Jan...Dec
825
-            'M' => array(
826
-                'js'     => 'M',
827
-                'moment' => 'MMM',
828
-            ),
829
-            //1-12
830
-            'n' => array(
831
-                'js'     => 'm',
832
-                'moment' => 'M',
833
-            ),
834
-            //number of days in given month
835
-            't' => array(
836
-                'js'     => '',
837
-                'moment' => '',
838
-            ),
839
-            // Year
840
-            //whether leap year or not 1/0
841
-            'L' => array(
842
-                'js'     => '',
843
-                'moment' => '',
844
-            ),
845
-            //ISO-8601 year number
846
-            'o' => array(
847
-                'js'     => '',
848
-                'moment' => 'GGGG',
849
-            ),
850
-            //1999...2003
851
-            'Y' => array(
852
-                'js'     => 'yy',
853
-                'moment' => 'YYYY',
854
-            ),
855
-            //99...03
856
-            'y' => array(
857
-                'js'     => 'y',
858
-                'moment' => 'YY',
859
-            ),
860
-            // Time
861
-            // am/pm
862
-            'a' => array(
863
-                'js'     => 'tt',
864
-                'moment' => 'a',
865
-            ),
866
-            // AM/PM
867
-            'A' => array(
868
-                'js'     => 'TT',
869
-                'moment' => 'A',
870
-            ),
871
-            // Swatch Internet Time?!?
872
-            'B' => array(
873
-                'js'     => '',
874
-                'moment' => '',
875
-            ),
876
-            //1...12
877
-            'g' => array(
878
-                'js'     => 'h',
879
-                'moment' => 'h',
880
-            ),
881
-            //0...23
882
-            'G' => array(
883
-                'js'     => 'H',
884
-                'moment' => 'H',
885
-            ),
886
-            //01...12
887
-            'h' => array(
888
-                'js'     => 'hh',
889
-                'moment' => 'hh',
890
-            ),
891
-            //00...23
892
-            'H' => array(
893
-                'js'     => 'HH',
894
-                'moment' => 'HH',
895
-            ),
896
-            //00..59
897
-            'i' => array(
898
-                'js'     => 'mm',
899
-                'moment' => 'mm',
900
-            ),
901
-            //seconds... 00...59
902
-            's' => array(
903
-                'js'     => 'ss',
904
-                'moment' => 'ss',
905
-            ),
906
-            //microseconds
907
-            'u' => array(
908
-                'js'     => '',
909
-                'moment' => '',
910
-            ),
911
-        );
912
-        $jquery_ui_format     = '';
913
-        $moment_format        = '';
914
-        $escaping             = false;
915
-        $format_string_length = strlen($format_string);
916
-        for ($i = 0; $i < $format_string_length; $i++) {
917
-            $char = $format_string[ $i ];
918
-            if ($char === '\\') { // PHP date format escaping character
919
-                $i++;
920
-                if ($escaping) {
921
-                    $jquery_ui_format .= $format_string[ $i ];
922
-                    $moment_format    .= $format_string[ $i ];
923
-                } else {
924
-                    $jquery_ui_format .= '\'' . $format_string[ $i ];
925
-                    $moment_format    .= $format_string[ $i ];
926
-                }
927
-                $escaping = true;
928
-            } else {
929
-                if ($escaping) {
930
-                    $jquery_ui_format .= "'";
931
-                    $moment_format    .= "'";
932
-                    $escaping         = false;
933
-                }
934
-                if (isset($symbols_map[ $char ])) {
935
-                    $jquery_ui_format .= $symbols_map[ $char ]['js'];
936
-                    $moment_format    .= $symbols_map[ $char ]['moment'];
937
-                } else {
938
-                    $jquery_ui_format .= $char;
939
-                    $moment_format    .= $char;
940
-                }
941
-            }
942
-        }
943
-        return array('js' => $jquery_ui_format, 'moment' => $moment_format);
944
-    }
945
-
946
-
947
-    /**
948
-     * This takes an incoming format string and validates it to ensure it will work fine with PHP.
949
-     *
950
-     * @param string $format_string   Incoming format string for php date().
951
-     * @return mixed bool|array  If all is okay then TRUE is returned.  Otherwise an array of validation
952
-     *                                errors is returned.  So for client code calling, check for is_array() to
953
-     *                                indicate failed validations.
954
-     */
955
-    public static function validate_format_string($format_string)
956
-    {
957
-        $error_msg = array();
958
-        //time format checks
959
-        switch (true) {
960
-            case   strpos($format_string, 'h') !== false  :
961
-            case   strpos($format_string, 'g') !== false :
962
-                /**
963
-                 * if the time string has a lowercase 'h' which == 12 hour time format and there
964
-                 * is not any ante meridiem format ('a' or 'A').  Then throw an error because its
965
-                 * too ambiguous and PHP won't be able to figure out whether 1 = 1pm or 1am.
966
-                 */
967
-                if (stripos($format_string, 'A') === false) {
968
-                    $error_msg[] = esc_html__(
969
-                        'There is a  time format for 12 hour time but no  "a" or "A" to indicate am/pm.  Without this distinction, PHP is unable to determine if a "1" for the hour value equals "1pm" or "1am".',
970
-                        'event_espresso'
971
-                    );
972
-                }
973
-                break;
974
-        }
975
-        return empty($error_msg) ? true : $error_msg;
976
-    }
977
-
978
-
979
-    /**
980
-     *     If the the first date starts at midnight on one day, and the next date ends at midnight on the
981
-     *     very next day then this method will return true.
982
-     *    If $date_1 = 2015-12-15 00:00:00 and $date_2 = 2015-12-16 00:00:00 then this function will return true.
983
-     *    If $date_1 = 2015-12-15 03:00:00 and $date_2 = 2015-12_16 03:00:00 then this function will return false.
984
-     *    If $date_1 = 2015-12-15 00:00:00 and $date_2 = 2015-12-15 00:00:00 then this function will return true.
985
-     *
986
-     * @param mixed $date_1
987
-     * @param mixed $date_2
988
-     * @return bool
989
-     */
990
-    public static function dates_represent_one_24_hour_date($date_1, $date_2)
991
-    {
992
-
993
-        if (
994
-            (! $date_1 instanceof DateTime || ! $date_2 instanceof DateTime)
995
-            || ($date_1->format(EE_Datetime_Field::mysql_time_format) !== '00:00:00'
996
-                || $date_2->format(
997
-                    EE_Datetime_Field::mysql_time_format
998
-                ) !== '00:00:00')
999
-        ) {
1000
-            return false;
1001
-        }
1002
-        return $date_2->format('U') - $date_1->format('U') === 86400;
1003
-    }
1004
-
1005
-
1006
-    /**
1007
-     * This returns the appropriate query interval string that can be used in sql queries involving mysql Date
1008
-     * Functions.
1009
-     *
1010
-     * @param string $timezone_string    A timezone string in a valid format to instantiate a DateTimeZone object.
1011
-     * @param string $field_for_interval The Database field that is the interval is applied to in the query.
1012
-     * @return string
1013
-     */
1014
-    public static function get_sql_query_interval_for_offset($timezone_string, $field_for_interval)
1015
-    {
1016
-        try {
1017
-            /** need to account for timezone offset on the selects */
1018
-            $DateTimeZone = new DateTimeZone($timezone_string);
1019
-        } catch (Exception $e) {
1020
-            $DateTimeZone = null;
1021
-        }
1022
-        /**
1023
-         * Note get_option( 'gmt_offset') returns a value in hours, whereas DateTimeZone::getOffset returns values in seconds.
1024
-         * Hence we do the calc for DateTimeZone::getOffset.
1025
-         */
1026
-        $offset         = $DateTimeZone instanceof DateTimeZone
1027
-            ? $DateTimeZone->getOffset(new DateTime('now')) / HOUR_IN_SECONDS
1028
-            : (float) get_option('gmt_offset');
1029
-        $query_interval = $offset < 0
1030
-            ? 'DATE_SUB(' . $field_for_interval . ', INTERVAL ' . $offset * -1 . ' HOUR)'
1031
-            : 'DATE_ADD(' . $field_for_interval . ', INTERVAL ' . $offset . ' HOUR)';
1032
-        return $query_interval;
1033
-    }
1034
-
1035
-
1036
-    /**
1037
-     * Retrieves the site's default timezone and returns it formatted so it's ready for display
1038
-     * to users. If you want to customize how its displayed feel free to fetch the 'timezone_string'
1039
-     * and 'gmt_offset' WordPress options directly; or use the filter
1040
-     * FHEE__EEH_DTT_Helper__get_timezone_string_for_display
1041
-     * (although note that we remove any HTML that may be added)
1042
-     *
1043
-     * @return string
1044
-     */
1045
-    public static function get_timezone_string_for_display()
1046
-    {
1047
-        $pretty_timezone = apply_filters('FHEE__EEH_DTT_Helper__get_timezone_string_for_display', '');
1048
-        if (! empty($pretty_timezone)) {
1049
-            return esc_html($pretty_timezone);
1050
-        }
1051
-        $timezone_string = get_option('timezone_string');
1052
-        if ($timezone_string) {
1053
-            static $mo_loaded = false;
1054
-            // Load translations for continents and cities just like wp_timezone_choice does
1055
-            if (! $mo_loaded) {
1056
-                $locale = get_locale();
1057
-                $mofile = WP_LANG_DIR . '/continents-cities-' . $locale . '.mo';
1058
-                load_textdomain('continents-cities', $mofile);
1059
-                $mo_loaded = true;
1060
-            }
1061
-            //well that was easy.
1062
-            $parts = explode('/', $timezone_string);
1063
-            //remove the continent
1064
-            unset($parts[0]);
1065
-            $t_parts = array();
1066
-            foreach ($parts as $part) {
1067
-                $t_parts[] = translate(str_replace('_', ' ', $part), 'continents-cities');
1068
-            }
1069
-            return implode(' - ', $t_parts);
1070
-        }
1071
-        //they haven't set the timezone string, so let's return a string like "UTC+1"
1072
-        $gmt_offset = get_option('gmt_offset');
1073
-        $prefix     = (int) $gmt_offset >= 0 ? '+' : '';
1074
-        $parts      = explode('.', (string) $gmt_offset);
1075
-        if (count($parts) === 1) {
1076
-            $parts[1] = '00';
1077
-        } else {
1078
-            //convert the part after the decimal, eg "5" (from x.5) or "25" (from x.25)
1079
-            //to minutes, eg 30 or 15, respectively
1080
-            $hour_fraction = (float) ('0.' . $parts[1]);
1081
-            $parts[1]      = (string) $hour_fraction * 60;
1082
-        }
1083
-        return sprintf(__('UTC%1$s', 'event_espresso'), $prefix . implode(':', $parts));
1084
-    }
1085
-
1086
-
1087
-
1088
-    /**
1089
-     * So PHP does this awesome thing where if you are trying to get a timestamp
1090
-     * for a month using a string like "February" or "February 2017",
1091
-     * and you don't specify a day as part of your string,
1092
-     * then PHP will use whatever the current day of the month is.
1093
-     * IF the current day of the month happens to be the 30th or 31st,
1094
-     * then PHP gets really confused by a date like February 30,
1095
-     * so instead of saying
1096
-     *      "Hey February only has 28 days (this year)...
1097
-     *      ...you must have meant the last day of the month!"
1098
-     * PHP does the next most logical thing, and bumps the date up to March 2nd,
1099
-     * because someone requesting February 30th obviously meant March 1st!
1100
-     * The way around this is to always set the day to the first,
1101
-     * so that the month will stay on the month you wanted.
1102
-     * this method will add that "1" into your date regardless of the format.
1103
-     *
1104
-     * @param string $month
1105
-     * @return string
1106
-     */
1107
-    public static function first_of_month_timestamp($month = '')
1108
-    {
1109
-        $month = (string) $month;
1110
-        $year  = '';
1111
-        // check if the incoming string has a year in it or not
1112
-        if (preg_match('/\b\d{4}\b/', $month, $matches)) {
1113
-            $year = $matches[0];
1114
-            // ten remove that from the month string as well as any spaces
1115
-            $month = trim(str_replace($year, '', $month));
1116
-            // add a space before the year
1117
-            $year = " {$year}";
1118
-        }
1119
-        // return timestamp for something like "February 1 2017"
1120
-        return strtotime("{$month} 1{$year}");
1121
-    }
1122
-
1123
-
1124
-    /**
1125
-     * This simply returns the timestamp for tomorrow (midnight next day) in this sites timezone.  So it may be midnight
1126
-     * for this sites timezone, but the timestamp could be some other time GMT.
1127
-     */
1128
-    public static function tomorrow()
1129
-    {
1130
-        //The multiplication of -1 ensures that we switch positive offsets to negative and negative offsets to positive
1131
-        //before adding to the timestamp.  Why? Because we want tomorrow to be for midnight the next day in THIS timezone
1132
-        //not an offset from midnight in UTC.  So if we're starting with UTC 00:00:00, then we want to make sure the
1133
-        //final timestamp is equivalent to midnight in this timezone as represented in GMT.
1134
-        return strtotime('tomorrow') + (self::get_site_timezone_gmt_offset() * -1);
1135
-    }
1136
-
1137
-
1138
-    /**
1139
-     * **
1140
-     * Gives a nicely-formatted list of timezone strings.
1141
-     * Copied from the core wp function by the same name so we could customize to remove UTC offsets.
1142
-     *
1143
-     * @since     4.9.40.rc.008
1144
-     * @staticvar bool $mo_loaded
1145
-     * @staticvar string $locale_loaded
1146
-     * @param string $selected_zone Selected timezone.
1147
-     * @param string $locale        Optional. Locale to load the timezones in. Default current site locale.
1148
-     * @return string
1149
-     */
1150
-    public static function wp_timezone_choice($selected_zone, $locale = null)
1151
-    {
1152
-        static $mo_loaded = false, $locale_loaded = null;
1153
-        $continents = array(
1154
-            'Africa',
1155
-            'America',
1156
-            'Antarctica',
1157
-            'Arctic',
1158
-            'Asia',
1159
-            'Atlantic',
1160
-            'Australia',
1161
-            'Europe',
1162
-            'Indian',
1163
-            'Pacific',
1164
-        );
1165
-        // Load translations for continents and cities.
1166
-        if (! $mo_loaded || $locale !== $locale_loaded) {
1167
-            $locale_loaded = $locale ? $locale : get_locale();
1168
-            $mofile        = WP_LANG_DIR . '/continents-cities-' . $locale_loaded . '.mo';
1169
-            unload_textdomain('continents-cities');
1170
-            load_textdomain('continents-cities', $mofile);
1171
-            $mo_loaded = true;
1172
-        }
1173
-        $zone_data = array();
1174
-        foreach (timezone_identifiers_list() as $zone) {
1175
-            $zone = explode('/', $zone);
1176
-            if (! in_array($zone[0], $continents, true)) {
1177
-                continue;
1178
-            }
1179
-            // This determines what gets set and translated - we don't translate Etc/* strings here, they are done later
1180
-            $exists      = array(
1181
-                0 => isset($zone[0]) && $zone[0],
1182
-                1 => isset($zone[1]) && $zone[1],
1183
-                2 => isset($zone[2]) && $zone[2],
1184
-            );
1185
-            $exists[3]   = $exists[0] && $zone[0] !== 'Etc';
1186
-            $exists[4]   = $exists[1] && $exists[3];
1187
-            $exists[5]   = $exists[2] && $exists[3];
1188
-            $zone_data[] = array(
1189
-                'continent'   => $exists[0] ? $zone[0] : '',
1190
-                'city'        => $exists[1] ? $zone[1] : '',
1191
-                'subcity'     => $exists[2] ? $zone[2] : '',
1192
-                't_continent' => $exists[3]
1193
-                    ? translate(str_replace('_', ' ', $zone[0]), 'continents-cities')
1194
-                    : '',
1195
-                't_city'      => $exists[4]
1196
-                    ? translate(str_replace('_', ' ', $zone[1]), 'continents-cities')
1197
-                    : '',
1198
-                't_subcity'   => $exists[5]
1199
-                    ? translate(str_replace('_', ' ', $zone[2]), 'continents-cities')
1200
-                    : '',
1201
-            );
1202
-        }
1203
-        usort($zone_data, '_wp_timezone_choice_usort_callback');
1204
-        $structure = array();
1205
-        if (empty($selected_zone)) {
1206
-            $structure[] = '<option selected="selected" value="">' . __('Select a city') . '</option>';
1207
-        }
1208
-        foreach ($zone_data as $key => $zone) {
1209
-            // Build value in an array to join later
1210
-            $value = array($zone['continent']);
1211
-            if (empty($zone['city'])) {
1212
-                // It's at the continent level (generally won't happen)
1213
-                $display = $zone['t_continent'];
1214
-            } else {
1215
-                // It's inside a continent group
1216
-                // Continent optgroup
1217
-                if (! isset($zone_data[ $key - 1 ]) || $zone_data[ $key - 1 ]['continent'] !== $zone['continent']) {
1218
-                    $label       = $zone['t_continent'];
1219
-                    $structure[] = '<optgroup label="' . esc_attr($label) . '">';
1220
-                }
1221
-                // Add the city to the value
1222
-                $value[] = $zone['city'];
1223
-                $display = $zone['t_city'];
1224
-                if (! empty($zone['subcity'])) {
1225
-                    // Add the subcity to the value
1226
-                    $value[] = $zone['subcity'];
1227
-                    $display .= ' - ' . $zone['t_subcity'];
1228
-                }
1229
-            }
1230
-            // Build the value
1231
-            $value       = implode('/', $value);
1232
-            $selected    = $value === $selected_zone ? ' selected="selected"' : '';
1233
-            $structure[] = '<option value="' . esc_attr($value) . '"' . $selected . '>'
1234
-                           . esc_html($display)
1235
-                           . '</option>';
1236
-            // Close continent optgroup
1237
-            if (! empty($zone['city'])
1238
-                && (
1239
-                    ! isset($zone_data[ $key + 1 ])
1240
-                    || (isset($zone_data[ $key + 1 ]) && $zone_data[ $key + 1 ]['continent'] !== $zone['continent'])
1241
-                )
1242
-            ) {
1243
-                $structure[] = '</optgroup>';
1244
-            }
1245
-        }
1246
-        return implode("\n", $structure);
1247
-    }
1248
-
1249
-
1250
-    /**
1251
-     * Shim for the WP function `get_user_locale` that was added in WordPress 4.7.0
1252
-     *
1253
-     * @param int|WP_User $user_id
1254
-     * @return string
1255
-     */
1256
-    public static function get_user_locale($user_id = 0)
1257
-    {
1258
-        if (function_exists('get_user_locale')) {
1259
-            return get_user_locale($user_id);
1260
-        }
1261
-        return get_locale();
1262
-    }
464
+	endif;
465
+	}
466
+
467
+
468
+	/**
469
+	 * This method will take an incoming unix timestamp and add the offset to it for the given timezone_string.
470
+	 * If no unix timestamp is given then time() is used.  If no timezone is given then the set timezone string for
471
+	 * the site is used.
472
+	 * This is used typically when using a Unix timestamp any core WP functions that expect their specially
473
+	 * computed timestamp (i.e. date_i18n() )
474
+	 *
475
+	 * @param int    $unix_timestamp                  if 0, then time() will be used.
476
+	 * @param string $timezone_string                 timezone_string. If empty, then the current set timezone for the
477
+	 *                                                site will be used.
478
+	 * @return int $unix_timestamp with the offset applied for the given timezone.
479
+	 * @throws EE_Error
480
+	 */
481
+	public static function get_timestamp_with_offset($unix_timestamp = 0, $timezone_string = '')
482
+	{
483
+		$unix_timestamp  = $unix_timestamp === 0 ? time() : (int) $unix_timestamp;
484
+		$timezone_string = self::get_valid_timezone_string($timezone_string);
485
+		$TimeZone        = new DateTimeZone($timezone_string);
486
+		$DateTime        = new DateTime('@' . $unix_timestamp, $TimeZone);
487
+		$offset          = timezone_offset_get($TimeZone, $DateTime);
488
+		return (int) $DateTime->format('U') + (int) $offset;
489
+	}
490
+
491
+
492
+	/**
493
+	 *    _set_date_time_field
494
+	 *    modifies EE_Base_Class EE_Datetime_Field objects
495
+	 *
496
+	 * @param  EE_Base_Class $obj                 EE_Base_Class object
497
+	 * @param    DateTime    $DateTime            PHP DateTime object
498
+	 * @param  string        $datetime_field_name the datetime fieldname to be manipulated
499
+	 * @return EE_Base_Class
500
+	 * @throws EE_Error
501
+	 */
502
+	protected static function _set_date_time_field(EE_Base_Class $obj, DateTime $DateTime, $datetime_field_name)
503
+	{
504
+		// grab current datetime format
505
+		$current_format = $obj->get_format();
506
+		// set new full timestamp format
507
+		$obj->set_date_format(EE_Datetime_Field::mysql_date_format);
508
+		$obj->set_time_format(EE_Datetime_Field::mysql_time_format);
509
+		// set the new date value using a full timestamp format so that no data is lost
510
+		$obj->set($datetime_field_name, $DateTime->format(EE_Datetime_Field::mysql_timestamp_format));
511
+		// reset datetime formats
512
+		$obj->set_date_format($current_format[0]);
513
+		$obj->set_time_format($current_format[1]);
514
+		return $obj;
515
+	}
516
+
517
+
518
+	/**
519
+	 *    date_time_add
520
+	 *    helper for doing simple datetime calculations on a given datetime from EE_Base_Class
521
+	 *    and modifying it IN the EE_Base_Class so you don't have to do anything else.
522
+	 *
523
+	 * @param  EE_Base_Class $obj                 EE_Base_Class object
524
+	 * @param  string        $datetime_field_name name of the EE_Datetime_Filed datatype db column to be manipulated
525
+	 * @param  string        $period              what you are adding. The options are (years, months, days, hours,
526
+	 *                                            minutes, seconds) defaults to years
527
+	 * @param  integer       $value               what you want to increment the time by
528
+	 * @return EE_Base_Class return the EE_Base_Class object so right away you can do something with it
529
+	 *                                            (chaining)
530
+	 * @throws EE_Error
531
+	 * @throws Exception
532
+	 */
533
+	public static function date_time_add(EE_Base_Class $obj, $datetime_field_name, $period = 'years', $value = 1)
534
+	{
535
+		//get the raw UTC date.
536
+		$DateTime = $obj->get_DateTime_object($datetime_field_name);
537
+		$DateTime = EEH_DTT_Helper::calc_date($DateTime, $period, $value);
538
+		return EEH_DTT_Helper::_set_date_time_field($obj, $DateTime, $datetime_field_name);
539
+	}
540
+
541
+
542
+	/**
543
+	 *    date_time_subtract
544
+	 *    same as date_time_add except subtracting value instead of adding.
545
+	 *
546
+	 * @param EE_Base_Class $obj
547
+	 * @param  string       $datetime_field_name name of the EE_Datetime_Filed datatype db column to be manipulated
548
+	 * @param string        $period
549
+	 * @param int           $value
550
+	 * @return EE_Base_Class
551
+	 * @throws EE_Error
552
+	 * @throws Exception
553
+	 */
554
+	public static function date_time_subtract(EE_Base_Class $obj, $datetime_field_name, $period = 'years', $value = 1)
555
+	{
556
+		//get the raw UTC date
557
+		$DateTime = $obj->get_DateTime_object($datetime_field_name);
558
+		$DateTime = EEH_DTT_Helper::calc_date($DateTime, $period, $value, '-');
559
+		return EEH_DTT_Helper::_set_date_time_field($obj, $DateTime, $datetime_field_name);
560
+	}
561
+
562
+
563
+	/**
564
+	 * Simply takes an incoming DateTime object and does calculations on it based on the incoming parameters
565
+	 *
566
+	 * @param  DateTime   $DateTime DateTime object
567
+	 * @param  string     $period   a value to indicate what interval is being used in the calculation. The options are
568
+	 *                              'years', 'months', 'days', 'hours', 'minutes', 'seconds'. Defaults to years.
569
+	 * @param  int|string $value    What you want to increment the date by
570
+	 * @param  string     $operand  What operand you wish to use for the calculation
571
+	 * @return DateTime return whatever type came in.
572
+	 * @throws Exception
573
+	 * @throws EE_Error
574
+	 */
575
+	protected static function _modify_datetime_object(DateTime $DateTime, $period = 'years', $value = 1, $operand = '+')
576
+	{
577
+		if (! $DateTime instanceof DateTime) {
578
+			throw new EE_Error(
579
+				sprintf(
580
+					esc_html__('Expected a PHP DateTime object, but instead received %1$s', 'event_espresso'),
581
+					print_r($DateTime, true)
582
+				)
583
+			);
584
+		}
585
+		switch ($period) {
586
+			case 'years' :
587
+				$value = 'P' . $value . 'Y';
588
+				break;
589
+			case 'months' :
590
+				$value = 'P' . $value . 'M';
591
+				break;
592
+			case 'weeks' :
593
+				$value = 'P' . $value . 'W';
594
+				break;
595
+			case 'days' :
596
+				$value = 'P' . $value . 'D';
597
+				break;
598
+			case 'hours' :
599
+				$value = 'PT' . $value . 'H';
600
+				break;
601
+			case 'minutes' :
602
+				$value = 'PT' . $value . 'M';
603
+				break;
604
+			case 'seconds' :
605
+				$value = 'PT' . $value . 'S';
606
+				break;
607
+		}
608
+		switch ($operand) {
609
+			case '+':
610
+				$DateTime->add(new DateInterval($value));
611
+				break;
612
+			case '-':
613
+				$DateTime->sub(new DateInterval($value));
614
+				break;
615
+		}
616
+		return $DateTime;
617
+	}
618
+
619
+
620
+	/**
621
+	 * Simply takes an incoming Unix timestamp and does calculations on it based on the incoming parameters
622
+	 *
623
+	 * @param  int     $timestamp Unix timestamp
624
+	 * @param  string  $period    a value to indicate what interval is being used in the calculation. The options are
625
+	 *                            'years', 'months', 'days', 'hours', 'minutes', 'seconds'. Defaults to years.
626
+	 * @param  integer $value     What you want to increment the date by
627
+	 * @param  string  $operand   What operand you wish to use for the calculation
628
+	 * @return int
629
+	 * @throws EE_Error
630
+	 */
631
+	protected static function _modify_timestamp($timestamp, $period = 'years', $value = 1, $operand = '+')
632
+	{
633
+		if (! preg_match(EE_Datetime_Field::unix_timestamp_regex, $timestamp)) {
634
+			throw new EE_Error(
635
+				sprintf(
636
+					esc_html__('Expected a Unix timestamp, but instead received %1$s', 'event_espresso'),
637
+					print_r($timestamp, true)
638
+				)
639
+			);
640
+		}
641
+		switch ($period) {
642
+			case 'years' :
643
+				$value = YEAR_IN_SECONDS * $value;
644
+				break;
645
+			case 'months' :
646
+				$value = YEAR_IN_SECONDS / 12 * $value;
647
+				break;
648
+			case 'weeks' :
649
+				$value = WEEK_IN_SECONDS * $value;
650
+				break;
651
+			case 'days' :
652
+				$value = DAY_IN_SECONDS * $value;
653
+				break;
654
+			case 'hours' :
655
+				$value = HOUR_IN_SECONDS * $value;
656
+				break;
657
+			case 'minutes' :
658
+				$value = MINUTE_IN_SECONDS * $value;
659
+				break;
660
+		}
661
+		switch ($operand) {
662
+			case '+':
663
+				$timestamp += $value;
664
+				break;
665
+			case '-':
666
+				$timestamp -= $value;
667
+				break;
668
+		}
669
+		return $timestamp;
670
+	}
671
+
672
+
673
+	/**
674
+	 * Simply takes an incoming UTC timestamp or DateTime object and does calculations on it based on the incoming
675
+	 * parameters and returns the new timestamp or DateTime.
676
+	 *
677
+	 * @param  int | DateTime $DateTime_or_timestamp DateTime object or Unix timestamp
678
+	 * @param  string         $period                a value to indicate what interval is being used in the
679
+	 *                                               calculation. The options are 'years', 'months', 'days', 'hours',
680
+	 *                                               'minutes', 'seconds'. Defaults to years.
681
+	 * @param  integer        $value                 What you want to increment the date by
682
+	 * @param  string         $operand               What operand you wish to use for the calculation
683
+	 * @return mixed string|DateTime          return whatever type came in.
684
+	 * @throws Exception
685
+	 * @throws EE_Error
686
+	 */
687
+	public static function calc_date($DateTime_or_timestamp, $period = 'years', $value = 1, $operand = '+')
688
+	{
689
+		if ($DateTime_or_timestamp instanceof DateTime) {
690
+			return EEH_DTT_Helper::_modify_datetime_object(
691
+				$DateTime_or_timestamp,
692
+				$period,
693
+				$value,
694
+				$operand
695
+			);
696
+		}
697
+		if (preg_match(EE_Datetime_Field::unix_timestamp_regex, $DateTime_or_timestamp)) {
698
+			return EEH_DTT_Helper::_modify_timestamp(
699
+				$DateTime_or_timestamp,
700
+				$period,
701
+				$value,
702
+				$operand
703
+			);
704
+		}
705
+		//error
706
+		return $DateTime_or_timestamp;
707
+	}
708
+
709
+
710
+	/**
711
+	 * The purpose of this helper method is to receive an incoming format string in php date/time format
712
+	 * and spit out the js and moment.js equivalent formats.
713
+	 * Note, if no format string is given, then it is assumed the user wants what is set for WP.
714
+	 * Note, js date and time formats are those used by the jquery-ui datepicker and the jquery-ui date-
715
+	 * time picker.
716
+	 *
717
+	 * @see http://stackoverflow.com/posts/16725290/ for the code inspiration.
718
+	 * @param string $date_format_string
719
+	 * @param string $time_format_string
720
+	 * @return array
721
+	 *              array(
722
+	 *              'js' => array (
723
+	 *              'date' => //date format
724
+	 *              'time' => //time format
725
+	 *              ),
726
+	 *              'moment' => //date and time format.
727
+	 *              )
728
+	 */
729
+	public static function convert_php_to_js_and_moment_date_formats(
730
+		$date_format_string = null,
731
+		$time_format_string = null
732
+	) {
733
+		if ($date_format_string === null) {
734
+			$date_format_string = (string) get_option('date_format');
735
+		}
736
+		if ($time_format_string === null) {
737
+			$time_format_string = (string) get_option('time_format');
738
+		}
739
+		$date_format = self::_php_to_js_moment_converter($date_format_string);
740
+		$time_format = self::_php_to_js_moment_converter($time_format_string);
741
+		return array(
742
+			'js'     => array(
743
+				'date' => $date_format['js'],
744
+				'time' => $time_format['js'],
745
+			),
746
+			'moment' => $date_format['moment'] . ' ' . $time_format['moment'],
747
+		);
748
+	}
749
+
750
+
751
+	/**
752
+	 * This converts incoming format string into js and moment variations.
753
+	 *
754
+	 * @param string $format_string incoming php format string
755
+	 * @return array js and moment formats.
756
+	 */
757
+	protected static function _php_to_js_moment_converter($format_string)
758
+	{
759
+		/**
760
+		 * This is a map of symbols for formats.
761
+		 * The index is the php symbol, the equivalent values are in the array.
762
+		 *
763
+		 * @var array
764
+		 */
765
+		$symbols_map          = array(
766
+			// Day
767
+			//01
768
+			'd' => array(
769
+				'js'     => 'dd',
770
+				'moment' => 'DD',
771
+			),
772
+			//Mon
773
+			'D' => array(
774
+				'js'     => 'D',
775
+				'moment' => 'ddd',
776
+			),
777
+			//1,2,...31
778
+			'j' => array(
779
+				'js'     => 'd',
780
+				'moment' => 'D',
781
+			),
782
+			//Monday
783
+			'l' => array(
784
+				'js'     => 'DD',
785
+				'moment' => 'dddd',
786
+			),
787
+			//ISO numeric representation of the day of the week (1-6)
788
+			'N' => array(
789
+				'js'     => '',
790
+				'moment' => 'E',
791
+			),
792
+			//st,nd.rd
793
+			'S' => array(
794
+				'js'     => '',
795
+				'moment' => 'o',
796
+			),
797
+			//numeric representation of day of week (0-6)
798
+			'w' => array(
799
+				'js'     => '',
800
+				'moment' => 'd',
801
+			),
802
+			//day of year starting from 0 (0-365)
803
+			'z' => array(
804
+				'js'     => 'o',
805
+				'moment' => 'DDD' //note moment does not start with 0 so will need to modify by subtracting 1
806
+			),
807
+			// Week
808
+			//ISO-8601 week number of year (weeks starting on monday)
809
+			'W' => array(
810
+				'js'     => '',
811
+				'moment' => 'w',
812
+			),
813
+			// Month
814
+			// January...December
815
+			'F' => array(
816
+				'js'     => 'MM',
817
+				'moment' => 'MMMM',
818
+			),
819
+			//01...12
820
+			'm' => array(
821
+				'js'     => 'mm',
822
+				'moment' => 'MM',
823
+			),
824
+			//Jan...Dec
825
+			'M' => array(
826
+				'js'     => 'M',
827
+				'moment' => 'MMM',
828
+			),
829
+			//1-12
830
+			'n' => array(
831
+				'js'     => 'm',
832
+				'moment' => 'M',
833
+			),
834
+			//number of days in given month
835
+			't' => array(
836
+				'js'     => '',
837
+				'moment' => '',
838
+			),
839
+			// Year
840
+			//whether leap year or not 1/0
841
+			'L' => array(
842
+				'js'     => '',
843
+				'moment' => '',
844
+			),
845
+			//ISO-8601 year number
846
+			'o' => array(
847
+				'js'     => '',
848
+				'moment' => 'GGGG',
849
+			),
850
+			//1999...2003
851
+			'Y' => array(
852
+				'js'     => 'yy',
853
+				'moment' => 'YYYY',
854
+			),
855
+			//99...03
856
+			'y' => array(
857
+				'js'     => 'y',
858
+				'moment' => 'YY',
859
+			),
860
+			// Time
861
+			// am/pm
862
+			'a' => array(
863
+				'js'     => 'tt',
864
+				'moment' => 'a',
865
+			),
866
+			// AM/PM
867
+			'A' => array(
868
+				'js'     => 'TT',
869
+				'moment' => 'A',
870
+			),
871
+			// Swatch Internet Time?!?
872
+			'B' => array(
873
+				'js'     => '',
874
+				'moment' => '',
875
+			),
876
+			//1...12
877
+			'g' => array(
878
+				'js'     => 'h',
879
+				'moment' => 'h',
880
+			),
881
+			//0...23
882
+			'G' => array(
883
+				'js'     => 'H',
884
+				'moment' => 'H',
885
+			),
886
+			//01...12
887
+			'h' => array(
888
+				'js'     => 'hh',
889
+				'moment' => 'hh',
890
+			),
891
+			//00...23
892
+			'H' => array(
893
+				'js'     => 'HH',
894
+				'moment' => 'HH',
895
+			),
896
+			//00..59
897
+			'i' => array(
898
+				'js'     => 'mm',
899
+				'moment' => 'mm',
900
+			),
901
+			//seconds... 00...59
902
+			's' => array(
903
+				'js'     => 'ss',
904
+				'moment' => 'ss',
905
+			),
906
+			//microseconds
907
+			'u' => array(
908
+				'js'     => '',
909
+				'moment' => '',
910
+			),
911
+		);
912
+		$jquery_ui_format     = '';
913
+		$moment_format        = '';
914
+		$escaping             = false;
915
+		$format_string_length = strlen($format_string);
916
+		for ($i = 0; $i < $format_string_length; $i++) {
917
+			$char = $format_string[ $i ];
918
+			if ($char === '\\') { // PHP date format escaping character
919
+				$i++;
920
+				if ($escaping) {
921
+					$jquery_ui_format .= $format_string[ $i ];
922
+					$moment_format    .= $format_string[ $i ];
923
+				} else {
924
+					$jquery_ui_format .= '\'' . $format_string[ $i ];
925
+					$moment_format    .= $format_string[ $i ];
926
+				}
927
+				$escaping = true;
928
+			} else {
929
+				if ($escaping) {
930
+					$jquery_ui_format .= "'";
931
+					$moment_format    .= "'";
932
+					$escaping         = false;
933
+				}
934
+				if (isset($symbols_map[ $char ])) {
935
+					$jquery_ui_format .= $symbols_map[ $char ]['js'];
936
+					$moment_format    .= $symbols_map[ $char ]['moment'];
937
+				} else {
938
+					$jquery_ui_format .= $char;
939
+					$moment_format    .= $char;
940
+				}
941
+			}
942
+		}
943
+		return array('js' => $jquery_ui_format, 'moment' => $moment_format);
944
+	}
945
+
946
+
947
+	/**
948
+	 * This takes an incoming format string and validates it to ensure it will work fine with PHP.
949
+	 *
950
+	 * @param string $format_string   Incoming format string for php date().
951
+	 * @return mixed bool|array  If all is okay then TRUE is returned.  Otherwise an array of validation
952
+	 *                                errors is returned.  So for client code calling, check for is_array() to
953
+	 *                                indicate failed validations.
954
+	 */
955
+	public static function validate_format_string($format_string)
956
+	{
957
+		$error_msg = array();
958
+		//time format checks
959
+		switch (true) {
960
+			case   strpos($format_string, 'h') !== false  :
961
+			case   strpos($format_string, 'g') !== false :
962
+				/**
963
+				 * if the time string has a lowercase 'h' which == 12 hour time format and there
964
+				 * is not any ante meridiem format ('a' or 'A').  Then throw an error because its
965
+				 * too ambiguous and PHP won't be able to figure out whether 1 = 1pm or 1am.
966
+				 */
967
+				if (stripos($format_string, 'A') === false) {
968
+					$error_msg[] = esc_html__(
969
+						'There is a  time format for 12 hour time but no  "a" or "A" to indicate am/pm.  Without this distinction, PHP is unable to determine if a "1" for the hour value equals "1pm" or "1am".',
970
+						'event_espresso'
971
+					);
972
+				}
973
+				break;
974
+		}
975
+		return empty($error_msg) ? true : $error_msg;
976
+	}
977
+
978
+
979
+	/**
980
+	 *     If the the first date starts at midnight on one day, and the next date ends at midnight on the
981
+	 *     very next day then this method will return true.
982
+	 *    If $date_1 = 2015-12-15 00:00:00 and $date_2 = 2015-12-16 00:00:00 then this function will return true.
983
+	 *    If $date_1 = 2015-12-15 03:00:00 and $date_2 = 2015-12_16 03:00:00 then this function will return false.
984
+	 *    If $date_1 = 2015-12-15 00:00:00 and $date_2 = 2015-12-15 00:00:00 then this function will return true.
985
+	 *
986
+	 * @param mixed $date_1
987
+	 * @param mixed $date_2
988
+	 * @return bool
989
+	 */
990
+	public static function dates_represent_one_24_hour_date($date_1, $date_2)
991
+	{
992
+
993
+		if (
994
+			(! $date_1 instanceof DateTime || ! $date_2 instanceof DateTime)
995
+			|| ($date_1->format(EE_Datetime_Field::mysql_time_format) !== '00:00:00'
996
+				|| $date_2->format(
997
+					EE_Datetime_Field::mysql_time_format
998
+				) !== '00:00:00')
999
+		) {
1000
+			return false;
1001
+		}
1002
+		return $date_2->format('U') - $date_1->format('U') === 86400;
1003
+	}
1004
+
1005
+
1006
+	/**
1007
+	 * This returns the appropriate query interval string that can be used in sql queries involving mysql Date
1008
+	 * Functions.
1009
+	 *
1010
+	 * @param string $timezone_string    A timezone string in a valid format to instantiate a DateTimeZone object.
1011
+	 * @param string $field_for_interval The Database field that is the interval is applied to in the query.
1012
+	 * @return string
1013
+	 */
1014
+	public static function get_sql_query_interval_for_offset($timezone_string, $field_for_interval)
1015
+	{
1016
+		try {
1017
+			/** need to account for timezone offset on the selects */
1018
+			$DateTimeZone = new DateTimeZone($timezone_string);
1019
+		} catch (Exception $e) {
1020
+			$DateTimeZone = null;
1021
+		}
1022
+		/**
1023
+		 * Note get_option( 'gmt_offset') returns a value in hours, whereas DateTimeZone::getOffset returns values in seconds.
1024
+		 * Hence we do the calc for DateTimeZone::getOffset.
1025
+		 */
1026
+		$offset         = $DateTimeZone instanceof DateTimeZone
1027
+			? $DateTimeZone->getOffset(new DateTime('now')) / HOUR_IN_SECONDS
1028
+			: (float) get_option('gmt_offset');
1029
+		$query_interval = $offset < 0
1030
+			? 'DATE_SUB(' . $field_for_interval . ', INTERVAL ' . $offset * -1 . ' HOUR)'
1031
+			: 'DATE_ADD(' . $field_for_interval . ', INTERVAL ' . $offset . ' HOUR)';
1032
+		return $query_interval;
1033
+	}
1034
+
1035
+
1036
+	/**
1037
+	 * Retrieves the site's default timezone and returns it formatted so it's ready for display
1038
+	 * to users. If you want to customize how its displayed feel free to fetch the 'timezone_string'
1039
+	 * and 'gmt_offset' WordPress options directly; or use the filter
1040
+	 * FHEE__EEH_DTT_Helper__get_timezone_string_for_display
1041
+	 * (although note that we remove any HTML that may be added)
1042
+	 *
1043
+	 * @return string
1044
+	 */
1045
+	public static function get_timezone_string_for_display()
1046
+	{
1047
+		$pretty_timezone = apply_filters('FHEE__EEH_DTT_Helper__get_timezone_string_for_display', '');
1048
+		if (! empty($pretty_timezone)) {
1049
+			return esc_html($pretty_timezone);
1050
+		}
1051
+		$timezone_string = get_option('timezone_string');
1052
+		if ($timezone_string) {
1053
+			static $mo_loaded = false;
1054
+			// Load translations for continents and cities just like wp_timezone_choice does
1055
+			if (! $mo_loaded) {
1056
+				$locale = get_locale();
1057
+				$mofile = WP_LANG_DIR . '/continents-cities-' . $locale . '.mo';
1058
+				load_textdomain('continents-cities', $mofile);
1059
+				$mo_loaded = true;
1060
+			}
1061
+			//well that was easy.
1062
+			$parts = explode('/', $timezone_string);
1063
+			//remove the continent
1064
+			unset($parts[0]);
1065
+			$t_parts = array();
1066
+			foreach ($parts as $part) {
1067
+				$t_parts[] = translate(str_replace('_', ' ', $part), 'continents-cities');
1068
+			}
1069
+			return implode(' - ', $t_parts);
1070
+		}
1071
+		//they haven't set the timezone string, so let's return a string like "UTC+1"
1072
+		$gmt_offset = get_option('gmt_offset');
1073
+		$prefix     = (int) $gmt_offset >= 0 ? '+' : '';
1074
+		$parts      = explode('.', (string) $gmt_offset);
1075
+		if (count($parts) === 1) {
1076
+			$parts[1] = '00';
1077
+		} else {
1078
+			//convert the part after the decimal, eg "5" (from x.5) or "25" (from x.25)
1079
+			//to minutes, eg 30 or 15, respectively
1080
+			$hour_fraction = (float) ('0.' . $parts[1]);
1081
+			$parts[1]      = (string) $hour_fraction * 60;
1082
+		}
1083
+		return sprintf(__('UTC%1$s', 'event_espresso'), $prefix . implode(':', $parts));
1084
+	}
1085
+
1086
+
1087
+
1088
+	/**
1089
+	 * So PHP does this awesome thing where if you are trying to get a timestamp
1090
+	 * for a month using a string like "February" or "February 2017",
1091
+	 * and you don't specify a day as part of your string,
1092
+	 * then PHP will use whatever the current day of the month is.
1093
+	 * IF the current day of the month happens to be the 30th or 31st,
1094
+	 * then PHP gets really confused by a date like February 30,
1095
+	 * so instead of saying
1096
+	 *      "Hey February only has 28 days (this year)...
1097
+	 *      ...you must have meant the last day of the month!"
1098
+	 * PHP does the next most logical thing, and bumps the date up to March 2nd,
1099
+	 * because someone requesting February 30th obviously meant March 1st!
1100
+	 * The way around this is to always set the day to the first,
1101
+	 * so that the month will stay on the month you wanted.
1102
+	 * this method will add that "1" into your date regardless of the format.
1103
+	 *
1104
+	 * @param string $month
1105
+	 * @return string
1106
+	 */
1107
+	public static function first_of_month_timestamp($month = '')
1108
+	{
1109
+		$month = (string) $month;
1110
+		$year  = '';
1111
+		// check if the incoming string has a year in it or not
1112
+		if (preg_match('/\b\d{4}\b/', $month, $matches)) {
1113
+			$year = $matches[0];
1114
+			// ten remove that from the month string as well as any spaces
1115
+			$month = trim(str_replace($year, '', $month));
1116
+			// add a space before the year
1117
+			$year = " {$year}";
1118
+		}
1119
+		// return timestamp for something like "February 1 2017"
1120
+		return strtotime("{$month} 1{$year}");
1121
+	}
1122
+
1123
+
1124
+	/**
1125
+	 * This simply returns the timestamp for tomorrow (midnight next day) in this sites timezone.  So it may be midnight
1126
+	 * for this sites timezone, but the timestamp could be some other time GMT.
1127
+	 */
1128
+	public static function tomorrow()
1129
+	{
1130
+		//The multiplication of -1 ensures that we switch positive offsets to negative and negative offsets to positive
1131
+		//before adding to the timestamp.  Why? Because we want tomorrow to be for midnight the next day in THIS timezone
1132
+		//not an offset from midnight in UTC.  So if we're starting with UTC 00:00:00, then we want to make sure the
1133
+		//final timestamp is equivalent to midnight in this timezone as represented in GMT.
1134
+		return strtotime('tomorrow') + (self::get_site_timezone_gmt_offset() * -1);
1135
+	}
1136
+
1137
+
1138
+	/**
1139
+	 * **
1140
+	 * Gives a nicely-formatted list of timezone strings.
1141
+	 * Copied from the core wp function by the same name so we could customize to remove UTC offsets.
1142
+	 *
1143
+	 * @since     4.9.40.rc.008
1144
+	 * @staticvar bool $mo_loaded
1145
+	 * @staticvar string $locale_loaded
1146
+	 * @param string $selected_zone Selected timezone.
1147
+	 * @param string $locale        Optional. Locale to load the timezones in. Default current site locale.
1148
+	 * @return string
1149
+	 */
1150
+	public static function wp_timezone_choice($selected_zone, $locale = null)
1151
+	{
1152
+		static $mo_loaded = false, $locale_loaded = null;
1153
+		$continents = array(
1154
+			'Africa',
1155
+			'America',
1156
+			'Antarctica',
1157
+			'Arctic',
1158
+			'Asia',
1159
+			'Atlantic',
1160
+			'Australia',
1161
+			'Europe',
1162
+			'Indian',
1163
+			'Pacific',
1164
+		);
1165
+		// Load translations for continents and cities.
1166
+		if (! $mo_loaded || $locale !== $locale_loaded) {
1167
+			$locale_loaded = $locale ? $locale : get_locale();
1168
+			$mofile        = WP_LANG_DIR . '/continents-cities-' . $locale_loaded . '.mo';
1169
+			unload_textdomain('continents-cities');
1170
+			load_textdomain('continents-cities', $mofile);
1171
+			$mo_loaded = true;
1172
+		}
1173
+		$zone_data = array();
1174
+		foreach (timezone_identifiers_list() as $zone) {
1175
+			$zone = explode('/', $zone);
1176
+			if (! in_array($zone[0], $continents, true)) {
1177
+				continue;
1178
+			}
1179
+			// This determines what gets set and translated - we don't translate Etc/* strings here, they are done later
1180
+			$exists      = array(
1181
+				0 => isset($zone[0]) && $zone[0],
1182
+				1 => isset($zone[1]) && $zone[1],
1183
+				2 => isset($zone[2]) && $zone[2],
1184
+			);
1185
+			$exists[3]   = $exists[0] && $zone[0] !== 'Etc';
1186
+			$exists[4]   = $exists[1] && $exists[3];
1187
+			$exists[5]   = $exists[2] && $exists[3];
1188
+			$zone_data[] = array(
1189
+				'continent'   => $exists[0] ? $zone[0] : '',
1190
+				'city'        => $exists[1] ? $zone[1] : '',
1191
+				'subcity'     => $exists[2] ? $zone[2] : '',
1192
+				't_continent' => $exists[3]
1193
+					? translate(str_replace('_', ' ', $zone[0]), 'continents-cities')
1194
+					: '',
1195
+				't_city'      => $exists[4]
1196
+					? translate(str_replace('_', ' ', $zone[1]), 'continents-cities')
1197
+					: '',
1198
+				't_subcity'   => $exists[5]
1199
+					? translate(str_replace('_', ' ', $zone[2]), 'continents-cities')
1200
+					: '',
1201
+			);
1202
+		}
1203
+		usort($zone_data, '_wp_timezone_choice_usort_callback');
1204
+		$structure = array();
1205
+		if (empty($selected_zone)) {
1206
+			$structure[] = '<option selected="selected" value="">' . __('Select a city') . '</option>';
1207
+		}
1208
+		foreach ($zone_data as $key => $zone) {
1209
+			// Build value in an array to join later
1210
+			$value = array($zone['continent']);
1211
+			if (empty($zone['city'])) {
1212
+				// It's at the continent level (generally won't happen)
1213
+				$display = $zone['t_continent'];
1214
+			} else {
1215
+				// It's inside a continent group
1216
+				// Continent optgroup
1217
+				if (! isset($zone_data[ $key - 1 ]) || $zone_data[ $key - 1 ]['continent'] !== $zone['continent']) {
1218
+					$label       = $zone['t_continent'];
1219
+					$structure[] = '<optgroup label="' . esc_attr($label) . '">';
1220
+				}
1221
+				// Add the city to the value
1222
+				$value[] = $zone['city'];
1223
+				$display = $zone['t_city'];
1224
+				if (! empty($zone['subcity'])) {
1225
+					// Add the subcity to the value
1226
+					$value[] = $zone['subcity'];
1227
+					$display .= ' - ' . $zone['t_subcity'];
1228
+				}
1229
+			}
1230
+			// Build the value
1231
+			$value       = implode('/', $value);
1232
+			$selected    = $value === $selected_zone ? ' selected="selected"' : '';
1233
+			$structure[] = '<option value="' . esc_attr($value) . '"' . $selected . '>'
1234
+						   . esc_html($display)
1235
+						   . '</option>';
1236
+			// Close continent optgroup
1237
+			if (! empty($zone['city'])
1238
+				&& (
1239
+					! isset($zone_data[ $key + 1 ])
1240
+					|| (isset($zone_data[ $key + 1 ]) && $zone_data[ $key + 1 ]['continent'] !== $zone['continent'])
1241
+				)
1242
+			) {
1243
+				$structure[] = '</optgroup>';
1244
+			}
1245
+		}
1246
+		return implode("\n", $structure);
1247
+	}
1248
+
1249
+
1250
+	/**
1251
+	 * Shim for the WP function `get_user_locale` that was added in WordPress 4.7.0
1252
+	 *
1253
+	 * @param int|WP_User $user_id
1254
+	 * @return string
1255
+	 */
1256
+	public static function get_user_locale($user_id = 0)
1257
+	{
1258
+		if (function_exists('get_user_locale')) {
1259
+			return get_user_locale($user_id);
1260
+		}
1261
+		return get_locale();
1262
+	}
1263 1263
 
1264 1264
 }
Please login to merge, or discard this patch.