Completed
Branch FET-8385-datetime-ticket-selec... (ec342c)
by
unknown
45:18 queued 34:32
created

EE_Datetime_Field   D

Complexity

Total Complexity 84

Size/Duplication

Total Lines 755
Duplicated Lines 4.5 %

Coupling/Cohesion

Components 2
Dependencies 4

Importance

Changes 0
Metric Value
dl 34
loc 755
rs 4.4444
c 0
b 0
f 0
wmc 84
lcom 2
cbo 4

29 Methods

Rating   Name   Duplication   Size   Complexity  
A get_blog_DateTimeZone() 0 6 2
B __construct() 0 21 5
A get_wpdb_data_type() 0 4 1
A get_UTC_DateTimeZone() 0 6 2
A prepare_for_set() 0 4 1
B _get_date_time_output() 0 18 6
A set_date_time_output() 0 4 1
A set_timezone() 0 11 4
A _create_timezone_object_from_timezone_string() 0 4 1
A get_timezone() 0 4 1
A set_date_format() 0 8 2
A get_date_format() 0 4 2
A set_time_format() 0 8 2
A get_time_format() 0 4 2
A set_pretty_date_format() 0 4 1
A set_pretty_time_format() 0 4 1
A prepare_for_set_with_new_time() 17 20 2
A prepare_for_set_with_new_date() 17 20 2
A prepare_for_get() 0 4 1
A prepare_for_pretty_echoing() 0 4 2
C _prepare_for_display() 0 50 7
C prepare_for_use_in_db() 0 25 7
B prepare_for_set_from_db() 0 32 6
A _display_timezone() 0 15 2
C _get_date_object() 0 59 10
B get_timezone_transitions() 0 7 6
A get_timezone_offset() 0 8 2
A get_timezone_abbrev() 0 7 1
A get_default_value() 0 8 2

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like EE_Datetime_Field often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use EE_Datetime_Field, and based on these observations, apply Extract Interface, too.

1
<?php use EventEspresso\core\domain\entities\DbSafeDateTime;
2
3
if (! defined('EVENT_ESPRESSO_VERSION')) {
4
    exit('No direct script access allowed');
5
}
6
7
/**
8
 * EE_Datetime_Field
9
 * Text_Fields is a base class for any fields which are have integer value. (Exception: foreign and private key fields.
10
 * Wish PHP had multiple-inheritance for this...)
11
 *
12
 * @package               Event Espresso
13
 * @subpackage            /core/db_models/fields/EE_Datetime_Field.php
14
 * @author                Darren Ethier
15
 */
16
class EE_Datetime_Field extends EE_Model_Field_Base
17
{
18
19
    /**
20
     * The pattern we're looking for is if only the characters 0-9 are found and there are only
21
     * 10 or more numbers (because 9 numbers even with all 9's would be sometime in 2001 )
22
     *
23
     * @type string unix_timestamp_regex
24
     */
25
    const unix_timestamp_regex = '/[0-9]{10,}/';
26
27
    /**
28
     * @type string mysql_timestamp_format
29
     */
30
    const mysql_timestamp_format = 'Y-m-d H:i:s';
31
32
    /**
33
     * @type string mysql_date_format
34
     */
35
    const mysql_date_format = 'Y-m-d';
36
37
    /**
38
     * @type string mysql_time_format
39
     */
40
    const mysql_time_format = 'H:i:s';
41
42
    /**
43
     * Const for using in the default value. If the field's default is set to this,
44
     * then we will return the time of calling `get_default_value()`, not
45
     * just the current time at construction
46
     */
47
    const now = 'now';
48
49
    /**
50
     * The following properties hold the default formats for date and time.
51
     * Defaults are set via the constructor and can be overridden on class instantiation.
52
     * However they can also be overridden later by the set_format() method
53
     * (and corresponding set_date_format, set_time_format methods);
54
     */
55
    /**
56
     * @type string $_date_format
57
     */
58
    protected $_date_format = '';
59
60
    /**
61
     * @type string $_time_format
62
     */
63
    protected $_time_format = '';
64
65
    /**
66
     * @type string $_pretty_date_format
67
     */
68
    protected $_pretty_date_format = '';
69
70
    /**
71
     * @type string $_pretty_time_format
72
     */
73
    protected $_pretty_time_format = '';
74
75
    /**
76
     * @type DateTimeZone $_DateTimeZone
77
     */
78
    protected $_DateTimeZone;
79
80
    /**
81
     * @type DateTimeZone $_UTC_DateTimeZone
82
     */
83
    protected $_UTC_DateTimeZone;
84
85
    /**
86
     * @type DateTimeZone $_blog_DateTimeZone
87
     */
88
    protected $_blog_DateTimeZone;
89
90
91
    /**
92
     * This property holds how we want the output returned when getting a datetime string.  It is set for the
93
     * set_date_time_output() method.  By default this is empty.  When empty, we are assuming that we want both date
94
     * and time returned via getters.
95
     *
96
     * @var mixed (null|string)
97
     */
98
    protected $_date_time_output;
99
100
101
    /**
102
     * timezone string
103
     * This gets set by the constructor and can be changed by the "set_timezone()" method so that we know what timezone
104
     * incoming strings|timestamps are in.  This can also be used before a get to set what timezone you want strings
105
     * coming out of the object to be in.  Default timezone is the current WP timezone option setting
106
     *
107
     * @var string
108
     */
109
    protected $_timezone_string;
110
111
112
    /**
113
     * This holds whatever UTC offset for the blog (we automatically convert timezone strings into their related
114
     * offsets for comparison purposes).
115
     *
116
     * @var int
117
     */
118
    protected $_blog_offset;
119
120
121
    /**
122
     * @param string $table_column
123
     * @param string $nice_name
124
     * @param bool   $nullable
125
     * @param string $default_value
126
     * @param string $timezone_string
127
     * @param string $date_format
128
     * @param string $time_format
129
     * @param string $pretty_date_format
130
     * @param string $pretty_time_format
131
     * @throws \EE_Error
132
     */
133
    public function __construct(
134
        $table_column,
135
        $nice_name,
136
        $nullable,
137
        $default_value,
138
        $timezone_string = '',
139
        $date_format = '',
140
        $time_format = '',
141
        $pretty_date_format = '',
142
        $pretty_time_format = ''
143
    ) {
144
145
        $this->_date_format        = ! empty($date_format) ? $date_format : get_option('date_format');
146
        $this->_time_format        = ! empty($time_format) ? $time_format : get_option('time_format');
147
        $this->_pretty_date_format = ! empty($pretty_date_format) ? $pretty_date_format : get_option('date_format');
148
        $this->_pretty_time_format = ! empty($pretty_time_format) ? $pretty_time_format : get_option('time_format');
149
150
        parent::__construct($table_column, $nice_name, $nullable, $default_value);
151
        $this->set_timezone($timezone_string);
152
153
    }
154
155
156
    /**
157
     * @return string
158
     */
159
    public function get_wpdb_data_type()
160
    {
161
        return '%s';
162
    }
163
164
165
    /**
166
     * @return DateTimeZone
167
     * @throws \EE_Error
168
     */
169
    public function get_UTC_DateTimeZone()
170
    {
171
        return $this->_UTC_DateTimeZone instanceof DateTimeZone
172
            ? $this->_UTC_DateTimeZone
173
            : $this->_create_timezone_object_from_timezone_string('UTC');
174
    }
175
176
177
    /**
178
     * @return DateTimeZone
179
     * @throws \EE_Error
180
     */
181
    public function get_blog_DateTimeZone()
182
    {
183
        return $this->_blog_DateTimeZone instanceof DateTimeZone
184
            ? $this->_blog_DateTimeZone
185
            : $this->_create_timezone_object_from_timezone_string('');
186
    }
187
188
189
    /**
190
     * this prepares any incoming date data and make sure its converted to a utc unix timestamp
191
     *
192
     * @param  string|int $value_inputted_for_field_on_model_object could be a string formatted date time or int unix
193
     *                                                              timestamp
194
     * @return DateTime
195
     */
196
    public function prepare_for_set($value_inputted_for_field_on_model_object)
197
    {
198
        return $this->_get_date_object($value_inputted_for_field_on_model_object);
199
    }
200
201
202
    /**
203
     * This returns the format string to be used by getters depending on what the $_date_time_output property is set at.
204
     * getters need to know whether we're just returning the date or the time or both.  By default we return both.
205
     *
206
     * @param bool $pretty If we're returning the pretty formats or standard format string.
207
     * @return string    The final assembled format string.
208
     */
209
    protected function _get_date_time_output($pretty = false)
210
    {
211
212
        switch ($this->_date_time_output) {
213
            case 'time' :
214
                return $pretty ? $this->_pretty_time_format : $this->_time_format;
215
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
216
217
            case 'date' :
218
                return $pretty ? $this->_pretty_date_format : $this->_date_format;
219
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
220
221
            default :
222
                return $pretty
223
                    ? $this->_pretty_date_format . ' ' . $this->_pretty_time_format
224
                    : $this->_date_format . ' ' . $this->_time_format;
225
        }
226
    }
227
228
229
    /**
230
     * This just sets the $_date_time_output property so we can flag how date and times are formatted before being
231
     * returned (using the format properties)
232
     *
233
     * @param string $what acceptable values are 'time' or 'date'.
234
     *                     Any other value will be set but will always result
235
     *                     in both 'date' and 'time' being returned.
236
     * @return void
237
     */
238
    public function set_date_time_output($what = null)
239
    {
240
        $this->_date_time_output = $what;
241
    }
242
243
244
    /**
245
     * See $_timezone property for description of what the timezone property is for.  This SETS the timezone internally
246
     * for being able to reference what timezone we are running conversions on when converting TO the internal timezone
247
     * (UTC Unix Timestamp) for the object OR when converting FROM the internal timezone (UTC Unix Timestamp).
248
     * We also set some other properties in this method.
249
     *
250
     * @param string $timezone_string A valid timezone string as described by @link
251
     *                                http://www.php.net/manual/en/timezones.php
252
     * @return void
253
     * @throws \EE_Error
254
     */
255
    public function set_timezone($timezone_string)
256
    {
257
        if (empty($timezone_string) && $this->_timezone_string !== null) {
258
            // leave the timezone AS-IS if we already have one and
259
            // the function arg didn't provide one
260
            return;
261
        }
262
        $timezone_string        = EEH_DTT_Helper::get_valid_timezone_string($timezone_string);
263
        $this->_timezone_string = ! empty($timezone_string) ? $timezone_string : 'UTC';
264
        $this->_DateTimeZone    = $this->_create_timezone_object_from_timezone_string($this->_timezone_string);
265
    }
266
267
268
    /**
269
     * _create_timezone_object_from_timezone_name
270
     *
271
     * @access protected
272
     * @param string $timezone_string
273
     * @return \DateTimeZone
274
     * @throws \EE_Error
275
     */
276
    protected function _create_timezone_object_from_timezone_string($timezone_string = '')
277
    {
278
        return new DateTimeZone(EEH_DTT_Helper::get_valid_timezone_string($timezone_string));
279
    }
280
281
282
    /**
283
     * This just returns whatever is set for the current timezone.
284
     *
285
     * @access public
286
     * @return string timezone string
287
     */
288
    public function get_timezone()
289
    {
290
        return $this->_timezone_string;
291
    }
292
293
294
    /**
295
     * set the $_date_format property
296
     *
297
     * @access public
298
     * @param string $format a new date format (corresponding to formats accepted by PHP date() function)
299
     * @param bool   $pretty Whether to set pretty format or not.
300
     * @return void
301
     */
302
    public function set_date_format($format, $pretty = false)
303
    {
304
        if ($pretty) {
305
            $this->_pretty_date_format = $format;
306
        } else {
307
            $this->_date_format = $format;
308
        }
309
    }
310
311
312
    /**
313
     * return the $_date_format property value.
314
     *
315
     * @param bool $pretty Whether to get pretty format or not.
316
     * @return string
317
     */
318
    public function get_date_format($pretty = false)
319
    {
320
        return $pretty ? $this->_pretty_date_format : $this->_date_format;
321
    }
322
323
324
    /**
325
     * set the $_time_format property
326
     *
327
     * @access public
328
     * @param string $format a new time format (corresponding to formats accepted by PHP date() function)
329
     * @param bool   $pretty Whether to set pretty format or not.
330
     * @return void
331
     */
332
    public function set_time_format($format, $pretty = false)
333
    {
334
        if ($pretty) {
335
            $this->_pretty_time_format = $format;
336
        } else {
337
            $this->_time_format = $format;
338
        }
339
    }
340
341
342
    /**
343
     * return the $_time_format property value.
344
     *
345
     * @param bool $pretty Whether to get pretty format or not.
346
     * @return string
347
     */
348
    public function get_time_format($pretty = false)
349
    {
350
        return $pretty ? $this->_pretty_time_format : $this->_time_format;
351
    }
352
353
354
    /**
355
     * set the $_pretty_date_format property
356
     *
357
     * @access public
358
     * @param string $format a new pretty date format (corresponding to formats accepted by PHP date() function)
359
     * @return void
360
     */
361
    public function set_pretty_date_format($format)
362
    {
363
        $this->_pretty_date_format = $format;
364
    }
365
366
367
    /**
368
     * set the $_pretty_time_format property
369
     *
370
     * @access public
371
     * @param string $format a new pretty time format (corresponding to formats accepted by PHP date() function)
372
     * @return void
373
     */
374
    public function set_pretty_time_format($format)
375
    {
376
        $this->_pretty_time_format = $format;
377
    }
378
379
380
    /**
381
     * Only sets the time portion of the datetime.
382
     *
383
     * @param string|DateTime $time_to_set_string like 8am OR a DateTime object.
384
     * @param DateTime        $current            current DateTime object for the datetime field
385
     * @return DateTime
386
     */
387 View Code Duplication
    public function prepare_for_set_with_new_time($time_to_set_string, DateTime $current)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
388
    {
389
        // if $time_to_set_string is datetime object, then let's use it to set the parse array.
390
        // Otherwise parse the string.
391
        if ($time_to_set_string instanceof DateTime) {
392
            $parsed = array(
393
                'hour'   => $time_to_set_string->format('H'),
394
                'minute' => $time_to_set_string->format('i'),
395
                'second' => $time_to_set_string->format('s'),
396
            );
397
        } else {
398
            //parse incoming string
399
            $parsed = date_parse_from_format($this->_time_format, $time_to_set_string);
400
        }
401
402
        //make sure $current is in the correct timezone.
403
        $current->setTimezone($this->_DateTimeZone);
404
405
        return $current->setTime($parsed['hour'], $parsed['minute'], $parsed['second']);
406
    }
407
408
409
    /**
410
     * Only sets the date portion of the datetime.
411
     *
412
     * @param string|DateTime $date_to_set_string like Friday, January 8th or a DateTime object.
413
     * @param DateTime        $current            current DateTime object for the datetime field
414
     * @return DateTime
415
     */
416 View Code Duplication
    public function prepare_for_set_with_new_date($date_to_set_string, DateTime $current)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
417
    {
418
        // if $time_to_set_string is datetime object, then let's use it to set the parse array.
419
        // Otherwise parse the string.
420
        if ($date_to_set_string instanceof DateTime) {
421
            $parsed = array(
422
                'year'  => $date_to_set_string->format('Y'),
423
                'month' => $date_to_set_string->format('m'),
424
                'day'   => $date_to_set_string->format('d'),
425
            );
426
        } else {
427
            //parse incoming string
428
            $parsed = date_parse_from_format($this->_date_format, $date_to_set_string);
429
        }
430
431
        //make sure $current is in the correct timezone
432
        $current->setTimezone($this->_DateTimeZone);
433
434
        return $current->setDate($parsed['year'], $parsed['month'], $parsed['day']);
435
    }
436
437
438
    /**
439
     * This prepares the EE_DateTime value to be saved to the db as mysql timestamp (UTC +0 timezone).  When the
440
     * datetime gets to this stage it should ALREADY be in UTC time
441
     *
442
     * @param  DateTime $DateTime
443
     * @return string formatted date time for given timezone
444
     * @throws \EE_Error
445
     */
446
    public function prepare_for_get($DateTime)
447
    {
448
        return $this->_prepare_for_display($DateTime);
449
    }
450
451
452
    /**
453
     * This differs from prepare_for_get in that it considers whether the internal $_timezone differs
454
     * from the set wp timezone.  If so, then it returns the datetime string formatted via
455
     * _pretty_date_format, and _pretty_time_format.  However, it also appends a timezone
456
     * abbreviation to the date_string.
457
     *
458
     * @param mixed $DateTime
459
     * @param null  $schema
460
     * @return string
461
     * @throws \EE_Error
462
     */
463
    public function prepare_for_pretty_echoing($DateTime, $schema = null)
464
    {
465
        return $this->_prepare_for_display($DateTime, $schema ? $schema : true);
466
    }
467
468
469
    /**
470
     * This prepares the EE_DateTime value to be saved to the db as mysql timestamp (UTC +0
471
     * timezone).
472
     *
473
     * @param DateTime    $DateTime
474
     * @param bool|string $schema
475
     * @return string
476
     * @throws \EE_Error
477
     */
478
    protected function _prepare_for_display($DateTime, $schema = false)
479
    {
480
        if (! $DateTime instanceof DateTime) {
481
            if ($this->_nullable) {
482
                return '';
483
            } else {
484
                if (WP_DEBUG) {
485
                    throw new EE_Error(
486
                        sprintf(
487
                            __(
488
                                'EE_Datetime_Field::_prepare_for_display requires a DateTime class to be the value for the $DateTime argument because the %s field is not nullable.',
489
                                'event_espresso'
490
                            ),
491
                            $this->_nicename
492
                        )
493
                    );
494
                } else {
495
                    $DateTime = new DbSafeDateTime(\EE_Datetime_Field::now);
496
                    EE_Error::add_error(
497
                        sprintf(
498
                            __(
499
                                'EE_Datetime_Field::_prepare_for_display requires a DateTime class to be the value for the $DateTime argument because the %s field is not nullable.  When WP_DEBUG is false, the value is set to "now" instead of throwing an exception.',
500
                                'event_espresso'
501
                            ),
502
                            $this->_nicename
503
                        )
504
                    );
505
                }
506
            }
507
        }
508
        $format_string = $this->_get_date_time_output($schema);
0 ignored issues
show
Bug introduced by
It seems like $schema defined by parameter $schema on line 478 can also be of type string; however, EE_Datetime_Field::_get_date_time_output() does only seem to accept boolean, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
509
        //make sure datetime_value is in the correct timezone (in case that's been updated).
510
        $DateTime->setTimezone($this->_DateTimeZone);
511
        if ($schema) {
512
            if ($this->_display_timezone()) {
513
                //must be explicit because schema could equal true.
514
                if ($schema === 'no_html') {
515
                    $timezone_string = ' (' . $DateTime->format('T') . ')';
516
                } else {
517
                    $timezone_string = ' <span class="ee_dtt_timezone_string">(' . $DateTime->format('T') . ')</span>';
518
                }
519
            } else {
520
                $timezone_string = '';
521
            }
522
523
            return $DateTime->format($format_string) . $timezone_string;
524
        } else {
525
            return $DateTime->format($format_string);
526
        }
527
    }
528
529
530
    /**
531
     * This prepares the EE_DateTime value to be saved to the db as mysql timestamp (UTC +0
532
     * timezone).
533
     *
534
     * @param  mixed $datetime_value u
535
     * @return string mysql timestamp in UTC
536
     * @throws \EE_Error
537
     */
538
    public function prepare_for_use_in_db($datetime_value)
539
    {
540
        //we allow an empty value or DateTime object, but nothing else.
541
        if (! empty($datetime_value) && ! $datetime_value instanceof DateTime) {
542
            throw new EE_Error(
543
                __(
544
                    'The incoming value being prepared for setting in the database must either be empty or a php DateTime object',
545
                    'event_espresso'
546
                )
547
            );
548
        }
549
550
        if ($datetime_value instanceof DateTime) {
551
            if ( ! $datetime_value instanceof DbSafeDateTime) {
552
                $datetime_value = DbSafeDateTime::createFromDateTime($datetime_value);
553
            }
554
555
            return $datetime_value->setTimezone($this->get_UTC_DateTimeZone())->format(
556
                EE_Datetime_Field::mysql_timestamp_format
557
            );
558
        }
559
560
        // if $datetime_value is empty, and ! $this->_nullable, use current_time() but set the GMT flag to true
561
        return ! $this->_nullable && empty($datetime_value) ? current_time('mysql', true) : null;
562
    }
563
564
565
    /**
566
     * This prepares the datetime for internal usage as a PHP DateTime object OR null (if nullable is
567
     * allowed)
568
     *
569
     * @param string $datetime_string mysql timestamp in UTC
570
     * @return  mixed null | DateTime
571
     * @throws \EE_Error
572
     */
573
    public function prepare_for_set_from_db($datetime_string)
574
    {
575
        //if $datetime_value is empty, and ! $this->_nullable, just use time()
576
        if (empty($datetime_string) && $this->_nullable) {
577
            return null;
578
        }
579
        // datetime strings from the db should ALWAYS be in UTC+0, so use UTC_DateTimeZone when creating
580
        if (empty($datetime_string)) {
581
            $DateTime = new DbSafeDateTime(\EE_Datetime_Field::now, $this->get_UTC_DateTimeZone());
582
        } else {
583
            $DateTime = DateTime::createFromFormat(
584
                EE_Datetime_Field::mysql_timestamp_format,
585
                $datetime_string,
586
                $this->get_UTC_DateTimeZone()
587
            );
588
            if ($DateTime instanceof \DateTime) {
589
                $DateTime = new DbSafeDateTime(
590
                    $DateTime->format(\EE_Datetime_Field::mysql_timestamp_format),
591
                    $this->get_UTC_DateTimeZone()
592
                );
593
            }
594
        }
595
596
        if (! $DateTime instanceof DbSafeDateTime) {
597
            // if still no datetime object, then let's just use now
598
            $DateTime = new DbSafeDateTime(\EE_Datetime_Field::now, $this->get_UTC_DateTimeZone());
599
        }
600
        // THEN apply the field's set DateTimeZone
601
        $DateTime->setTimezone($this->_DateTimeZone);
602
603
        return $DateTime;
604
    }
605
606
607
    /**
608
     * All this method does is determine if we're going to display the timezone string or not on any output.
609
     * To determine this we check if the set timezone offset is different than the blog's set timezone offset.
610
     * If so, then true.
611
     *
612
     * @return bool true for yes false for no
613
     * @throws \EE_Error
614
     */
615
    protected function _display_timezone()
616
    {
617
618
        // first let's do a comparison of timezone strings.
619
        // If they match then we can get out without any further calculations
620
        $blog_string = get_option('timezone_string');
621
        if ($blog_string === $this->_timezone_string) {
622
            return false;
623
        }
624
        // now we need to calc the offset for the timezone string so we can compare with the blog offset.
625
        $this_offset = $this->get_timezone_offset($this->_DateTimeZone);
626
        $blog_offset = $this->get_timezone_offset($this->get_blog_DateTimeZone());
627
        // now compare
628
        return $blog_offset !== $this_offset;
629
    }
630
631
632
    /**
633
     * This method returns a php DateTime object for setting on the EE_Base_Class model.
634
     * EE passes around DateTime objects because they are MUCH easier to manipulate and deal
635
     * with.
636
     *
637
     * @param int|string|DateTime $date_string            This should be the incoming date string.  It's assumed to be
638
     *                                                    in the format that is set on the date_field (or DateTime
639
     *                                                    object)!
640
     * @return DateTime
641
     */
642
    protected function _get_date_object($date_string)
643
    {
644
        //first if this is an empty date_string and nullable is allowed, just return null.
645
        if ($this->_nullable && empty($date_string)) {
646
            return null;
647
        }
648
649
        // if incoming date
650
        if ($date_string instanceof DateTime) {
651
            $date_string->setTimezone($this->_DateTimeZone);
652
653
            return $date_string;
654
        }
655
        // if empty date_string and made it here.
656
        // Return a datetime object for now in the given timezone.
657
        if (empty($date_string)) {
658
            return new DbSafeDateTime(\EE_Datetime_Field::now, $this->_DateTimeZone);
659
        }
660
        // if $date_string is matches something that looks like a Unix timestamp let's just use it.
661
        if (preg_match(EE_Datetime_Field::unix_timestamp_regex, $date_string)) {
662
            try {
663
                // This is operating under the assumption that the incoming Unix timestamp
664
                // is an ACTUAL Unix timestamp and not the calculated one output by current_time('timestamp');
665
                $DateTime = new DbSafeDateTime(\EE_Datetime_Field::now, $this->_DateTimeZone);
666
                $DateTime->setTimestamp($date_string);
667
668
                return $DateTime;
669
            } catch (Exception $e) {
670
                // should be rare, but if things got fooled then let's just continue
671
            }
672
        }
673
        //not a unix timestamp.  So we will use the set format on this object and set timezone to
674
        //create the DateTime object.
675
        $format = $this->_date_format . ' ' . $this->_time_format;
676
        try {
677
            $DateTime = DateTime::createFromFormat($format, $date_string, $this->_DateTimeZone);
678
            if ($DateTime instanceof DateTime) {
679
                $DateTime = new DbSafeDateTime(
680
                    $DateTime->format(\EE_Datetime_Field::mysql_timestamp_format),
681
                    $this->_DateTimeZone
682
                );
683
            }
684
            if (! $DateTime instanceof DbSafeDateTime) {
685
                throw new EE_Error(
686
                    sprintf(
687
                        __('"%1$s" does not represent a valid Date Time in the format "%2$s".', 'event_espresso'),
688
                        $date_string,
689
                        $format
690
                    )
691
                );
692
            }
693
        } catch (Exception $e) {
694
            // if we made it here then likely then something went really wrong.
695
            // Instead of throwing an exception, let's just return a DateTime object for now, in the set timezone.
696
            $DateTime = new DbSafeDateTime(\EE_Datetime_Field::now, $this->_DateTimeZone);
697
        }
698
699
        return $DateTime;
700
    }
701
702
703
704
    /**
705
     * get_timezone_transitions
706
     *
707
     * @param \DateTimeZone $DateTimeZone
708
     * @param int           $time
709
     * @param bool          $first_only
710
     * @return mixed
711
     */
712
    public function get_timezone_transitions(DateTimeZone $DateTimeZone, $time = null, $first_only = true)
713
    {
714
        $time = is_int($time) || $time === null ? $time : strtotime($time);
715
        $time = preg_match(EE_Datetime_Field::unix_timestamp_regex, $time) ? $time : time();
716
        $transitions = $DateTimeZone->getTransitions($time);
717
        return $first_only && ! isset($transitions['ts']) ? reset($transitions) : $transitions;
718
    }
719
720
721
722
    /**
723
     * get_timezone_offset
724
     *
725
     * @param \DateTimeZone $DateTimeZone
726
     * @param int           $time
727
     * @return mixed
728
     * @throws \DomainException
729
     */
730
    public function get_timezone_offset(DateTimeZone $DateTimeZone, $time = null)
731
    {
732
        $transitions = $this->get_timezone_transitions($DateTimeZone, $time);
733
        if ( ! isset($transitions['offset'])) {
734
            throw new DomainException();
735
        }
736
        return $transitions['offset'];
737
    }
738
739
740
    /**
741
     * This will take an incoming timezone string and return the abbreviation for that timezone
742
     *
743
     * @param  string $timezone_string
744
     * @return string           abbreviation
745
     * @throws \EE_Error
746
     */
747
    public function get_timezone_abbrev($timezone_string)
748
    {
749
        $timezone_string = EEH_DTT_Helper::get_valid_timezone_string($timezone_string);
750
        $dateTime        = new DateTime(\EE_Datetime_Field::now, new DateTimeZone($timezone_string));
751
752
        return $dateTime->format('T');
753
    }
754
755
    /**
756
     * Overrides the parent to allow for having a dynamic "now" value
757
     *
758
     * @return mixed
759
     */
760
    public function get_default_value()
761
    {
762
        if ($this->_default_value === EE_Datetime_Field::now) {
763
            return time();
764
        } else {
765
            return parent::get_default_value();
766
        }
767
    }
768
769
770
}
771