Completed
Branch BUG-10324-unit-tests-php7.1 (acc21a)
by
unknown
139:31 queued 129:15
created

EE_Datetime_Field   D

Complexity

Total Complexity 84

Size/Duplication

Total Lines 780
Duplicated Lines 4.36 %

Coupling/Cohesion

Components 2
Dependencies 4

Importance

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

29 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 21 5
A get_wpdb_data_type() 0 4 1
A get_UTC_DateTimeZone() 0 6 2
A get_blog_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 28 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
 *
10
 * Text_Fields is a base class for any fields which are have integer value. (Exception: foreign and private key fields.
11
 * Wish PHP had multiple-inheritance for this...)
12
 *
13
 * @package               Event Espresso
14
 * @subpackage            /core/db_models/fields/EE_Datetime_Field.php
15
 * @author                Darren Ethier
16
 */
17
class EE_Datetime_Field extends EE_Model_Field_Base
18
{
19
20
    /**
21
     * The pattern we're looking for is if only the characters 0-9 are found and there are only
22
     * 10 or more numbers (because 9 numbers even with all 9's would be sometime in 2001 )
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
     * @var mixed (null|string)
96
     */
97
    protected $_date_time_output;
98
99
100
    /**
101
     * timezone string
102
     * This gets set by the constructor and can be changed by the "set_timezone()" method so that we know what timezone
103
     * incoming strings|timestamps are in.  This can also be used before a get to set what timezone you want strings
104
     * coming out of the object to be in.  Default timezone is the current WP timezone option setting
105
     * @var string
106
     */
107
    protected $_timezone_string;
108
109
110
    /**
111
     * This holds whatever UTC offset for the blog (we automatically convert timezone strings into their related
112
     * offsets for comparison purposes).
113
     * @var int
114
     */
115
    protected $_blog_offset;
116
117
118
119
	/**
120
	 * @param string $table_column
121
	 * @param string $nice_name
122
	 * @param bool   $nullable
123
	 * @param string $default_value
124
	 * @param string $timezone_string
125
	 * @param string $date_format
126
	 * @param string $time_format
127
	 * @param string $pretty_date_format
128
	 * @param string $pretty_time_format
129
	 * @throws \EE_Error
130
	 */
131
    public function __construct(
132
        $table_column,
133
        $nice_name,
134
        $nullable,
135
        $default_value,
136
        $timezone_string = '',
137
        $date_format = '',
138
        $time_format = '',
139
        $pretty_date_format = '',
140
        $pretty_time_format = ''
141
    ) {
142
143
        $this->_date_format        = ! empty($date_format) ? $date_format : get_option('date_format');
144
        $this->_time_format        = ! empty($time_format) ? $time_format : get_option('time_format');
145
        $this->_pretty_date_format = ! empty($pretty_date_format) ? $pretty_date_format : get_option('date_format');
146
        $this->_pretty_time_format = ! empty($pretty_time_format) ? $pretty_time_format : get_option('time_format');
147
148
        parent::__construct($table_column, $nice_name, $nullable, $default_value);
149
        $this->set_timezone($timezone_string);
150
151
    }
152
153
154
    /**
155
     * @return string
156
     */
157
    public function get_wpdb_data_type()
158
    {
159
        return '%s';
160
    }
161
162
163
164
	/**
165
	 * @return DateTimeZone
166
	 * @throws \EE_Error
167
	 */
168
    public function get_UTC_DateTimeZone()
169
    {
170
        return $this->_UTC_DateTimeZone instanceof DateTimeZone
171
	        ? $this->_UTC_DateTimeZone
172
	        : $this->_create_timezone_object_from_timezone_string('UTC');
173
    }
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
     *
195
     * @return DateTime
196
     */
197
    public function prepare_for_set($value_inputted_for_field_on_model_object)
198
    {
199
        return $this->_get_date_object($value_inputted_for_field_on_model_object);
200
    }
201
202
203
    /**
204
     * This returns the format string to be used by getters depending on what the $_date_time_output property is set at.
205
     *
206
     * getters need to know whether we're just returning the date or the time or both.  By default we return both.
207
     *
208
     * @param bool $pretty If we're returning the pretty formats or standard format string.
209
     * @return string    The final assembled format string.
210
     */
211
    protected function _get_date_time_output($pretty = false)
212
    {
213
214
        switch ($this->_date_time_output) {
215
            case 'time' :
216
                return $pretty ? $this->_pretty_time_format : $this->_time_format;
217
                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...
218
219
            case 'date' :
220
                return $pretty ? $this->_pretty_date_format : $this->_date_format;
221
                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...
222
223
            default :
224
                return $pretty
225
	                ? $this->_pretty_date_format . ' ' . $this->_pretty_time_format
226
	                : $this->_date_format . ' ' . $this->_time_format;
227
        }
228
    }
229
230
231
    /**
232
     * This just sets the $_date_time_output property so we can flag how date and times are formatted before being
233
     * returned (using the format properties)
234
     *
235
     * @param string $what acceptable values are 'time' or 'date'.
236
     *                     Any other value will be set but will always result
237
     *                     in both 'date' and 'time' being returned.
238
     * @return void
239
     */
240
    public function set_date_time_output($what = null)
241
    {
242
        $this->_date_time_output = $what;
243
    }
244
245
246
247
	/**
248
	 * See $_timezone property for description of what the timezone property is for.  This SETS the timezone internally
249
	 * for being able to reference what timezone we are running conversions on when converting TO the internal timezone
250
	 * (UTC Unix Timestamp) for the object OR when converting FROM the internal timezone (UTC Unix Timestamp).
251
	 * We also set some other properties in this method.
252
	 *
253
	 * @param string $timezone_string A valid timezone string as described by @link
254
	 *                                http://www.php.net/manual/en/timezones.php
255
	 * @return void
256
	 * @throws \EE_Error
257
	 */
258
    public function set_timezone($timezone_string)
259
    {
260
        if (empty($timezone_string) && $this->_timezone_string !== null) {
261
            // leave the timezone AS-IS if we already have one and
262
            // the function arg didn't provide one
263
            return;
264
        }
265
        $timezone_string        = EEH_DTT_Helper::get_valid_timezone_string($timezone_string);
266
        $this->_timezone_string = ! empty($timezone_string) ? $timezone_string : 'UTC';
267
        $this->_DateTimeZone    = $this->_create_timezone_object_from_timezone_string($this->_timezone_string);
268
    }
269
270
271
272
	/**
273
	 * _create_timezone_object_from_timezone_name
274
	 *
275
	 * @access protected
276
	 * @param string $timezone_string
277
	 * @return \DateTimeZone
278
	 * @throws \EE_Error
279
	 */
280
    protected function _create_timezone_object_from_timezone_string($timezone_string = '')
281
    {
282
        return new DateTimeZone(EEH_DTT_Helper::get_valid_timezone_string($timezone_string));
283
    }
284
285
286
    /**
287
     * This just returns whatever is set for the current timezone.
288
     *
289
     * @access public
290
     * @return string timezone string
291
     */
292
    public function get_timezone()
293
    {
294
        return $this->_timezone_string;
295
    }
296
297
298
    /**
299
     * set the $_date_format property
300
     *
301
     * @access public
302
     *
303
     * @param string $format a new date format (corresponding to formats accepted by PHP date() function)
304
     * @param bool   $pretty Whether to set pretty format or not.
305
     *
306
     * @return void
307
     */
308
    public function set_date_format($format, $pretty = false)
309
    {
310
        if ($pretty) {
311
            $this->_pretty_date_format = $format;
312
        } else {
313
            $this->_date_format = $format;
314
        }
315
    }
316
317
318
    /**
319
     * return the $_date_format property value.
320
     *
321
     * @param bool $pretty Whether to get pretty format or not.
322
     *
323
     * @return string
324
     */
325
    public function get_date_format($pretty = false)
326
    {
327
        return $pretty ? $this->_pretty_date_format : $this->_date_format;
328
    }
329
330
331
    /**
332
     * set the $_time_format property
333
     *
334
     * @access public
335
     *
336
     * @param string $format a new time format (corresponding to formats accepted by PHP date() function)
337
     * @param bool   $pretty Whether to set pretty format or not.
338
     *
339
     * @return void
340
     */
341
    public function set_time_format($format, $pretty = false)
342
    {
343
        if ($pretty) {
344
            $this->_pretty_time_format = $format;
345
        } else {
346
            $this->_time_format = $format;
347
        }
348
    }
349
350
351
    /**
352
     * return the $_time_format property value.
353
     *
354
     * @param bool $pretty Whether to get pretty format or not.
355
     *
356
     * @return string
357
     */
358
    public function get_time_format($pretty = false)
359
    {
360
        return $pretty ? $this->_pretty_time_format : $this->_time_format;
361
    }
362
363
364
    /**
365
     * set the $_pretty_date_format property
366
     *
367
     * @access public
368
     *
369
     * @param string $format a new pretty date format (corresponding to formats accepted by PHP date() function)
370
     *
371
     * @return void
372
     */
373
    public function set_pretty_date_format($format)
374
    {
375
        $this->_pretty_date_format = $format;
376
    }
377
378
379
    /**
380
     * set the $_pretty_time_format property
381
     *
382
     * @access public
383
     *
384
     * @param string $format a new pretty time format (corresponding to formats accepted by PHP date() function)
385
     *
386
     * @return void
387
     */
388
    public function set_pretty_time_format($format)
389
    {
390
        $this->_pretty_time_format = $format;
391
    }
392
393
394
    /**
395
     * Only sets the time portion of the datetime.
396
     *
397
     * @param string|DateTime $time_to_set_string like 8am OR a DateTime object.
398
     * @param DateTime        $current            current DateTime object for the datetime field
399
     *
400
     * @return DateTime
401
     */
402 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...
403
    {
404
        // if $time_to_set_string is datetime object, then let's use it to set the parse array.
405
	    // Otherwise parse the string.
406
        if ($time_to_set_string instanceof DateTime) {
407
            $parsed = array(
408
                'hour'   => $time_to_set_string->format('H'),
409
                'minute' => $time_to_set_string->format('i'),
410
                'second' => $time_to_set_string->format('s')
411
            );
412
        } else {
413
            //parse incoming string
414
            $parsed = date_parse_from_format($this->_time_format, $time_to_set_string);
415
        }
416
417
        //make sure $current is in the correct timezone.
418
        $current->setTimezone($this->_DateTimeZone);
419
420
        return $current->setTime($parsed['hour'], $parsed['minute'], $parsed['second']);
421
    }
422
423
424
    /**
425
     * Only sets the date portion of the datetime.
426
     *
427
     * @param string|DateTime $date_to_set_string like Friday, January 8th or a DateTime object.
428
     * @param DateTime        $current            current DateTime object for the datetime field
429
     *
430
     * @return DateTime
431
     */
432 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...
433
    {
434
        // if $time_to_set_string is datetime object, then let's use it to set the parse array.
435
	    // Otherwise parse the string.
436
        if ($date_to_set_string instanceof DateTime) {
437
            $parsed = array(
438
                'year'  => $date_to_set_string->format('Y'),
439
                'month' => $date_to_set_string->format('m'),
440
                'day'   => $date_to_set_string->format('d')
441
            );
442
        } else {
443
            //parse incoming string
444
            $parsed = date_parse_from_format($this->_date_format, $date_to_set_string);
445
        }
446
447
        //make sure $current is in the correct timezone
448
        $current->setTimezone($this->_DateTimeZone);
449
450
        return $current->setDate($parsed['year'], $parsed['month'], $parsed['day']);
451
    }
452
453
454
455
	/**
456
	 * This prepares the EE_DateTime value to be saved to the db as mysql timestamp (UTC +0 timezone).  When the
457
	 * datetime gets to this stage it should ALREADY be in UTC time
458
	 *
459
	 * @param  DateTime $DateTime
460
	 * @return string formatted date time for given timezone
461
	 * @throws \EE_Error
462
	 */
463
    public function prepare_for_get($DateTime)
464
    {
465
        return $this->_prepare_for_display($DateTime);
466
    }
467
468
469
470
	/**
471
	 * This differs from prepare_for_get in that it considers whether the internal $_timezone differs
472
	 * from the set wp timezone.  If so, then it returns the datetime string formatted via
473
	 * _pretty_date_format, and _pretty_time_format.  However, it also appends a timezone
474
	 * abbreviation to the date_string.
475
	 *
476
	 * @param mixed $DateTime
477
	 * @param null  $schema
478
	 * @return string
479
	 * @throws \EE_Error
480
	 */
481
    public function prepare_for_pretty_echoing($DateTime, $schema = null)
482
    {
483
        return $this->_prepare_for_display($DateTime, $schema ? $schema : true);
484
    }
485
486
487
    /**
488
     * This prepares the EE_DateTime value to be saved to the db as mysql timestamp (UTC +0
489
     * timezone).
490
     *
491
     * @param DateTime    $DateTime
492
     * @param bool|string $schema
493
     * @return string
494
     * @throws \EE_Error
495
     */
496
    protected function _prepare_for_display($DateTime, $schema = false)
497
    {
498
        if ( ! $DateTime instanceof DateTime) {
499
            if ($this->_nullable) {
500
                return '';
501
            } else {
502
                if (WP_DEBUG) {
503
	                throw new EE_Error(
504
		                sprintf(
505
			                __(
506
				                '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.',
507
				                'event_espresso'
508
			                ),
509
			                $this->_nicename
510
		                )
511
	                );
512
                } else {
513
                    $DateTime = new DbSafeDateTime(\EE_Datetime_Field::now);
514
	                EE_Error::add_error(
515
		                sprintf(
516
			                __(
517
				                '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.',
518
				                'event_espresso'
519
			                ),
520
			                $this->_nicename
521
		                )
522
	                );
523
                }
524
            }
525
        }
526
        $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 496 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...
527
        //make sure datetime_value is in the correct timezone (in case that's been updated).
528
        $DateTime->setTimezone($this->_DateTimeZone);
529
        if ($schema) {
530
            if ($this->_display_timezone()) {
531
                //must be explicit because schema could equal true.
532
                if ($schema === 'no_html') {
533
                    $timezone_string = ' (' . $DateTime->format('T') . ')';
534
                } else {
535
                    $timezone_string = ' <span class="ee_dtt_timezone_string">(' . $DateTime->format('T') . ')</span>';
536
                }
537
            } else {
538
                $timezone_string = '';
539
            }
540
541
            return $DateTime->format($format_string) . $timezone_string;
542
        } else {
543
            return $DateTime->format($format_string);
544
        }
545
    }
546
547
548
    /**
549
     * This prepares the EE_DateTime value to be saved to the db as mysql timestamp (UTC +0
550
     * timezone).
551
     *
552
     * @param  mixed $datetime_value u
553
     *
554
     * @return string mysql timestamp in UTC
555
     * @throws \EE_Error
556
     */
557
    public function prepare_for_use_in_db($datetime_value)
558
    {
559
        //we allow an empty value or DateTime object, but nothing else.
560
        if ( ! empty($datetime_value) && ! $datetime_value instanceof DateTime) {
561
            throw new EE_Error(
562
            	__(
563
            		'The incoming value being prepared for setting in the database must either be empty or a php DateTime object',
564
                    'event_espresso'
565
	            )
566
            );
567
        }
568
569
        if ($datetime_value instanceof DateTime) {
570
            if ( ! $datetime_value instanceof DbSafeDateTime) {
571
                $datetime_value = new DbSafeDateTime(
572
                    $datetime_value->format(EE_Datetime_Field::mysql_timestamp_format),
573
                    new \DateTimeZone($datetime_value->format('e'))
574
                );
575
            }
576
577
            return $datetime_value->setTimezone($this->get_UTC_DateTimeZone())->format(
578
            	EE_Datetime_Field::mysql_timestamp_format
579
            );
580
        }
581
582
        // if $datetime_value is empty, and ! $this->_nullable, use current_time() but set the GMT flag to true
583
        return ! $this->_nullable && empty($datetime_value) ? current_time('mysql', true) : null;
584
    }
585
586
587
588
	/**
589
	 * This prepares the datetime for internal usage as a PHP DateTime object OR null (if nullable is
590
	 * allowed)
591
	 *
592
	 * @param string $datetime_string mysql timestamp in UTC
593
	 * @return  mixed null | DateTime
594
	 * @throws \EE_Error
595
	 */
596
    public function prepare_for_set_from_db($datetime_string)
597
    {
598
        //if $datetime_value is empty, and ! $this->_nullable, just use time()
599
        if (empty($datetime_string) && $this->_nullable) {
600
            return null;
601
        }
602
        // datetime strings from the db should ALWAYS be in UTC+0, so use UTC_DateTimeZone when creating
603
        if (empty($datetime_string)) {
604
            $DateTime = new DbSafeDateTime(\EE_Datetime_Field::now, $this->get_UTC_DateTimeZone());
605
        } else {
606
            $DateTime = DateTime::createFromFormat(
607
                EE_Datetime_Field::mysql_timestamp_format,
608
                $datetime_string,
609
                $this->get_UTC_DateTimeZone()
610
            );
611
            if ($DateTime instanceof \DateTime) {
612
                $DateTime = new DbSafeDateTime(
613
                    $DateTime->format(\EE_Datetime_Field::mysql_timestamp_format),
614
                    $this->get_UTC_DateTimeZone()
615
                );
616
            }
617
        }
618
619
        if ( ! $DateTime instanceof DbSafeDateTime) {
620
            // if still no datetime object, then let's just use now
621
            $DateTime = new DbSafeDateTime(\EE_Datetime_Field::now, $this->get_UTC_DateTimeZone());
622
        }
623
        // THEN apply the field's set DateTimeZone
624
        $DateTime->setTimezone($this->_DateTimeZone);
625
626
        return $DateTime;
627
    }
628
629
630
631
	/**
632
	 * All this method does is determine if we're going to display the timezone string or not on any output.
633
	 * To determine this we check if the set timezone offset is different than the blog's set timezone offset.
634
	 * If so, then true.
635
	 *
636
	 * @return bool true for yes false for no
637
	 * @throws \EE_Error
638
	 */
639
    protected function _display_timezone()
640
    {
641
642
        // first let's do a comparison of timezone strings.
643
	    // If they match then we can get out without any further calculations
644
        $blog_string = get_option('timezone_string');
645
        if ($blog_string === $this->_timezone_string) {
646
            return false;
647
        }
648
        // now we need to calc the offset for the timezone string so we can compare with the blog offset.
649
        $this_offset = $this->get_timezone_offset($this->_DateTimeZone);
650
        $blog_offset = $this->get_timezone_offset($this->get_blog_DateTimeZone());
651
        // now compare
652
	    return $blog_offset !== $this_offset;
653
    }
654
655
656
    /**
657
     * This method returns a php DateTime object for setting on the EE_Base_Class model.
658
     * EE passes around DateTime objects because they are MUCH easier to manipulate and deal
659
     * with.
660
     *
661
     * @param int|string|DateTime $date_string            This should be the incoming date string.  It's assumed to be
662
     *                                                    in the format that is set on the date_field (or DateTime
663
     *                                                    object)!
664
     *
665
     * @return DateTime
666
     */
667
    protected function _get_date_object($date_string)
668
    {
669
        //first if this is an empty date_string and nullable is allowed, just return null.
670
        if ($this->_nullable && empty($date_string)) {
671
            return null;
672
        }
673
674
        // if incoming date
675
        if ($date_string instanceof DateTime) {
676
            $date_string->setTimezone($this->_DateTimeZone);
677
678
            return $date_string;
679
        }
680
        // if empty date_string and made it here.
681
        // Return a datetime object for now in the given timezone.
682
        if (empty($date_string)) {
683
            return new DbSafeDateTime(\EE_Datetime_Field::now, $this->_DateTimeZone);
684
        }
685
        // if $date_string is matches something that looks like a Unix timestamp let's just use it.
686
        if (preg_match(EE_Datetime_Field::unix_timestamp_regex, $date_string)) {
687
            try {
688
                // This is operating under the assumption that the incoming Unix timestamp
689
	            // is an ACTUAL Unix timestamp and not the calculated one output by current_time('timestamp');
690
                $DateTime = new DbSafeDateTime(\EE_Datetime_Field::now, $this->_DateTimeZone);
691
                $DateTime->setTimestamp($date_string);
692
693
                return $DateTime;
694
            } catch (Exception $e) {
695
                // should be rare, but if things got fooled then let's just continue
696
            }
697
        }
698
        //not a unix timestamp.  So we will use the set format on this object and set timezone to
699
        //create the DateTime object.
700
        $format = $this->_date_format . ' ' . $this->_time_format;
701
        try {
702
            $DateTime = DateTime::createFromFormat($format, $date_string, $this->_DateTimeZone);
703
            if ($DateTime instanceof DateTime) {
704
                $DateTime = new DbSafeDateTime(
705
                    $DateTime->format(\EE_Datetime_Field::mysql_timestamp_format),
706
                    $this->_DateTimeZone
707
                );
708
            }
709
            if ( ! $DateTime instanceof DbSafeDateTime) {
710
                throw new EE_Error(
711
                    sprintf(
712
                        __('"%1$s" does not represent a valid Date Time in the format "%2$s".', 'event_espresso'),
713
                        $date_string,
714
                        $format
715
                    )
716
                );
717
            }
718
        } catch (Exception $e) {
719
            // if we made it here then likely then something went really wrong.
720
	        // Instead of throwing an exception, let's just return a DateTime object for now, in the set timezone.
721
            $DateTime = new DbSafeDateTime(\EE_Datetime_Field::now, $this->_DateTimeZone);
722
        }
723
724
        return $DateTime;
725
    }
726
727
728
729
    /**
730
     * get_timezone_transitions
731
     *
732
     * @param \DateTimeZone $DateTimeZone
733
     * @param int           $time
734
     * @param bool          $first_only
735
     * @return mixed
736
     */
737
    public function get_timezone_transitions(DateTimeZone $DateTimeZone, $time = null, $first_only = true)
738
    {
739
        $time = is_int($time) || $time === null ? $time : strtotime($time);
740
        $time = preg_match(EE_Datetime_Field::unix_timestamp_regex, $time) ? $time : time();
741
        $transitions = $DateTimeZone->getTransitions($time);
742
        return $first_only && ! isset($transitions['ts']) ? reset($transitions) : $transitions;
743
    }
744
745
746
747
    /**
748
     * get_timezone_offset
749
     *
750
     * @param \DateTimeZone $DateTimeZone
751
     * @param int           $time
752
     * @return mixed
753
     * @throws \DomainException
754
     */
755
    public function get_timezone_offset(DateTimeZone $DateTimeZone, $time = null)
756
    {
757
        $transitions = $this->get_timezone_transitions($DateTimeZone, $time);
758
        if ( ! isset($transitions['offset'])) {
759
            throw new DomainException();
760
        }
761
        return $transitions['offset'];
762
    }
763
764
765
766
	/**
767
	 * This will take an incoming timezone string and return the abbreviation for that timezone
768
	 *
769
	 * @param  string $timezone_string
770
	 * @return string           abbreviation
771
	 * @throws \EE_Error
772
	 */
773
    public function get_timezone_abbrev($timezone_string)
774
    {
775
        $timezone_string = EEH_DTT_Helper::get_valid_timezone_string($timezone_string);
776
        $dateTime        = new DateTime(\EE_Datetime_Field::now, new DateTimeZone($timezone_string));
777
778
        return $dateTime->format('T');
779
    }
780
781
    /**
782
     * Overrides the parent to allow for having a dynamic "now" value
783
     *
784
     * @return mixed
785
     */
786
    public function get_default_value()
787
    {
788
        if ($this->_default_value === EE_Datetime_Field::now) {
789
            return time();
790
        } else {
791
            return parent::get_default_value();
792
        }
793
    }
794
795
796
}
797