Issues (9)

src/ToolBag/Helper/TimeHelper.php (5 issues)

1
<?php
2
3
/**
4
 * @file TimeHelper.php
5
 * @brief This file contains the TimeHelper class.
6
 * @details
7
 * @author Filippo F. Fadda
8
 */
9
10
11
namespace ToolBag\Helper;
12
13
14
/**
15
 * @brief This class contains routines to handle time.
16
 * @nosubgrouping
17
 */
18
class TimeHelper {
19
20
  /** @name Time Periods */
21
  //!@{
22
  const TODAY = "today";
23
  const YESTERDAY = "yesterday";
24
  const THIS_WEEK = "this-week";
25
  const LAST_WEEK = "last-week";
26
  const THIS_MONTH = "this-month";
27
  const LAST_MONTH = "last-month";
28
  const THIS_YEAR = "this-year";
29
  const LAST_YEAR = "last-year";
30
  const ALL_TIME = "all-time";
31
  //!@}
32
33
34
  /** @name Time Periods Array */
35
  //!@{
36
  public static $periods = array( // Cannot use [] syntax otherwise Doxygen generates a warning.
37
    self::ALL_TIME => NULL,
38
    self::THIS_YEAR => NULL,
39
    self::LAST_YEAR => NULL,
40
    self::THIS_MONTH => NULL,
41
    self::LAST_MONTH => NULL,
42
    self::THIS_WEEK => NULL,
43
    self::LAST_WEEK => NULL,
44
    self::TODAY => NULL,
45
    self::YESTERDAY => NULL
46
  );
47
  //!@}
48
49
50
  /**
51
   * @brief Returns an associative array with the elapsed time, from the provided timestamp, in days, hours, minutes and
52
   * seconds.
53
   * @param string $timestamp A timestamp in seconds/microseconds.
54
   * @param string $micro When `true` the timestamp is expressed in microseconds otherwise in seconds.
55
   * @return array An associative array
56
   */
57
  public static function since($timestamp, $micro = FALSE) {
58
    $microsecondsInASecond = 1000000;
59
    $secondsInAMinute = 60;
60
    $secondsInAnHour = 60 * $secondsInAMinute;
61
    $secondsInADay = 24 * $secondsInAnHour;
62
63
    if ($micro) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $micro of type false|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
64
      // Gets the current timestamp in microseconds.
65
      $now = microtime(TRUE);
66
67
      // Subtracts from the current timestamp the last timestamp server was started.
68
      $microseconds = ($now * $microsecondsInASecond) - (float)$timestamp;
69
70
      // Converts microseconds in seconds.
71
      $seconds = floor($microseconds / $microsecondsInASecond);
72
    }
73
    else {
74
      // Calculates difference in seconds.
75
      $seconds = time() - $timestamp;
76
    }
77
78
    // Extracts days.
79
    $days = (int)floor($seconds / $secondsInADay);
80
81
    // Extracts hours.
82
    $hourSeconds = $seconds % $secondsInADay;
83
    $hours = (int)floor($hourSeconds / $secondsInAnHour);
84
85
    // Extracts minutes.
86
    $minuteSeconds = $hourSeconds % $secondsInAnHour;
87
    $minutes = (int)floor($minuteSeconds / $secondsInAMinute);
88
89
    // Extracts the remaining seconds.
90
    $remainingSeconds = $minuteSeconds % $secondsInAMinute;
91
    $seconds = (int)ceil($remainingSeconds);
92
93
    $time = [];
94
    $time['days'] = $days;
95
    $time['hours'] = $hours;
96
    $time['minutes'] = $minutes;
97
    $time['seconds'] = $seconds;
98
99
    return $time;
100
  }
101
102
103
  /**
104
   * @brief Checks if the provided string represents a period of time and returns it if exists otherwise returns `false`.
105
   * @param string $str A human readable period of time.
106
   * @return int|bool If the period of time exists returns it, else returns `false`. In case `$str` is `null`, returns
107
   * `all_time`.
108
   */
109
  public static function period($str) {
110
    return is_null($str) ? self::ALL_TIME : ArrayHelper::key($str, self::$periods);
0 ignored issues
show
Bug Best Practice introduced by
The expression return is_null($str) ? s...ey($str, self::periods) also could return the type string which is incompatible with the documented return type integer|boolean.
Loading history...
The condition is_null($str) can never be true.
Loading history...
111
  }
112
113
114
  /**
115
   * @brief Returns a measure of the time passed since the provided timestamp. In case is passed more than a day,
116
   * returns a human readable date.
117
   * @param int $timestamp A timestamp in seconds.
118
   * @param bool $showTime When `true` returns also the time passed in case of an event occurred in the past.
119
   * @return string
120
   */
121
  public static function when($timestamp, $showTime = TRUE) {
122
    $today = date('Ymd');
123
124
    // Today.
125
    if ($today == date('Ymd', $timestamp)) {
126
      $time = self::since($timestamp);
127
128
      if ($time['hours'] > 1)
129
        return sprintf('%d hours ago', $time['hours']);
130
      elseif ($time['hours'] == 1)
131
        return "one hour ago";
132
      elseif ($time['minutes'] > 1)
133
        return sprintf('%d minutes ago', $time['minutes']);
134
      elseif ($time['minutes'] == 1)
135
        return "one minute ago";
136
      elseif ($time['seconds'] > 1)
137
        return sprintf('%d seconds ago', $time['seconds']);
138
      else // $time['seconds'] == 1
139
        return "one second ago";
140
    }
141
    // Yesterday.
142
    elseif (strtotime('-1 day', $today) == date('Ymd', $timestamp))
0 ignored issues
show
$today of type string is incompatible with the type integer expected by parameter $now of strtotime(). ( Ignorable by Annotation )

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

142
    elseif (strtotime('-1 day', /** @scrutinizer ignore-type */ $today) == date('Ymd', $timestamp))
Loading history...
143
      return "yesterday";
144
    // In the past.
145
    else
146
      return $showTime ? date('d/m/Y H:i', $timestamp) : date('d/m/Y', $timestamp);
147
  }
148
149
150
  /**
151
   * @brief Given a constant representing a period, returns a formatted string.
152
   * @param int $periodInTime A period in time.
153
   * @param string $prefix A string prefix.
154
   * @param string $postfix A string postfix.
155
   * @return string
156
   */
157
  public static function aWhileBack($periodInTime, $prefix = "", $postfix = "") {
158
    $date = new \DateTime();
159
160
    switch ($periodInTime) {
161
      case self::TODAY:
162
        $format = $date->format("Ymd");
163
        break;
164
      case self::YESTERDAY:
165
        $date->modify('yesterday');
166
        $format = $date->format("Ymd");
167
        break;
168
      case self::THIS_WEEK:
169
        $format = $date->format("Y_W");
170
        break;
171
      case self::LAST_WEEK;
172
        $date->modify('last week');
173
        $format = $date->format("Y_W");
174
        break;
175
      case self::THIS_MONTH;
176
          $format = $date->format("Ym");
177
        break;
178
      case self::LAST_MONTH;
179
        $date->modify('last month');
180
        $format = $date->format("Ym");
181
        break;
182
      case self::THIS_YEAR;
183
        $format = $date->format("Y");
184
        break;
185
      case self::LAST_YEAR:
186
        $date->modify('last year');
187
        $format = $date->format("Y");
188
        break;
189
      default: // EVER
190
        $format = "";
191
    }
192
193
    return empty($format) ? $format : $prefix.$format.$postfix;
0 ignored issues
show
The condition empty($format) can never be false.
Loading history...
194
  }
195
196
197
  /**
198
   * @brief Given a constant representing a period, returns a range of timestamps (minimum and maximum) for that period.
199
   * @param int $periodInTime A period in time.
200
   * @param[out] \DateTime $minTimestamp The minimum date in the period.
201
   * @param[out] \DateTime $maxTimestamp The maximum date in the period.
202
   */
203
  public static function minMaxInPeriod($periodInTime, &$minTimestamp, &$maxTimestamp) {
204
    switch ($periodInTime) {
205
      case self::TODAY:
206
        $minTimestamp = strtotime('midnight');
207
        $maxTimestamp = time();
208
        break;
209
      case self::YESTERDAY:
210
        $minTimestamp = strtotime('yesterday');
211
        $maxTimestamp = strtotime('midnight') - 1;
212
        break;
213
      case self::THIS_WEEK:
214
        $minTimestamp = strtotime('last monday');
215
        $maxTimestamp = time();
216
        break;
217
      case self::LAST_WEEK;
218
        $minTimestamp = strtotime('Monday last week');
219
        $maxTimestamp = strtotime('Monday this week') - 1;
220
        break;
221
      case self::THIS_MONTH;
222
        $minTimestamp = strtotime('first day of this month midnight');
223
        $maxTimestamp = time();
224
        break;
225
      case self::LAST_MONTH;
226
        $minTimestamp = strtotime('first day of last month midnight');
227
        $maxTimestamp = strtotime('first day of this month midnight') - 1;
228
        break;
229
      case self::THIS_YEAR;
230
        $minTimestamp = strtotime('first day of January midnight');
231
        $maxTimestamp = time();
232
        break;
233
      case self::LAST_YEAR:
234
        $minTimestamp = strtotime('first day of January last year midnight');
235
        $maxTimestamp = strtotime('first day of January this year midnight') - 1;
236
        break;
237
      default: // EVER
238
        $minTimestamp = 0;
239
        $maxTimestamp = new \stdClass();
240
    }
241
  }
242
243
244
  /**
245
   * @brief Given a period of time (an year, a month or a day), calculates the date limits for that period.
246
   * @param[out] \DateTime $minDate The minimum date in the period.
247
   * @param[out] \DateTime $maxDate The maximum date in the period.
248
   * @param string $year An year.
249
   * @param string $month (optional) A month.
250
   * @param string $day (optional) A day.
251
   */
252
  public static function dateLimits(&$minDate, &$maxDate, $year, $month = NULL, $day = NULL) {
253
    $aDay = (is_null($day)) ? 1 : (int)$day;
254
    $aMonth = (is_null($month)) ? 1 : (int)$month;
255
    $aYear = (int)$year;
256
257
    $minDate = (new \DateTime())->setDate($aYear, $aMonth, $aDay)->modify('midnight');
258
    $maxDate = clone($minDate);
259
260
    if (isset($day))
261
      $maxDate->modify('tomorrow')->modify('last second');
262
    elseif (isset($month))
263
      $maxDate->modify('last day of this month')->modify('last second');
264
    else
265
      $maxDate->setDate($aYear, 12, 31)->modify('last second');
266
  }
267
268
}