Issues (441)

common/components/Time.php (4 issues)

1
<?php
2
namespace common\components;
3
4
use yii;
5
use \DateTime;
6
use \DateTimeZone;
7
8
class Time extends \yii\base\BaseObject implements \common\interfaces\TimeInterface {
9
10
  public const EARLIEST_DATE = '2014-01-01';
11
12
  public $timezone;
13
14
  public function __construct(String $timezone, $config = []) {
15
    $this->timezone = $timezone;
16
    parent::__construct($config);
17
  }
18
19
  /*
20
   * Returns a \DateTime object of the current time in $this->timezone
21
   *
22
   * @return \DateTime the current time in $this->timezone
23
   */
24
  public function now() {
25
    return new DateTime("now", new DateTimeZone($this->timezone));
26
  }
27
28
  /*
29
   * Parses the supplied string into a `\DateTime` object of the
30
   * given `$format`. It assumes the supplied string is in the
31
   * timezone specified in $this->timezone.
32
   *
33
   * @param string $time the questionable time to parse
34
   * @param bool | \DateTime $default the value to return if $time is not a parseable date
35
   * @param string $format the format `$time` is expected to be in
36
   * @return \DateTime the parsed time or the default value
37
   */
38
  public function parse($time, $default = false, string $format = 'Y-m-d') {
39
    if(is_string($time)) {
0 ignored issues
show
The condition is_string($time) is always true.
Loading history...
40
      $dt = DateTime::createFromFormat($format, $time, new DateTimeZone($this->timezone));
41
      if($dt) {
0 ignored issues
show
$dt is of type DateTime, thus it always evaluated to true.
Loading history...
42
        // for some reason, using createFromFromat adds in the time. The regular DateTime constructor _does not_ do this. We manually zero out the time here to make the DateTime objects match.
43
        $dt->setTime(0, 0, 0);
44
        $formatted = $dt->format($format);
45
        if($formatted === $time && $this->inBounds($dt)) {
46
          return $dt;
47
        }
48
      }
49
    }
50
    return $default;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $default also could return the type boolean which is incompatible with the documented return type DateTime.
Loading history...
51
  }
52
53
  /*
54
   * Checks if the given `\DateTime` is within "acceptable" date bounds.
55
   * It does no good to have the date be far in the past or in the future.
56
   *
57
   * @param \DateTime $dt
58
   * @return boolean
59
   */
60
  public function inBounds(DateTime $dt) {
61
    $first = strtotime((new DateTime(self::EARLIEST_DATE))->format('Y-m-d'));
62
    $test  = strtotime($dt->format('Y-m-d'));
63
    $now   = strtotime($this->getLocalDate());
64
65
    if($first <= $test && $test <= $now) {
66
      return true;
67
    } else {
68
      return false;
69
    }
70
  }
71
72
  public function convertLocalToUTC($local, $inc_time = true) {
73
    $fmt = $inc_time ? "Y-m-d H:i:s" : "Y-m-d";
74
75
    $timestamp = new DateTime($local, new DateTimeZone($this->timezone));
76
    $timestamp->setTimeZone(new DateTimeZone("UTC"));
77
    return $timestamp->format($fmt);
78
  }
79
80
  public function convertUTCToLocal($utc, $iso = true) {
81
    $fmt = $iso ? Datetime::ATOM : "Y-m-d H:i:s";
82
83
    $timestamp = new DateTime($utc, new DateTimeZone("UTC"));
84
    $timestamp->setTimeZone(new DateTimeZone($this->timezone));
85
    return $timestamp->format($fmt);
86
  }
87
88
  public function getLocalTime($timezone = null) {
89
    if($timezone === null)
90
      $timezone = $this->timezone;
91
92
    $timestamp = new DateTime("now", new DateTimeZone($timezone));
93
    return $timestamp->format("Y-m-d H:i:s");
94
  }
95
96
  public function getLocalDate($timezone = null) {
97
    if($timezone === null)
98
      $timezone = $this->timezone;
99
100
    return (new DateTime("now", new DateTimeZone($timezone)))
101
      ->format("Y-m-d");
102
  }
103
104
  public function alterLocalDate($date, $modifier) {
105
    return (new DateTime("$date $modifier", new DateTimeZone($this->timezone)))
106
      ->format("Y-m-d");
107
  }
108
109
  public function getUTCBookends($local) {
110
    $local = trim($local);
111
    if(strpos($local, " ")) {
112
      return false;
113
    }
114
115
    $start = $local . " 00:00:00";
116
    $end   = $local . "23:59:59";
117
118
    $front = self::convertLocalToUTC($start);
0 ignored issues
show
Bug Best Practice introduced by
The method common\components\Time::convertLocalToUTC() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

118
    /** @scrutinizer ignore-call */ 
119
    $front = self::convertLocalToUTC($start);
Loading history...
119
    $back  = self::convertLocalToUTC($end);
120
121
    return [$front, $back];
122
  }
123
124
  /*
125
   * Verifies that what it is given is a parseable date string
126
   * If it is not a parseable string, it defaults to the current
127
   * date.
128
   * 
129
   * @param $date a date string or null
130
   * @return string a date string
131
   */
132
  public function validate($date = null) {
133
    if(is_null($date)) {
134
      return $this->getLocalDate();
135
    } else if($dt = $this->parse($date)) {
136
      return $dt->format('Y-m-d');
137
    } else {
138
      return $this->getLocalDate();
139
    }
140
  }
141
142
  /*
143
   * Returns a \DatePeriod iterable containing a DateTime for each day of the
144
   * last $period days. The \DatePeriod is in the $this->timezone timezone. The
145
   * current day (end of the period) is included in the \returned \DatePeriod.
146
   *
147
   * @param $period int
148
   * @return \DatePeriod of length $period, from $period days ago to today
149
   */
150
  public function getDateTimesInPeriod(int $period = 30) {
151
    $start = new DateTime("now", new DateTimeZone($this->timezone));
152
    $end   = new DateTime("now", new DateTimeZone($this->timezone));
153
    $oneday = new \DateInterval('P1D');
154
    $end->add($oneday);      // add a day, so the end date gets included in the intervals
155
 
156
    $start->add(new \DateInterval('PT2M'))  // add two minutes, in case they just did a check-in
157
          ->sub(new \DateInterval("P${period}D")); // subtract `$period` number of days
158
    $end->add(new \DateInterval('PT2M'));   // add two minutes, in case they just did a check-in
159
160
    $periods = new \DatePeriod($start, $oneday, $end, \DatePeriod::EXCLUDE_START_DATE);
161
    $local_tz = new \DateTimeZone($this->timezone);
162
    foreach($periods as $period) {
163
      $period->setTimezone($local_tz);
164
    }
165
    return $periods;
166
  }
167
}
168