]> git.mxchange.org Git - friendica.git/blob - src/Util/DateTimeFormat.php
Merge pull request #10967 from annando/api
[friendica.git] / src / Util / DateTimeFormat.php
1 <?php
2 /**
3  * @copyright Copyright (C) 2010-2021, the Friendica project
4  *
5  * @license GNU AGPL version 3 or any later version
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU Affero General Public License as
9  * published by the Free Software Foundation, either version 3 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Affero General Public License for more details.
16  *
17  * You should have received a copy of the GNU Affero General Public License
18  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19  *
20  */
21
22 namespace Friendica\Util;
23
24 use Friendica\Core\Logger;
25 use DateTime;
26 use DateTimeZone;
27 use Exception;
28
29 /**
30  * Temporal class
31  */
32 class DateTimeFormat
33 {
34         const ATOM  = 'Y-m-d\TH:i:s\Z';
35         const MYSQL = 'Y-m-d H:i:s';
36         const HTTP  = 'D, d M Y H:i:s \G\M\T';
37         const JSON  = 'Y-m-d\TH:i:s.v\Z';
38
39         static $localTimezone = 'UTC';
40
41         public static function setLocalTimeZone(string $timezone)
42         {
43                 self::$localTimezone = $timezone;
44         }
45
46         /**
47          * convert() shorthand for UTC.
48          *
49          * @param string $time   A date/time string
50          * @param string $format DateTime format string or Temporal constant
51          * @return string
52          * @throws Exception
53          */
54         public static function utc($time, $format = self::MYSQL)
55         {
56                 return self::convert($time, 'UTC', 'UTC', $format);
57         }
58
59         /**
60          * convert() shorthand for local.
61          *
62          * @param string $time   A date/time string
63          * @param string $format DateTime format string or Temporal constant
64          * @return string
65          * @throws Exception
66          */
67         public static function local($time, $format = self::MYSQL)
68         {
69                 return self::convert($time, self::$localTimezone, 'UTC', $format);
70         }
71
72         /**
73          * convert() shorthand for timezoned now.
74          *
75          * @param        $timezone
76          * @param string $format DateTime format string or Temporal constant
77          * @return string
78          * @throws Exception
79          */
80         public static function timezoneNow($timezone, $format = self::MYSQL)
81         {
82                 return self::convert('now', $timezone, 'UTC', $format);
83         }
84
85         /**
86          * convert() shorthand for local now.
87          *
88          * @param string $format DateTime format string or Temporal constant
89          * @return string
90          * @throws Exception
91          */
92         public static function localNow($format = self::MYSQL)
93         {
94                 return self::local('now', $format);
95         }
96
97         /**
98          * convert() shorthand for UTC now.
99          *
100          * @param string $format DateTime format string or Temporal constant
101          * @return string
102          * @throws Exception
103          */
104         public static function utcNow($format = self::MYSQL)
105         {
106                 return self::utc('now', $format);
107         }
108
109         /**
110          * General purpose date parse/convert/format function.
111          *
112          * @param string $s       Some parseable date/time string
113          * @param string $tz_to   Destination timezone
114          * @param string $tz_from Source timezone
115          * @param string $format  Output format recognised from php's DateTime class
116          *                        http://www.php.net/manual/en/datetime.format.php
117          *
118          * @return string Formatted date according to given format
119          * @throws Exception
120          */
121         public static function convert($s = 'now', $tz_to = 'UTC', $tz_from = 'UTC', $format = self::MYSQL)
122         {
123                 // Defaults to UTC if nothing is set, but throws an exception if set to empty string.
124                 // Provide some sane defaults regardless.
125                 if ($tz_from === '') {
126                         $tz_from = 'UTC';
127                 }
128
129                 if ($tz_to === '') {
130                         $tz_to = 'UTC';
131                 }
132
133                 if (($s === '') || (!is_string($s))) {
134                         $s = 'now';
135                 }
136
137                 /*
138                  * Slight hackish adjustment so that 'zero' datetime actually returns what is intended
139                  * otherwise we end up with -0001-11-30 ...
140                  * add 32 days so that we at least get year 00, and then hack around the fact that
141                  * months and days always start with 1.
142                  */
143                 if (substr($s, 0, 10) <= '0001-01-01') {
144                         if ($s < '0000-00-00') {
145                                 $s = '0000-00-00';
146                         }
147                         $d = new DateTime($s . ' + 32 days', new DateTimeZone('UTC'));
148                         return str_replace('1', '0', $d->format($format));
149                 }
150
151                 try {
152                         $from_obj = new DateTimeZone($tz_from);
153                 } catch (Exception $e) {
154                         $from_obj = new DateTimeZone('UTC');
155                 }
156
157                 try {
158                         $d = new DateTime($s, $from_obj);
159                 } catch (Exception $e) {
160                         Logger::notice('DateTimeFormat::convert: exception: ' . $e->getMessage());
161                         $d = new DateTime('now', $from_obj);
162                 }
163
164                 try {
165                         $to_obj = new DateTimeZone($tz_to);
166                 } catch (Exception $e) {
167                         $to_obj = new DateTimeZone('UTC');
168                 }
169
170                 $d->setTimezone($to_obj);
171
172                 return $d->format($format);
173         }
174
175         /**
176          * Checks, if the given string is a date with the pattern YYYY-MM
177          *
178          * @param string $dateString The given date
179          *
180          * @return boolean True, if the date is a valid pattern
181          */
182         public function isYearMonth(string $dateString)
183         {
184                 // Check format (2019-01, 2019-1, 2019-10)
185                 if (!preg_match('/^([12]\d{3}-(1[0-2]|0[1-9]|\d))$/', $dateString)) {
186                         return false;
187                 }
188
189                 $date = DateTime::createFromFormat('Y-m', $dateString);
190
191                 if (!$date) {
192                         return false;
193                 }
194
195                 try {
196                         $now = new DateTime();
197                 } catch (\Throwable $t) {
198                         return false;
199                 }
200
201                 if ($date > $now) {
202                         return false;
203                 }
204
205                 return true;
206         }
207
208         /**
209          * Checks, if the given string is a date with the pattern YYYY-MM-DD
210          *
211          * @param string $dateString The given date
212          *
213          * @return boolean True, if the date is a valid pattern
214          */
215         public function isYearMonthDay(string $dateString)
216         {
217                 $date = DateTime::createFromFormat('Y-m-d', $dateString);
218                 if (!$date) {
219                         return false;
220                 }
221
222                 if (DateTime::getLastErrors()['error_count'] || DateTime::getLastErrors()['warning_count']) {
223                         return false;
224                 }
225
226                 return true;
227         }
228 }