Updated Drupal to 8.6. This goes with the following updates because it's possible...
[yaffs-website] / vendor / lsolesen / pel / src / PelEntryTime.php
1 <?php
2
3 /**
4  * PEL: PHP Exif Library.
5  * A library with support for reading and
6  * writing all Exif headers in JPEG and TIFF images using PHP.
7  *
8  * Copyright (C) 2004, 2005, 2006, 2007 Martin Geisler.
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program in the file COPYING; if not, write to the
22  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
23  * Boston, MA 02110-1301 USA
24  */
25 namespace lsolesen\pel;
26
27 /**
28  * Classes used to hold ASCII strings.
29  *
30  * The classes defined here are to be used for Exif entries holding
31  * ASCII strings, such as {@link PelTag::MAKE}, {@link
32  * PelTag::SOFTWARE}, and {@link PelTag::DATE_TIME}. For
33  * entries holding normal textual ASCII strings the class {@link
34  * PelEntryAscii} should be used, but for entries holding
35  * timestamps the class {@link PelEntryTime} would be more
36  * convenient instead. Copyright information is handled by the {@link
37  * PelEntryCopyright} class.
38  *
39  * @author Martin Geisler <mgeisler@users.sourceforge.net>
40  * @license http://www.gnu.org/licenses/gpl.html GNU General Public
41  *          License (GPL)
42  * @package PEL
43  */
44
45 /**
46  * Class for holding a date and time.
47  *
48  * This class can hold a timestamp, and it will be used as
49  * in this example where the time is advanced by one week:
50  * <code>
51  * $entry = $ifd->getEntry(PelTag::DATE_TIME_ORIGINAL);
52  * $time = $entry->getValue();
53  * print('The image was taken on the ' . date('jS', $time));
54  * $entry->setValue($time + 7 * 24 * 3600);
55  * </code>
56  *
57  * The example used a standard UNIX timestamp, which is the default
58  * for this class.
59  *
60  * But the Exif format defines dates outside the range of a UNIX
61  * timestamp (about 1970 to 2038) and so you can also get access to
62  * the timestamp in two other formats: a simple string or a Julian Day
63  * Count. Please see the Calendar extension in the PHP Manual for more
64  * information about the Julian Day Count.
65  *
66  * @author Martin Geisler <mgeisler@users.sourceforge.net>
67  * @package PEL
68  */
69 class PelEntryTime extends PelEntryAscii
70 {
71
72     /**
73      * Constant denoting a UNIX timestamp.
74      */
75     const UNIX_TIMESTAMP = 1;
76
77     /**
78      * Constant denoting a Exif string.
79      */
80     const EXIF_STRING = 2;
81
82     /**
83      * Constant denoting a Julian Day Count.
84      */
85     const JULIAN_DAY_COUNT = 3;
86
87     /**
88      * The Julian Day Count of the timestamp held by this entry.
89      *
90      * This is an integer counting the number of whole days since
91      * January 1st, 4713 B.C. The fractional part of the timestamp held
92      * by this entry is stored in {@link $seconds}.
93      *
94      * @var int
95      */
96     private $day_count;
97
98     /**
99      * The number of seconds into the day of the timestamp held by this
100      * entry.
101      *
102      * The number of whole days is stored in {@link $day_count} and the
103      * number of seconds left-over is stored here.
104      *
105      * @var int
106      */
107     private $seconds;
108
109     /**
110      * Make a new entry for holding a timestamp.
111      *
112      * @param integer $tag
113      *            the Exif tag which this entry represents. There are
114      *            only three standard tags which hold timestamp, so this should be
115      *            one of the constants {@link PelTag::DATE_TIME}, {@link
116      *            PelTag::DATE_TIME_ORIGINAL}, or {@link
117      *            PelTag::DATE_TIME_DIGITIZED}.
118      *
119      * @param integer $timestamp
120      *            the timestamp held by this entry in the correct form
121      *            as indicated by the third argument. For {@link UNIX_TIMESTAMP}
122      *            this is an integer counting the number of seconds since January
123      *            1st 1970, for {@link EXIF_STRING} this is a string of the form
124      *            'YYYY:MM:DD hh:mm:ss', and for {@link JULIAN_DAY_COUNT} this is a
125      *            floating point number where the integer part denotes the day
126      *            count and the fractional part denotes the time of day (0.25 means
127      *            6:00, 0.75 means 18:00).
128      *
129      * @param integer $type
130      *            the type of the timestamp. This must be one of
131      *            {@link UNIX_TIMESTAMP}, {@link EXIF_STRING}, or
132      *            {@link JULIAN_DAY_COUNT}.
133      */
134     public function __construct($tag, $timestamp, $type = self::UNIX_TIMESTAMP)
135     {
136         parent::__construct($tag);
137         $this->setValue($timestamp, $type);
138     }
139
140     /**
141      * Return the timestamp of the entry.
142      *
143      * The timestamp held by this entry is returned in one of three
144      * formats: as a standard UNIX timestamp (default), as a fractional
145      * Julian Day Count, or as a string.
146      *
147      * @param integer $type
148      *            the type of the timestamp. This must be one of
149      *            {@link UNIX_TIMESTAMP}, {@link EXIF_STRING}, or
150      *            {@link JULIAN_DAY_COUNT}.
151      *
152      * @return integer the timestamp held by this entry in the correct form
153      *         as indicated by the type argument. For {@link UNIX_TIMESTAMP}
154      *         this is an integer counting the number of seconds since January
155      *         1st 1970, for {@link EXIF_STRING} this is a string of the form
156      *         'YYYY:MM:DD hh:mm:ss', and for {@link JULIAN_DAY_COUNT} this is a
157      *         floating point number where the integer part denotes the day
158      *         count and the fractional part denotes the time of day (0.25 means
159      *         6:00, 0.75 means 18:00).
160      */
161     public function getValue($type = self::UNIX_TIMESTAMP)
162     {
163         switch ($type) {
164             case self::UNIX_TIMESTAMP:
165                 $seconds = $this->convertJdToUnix($this->day_count);
166                 if ($seconds === false) {
167                     /*
168                      * We get false if the Julian Day Count is outside the range
169                      * of a UNIX timestamp.
170                      */
171                     return false;
172                 } else {
173                     return $seconds + $this->seconds;
174                 }
175                 break;
176             case self::EXIF_STRING:
177                 list ($year, $month, $day) = $this->convertJdToGregorian($this->day_count);
178                 $hours = (int) ($this->seconds / 3600);
179                 $minutes = (int) ($this->seconds % 3600 / 60);
180                 $seconds = $this->seconds % 60;
181                 return sprintf('%04d:%02d:%02d %02d:%02d:%02d', $year, $month, $day, $hours, $minutes, $seconds);
182             case self::JULIAN_DAY_COUNT:
183                 return $this->day_count + $this->seconds / 86400;
184             default:
185                 throw new PelInvalidArgumentException(
186                     'Expected UNIX_TIMESTAMP (%d), ' . 'EXIF_STRING (%d), or ' . 'JULIAN_DAY_COUNT (%d) for $type, ' .
187                          'got %d.',
188                         self::UNIX_TIMESTAMP,
189                         self::EXIF_STRING,
190                         self::JULIAN_DAY_COUNT,
191                         $type);
192         }
193     }
194
195     /**
196      * Update the timestamp held by this entry.
197      *
198      * @param integer $timestamp
199      *            the timestamp held by this entry in the correct form
200      *            as indicated by the third argument. For {@link UNIX_TIMESTAMP}
201      *            this is an integer counting the number of seconds since January
202      *            1st 1970, for {@link EXIF_STRING} this is a string of the form
203      *            'YYYY:MM:DD hh:mm:ss', and for {@link JULIAN_DAY_COUNT} this is a
204      *            floating point number where the integer part denotes the day
205      *            count and the fractional part denotes the time of day (0.25 means
206      *            6:00, 0.75 means 18:00).
207      *
208      * @param integer $type
209      *            the type of the timestamp. This must be one of
210      *            {@link UNIX_TIMESTAMP}, {@link EXIF_STRING}, or
211      *            {@link JULIAN_DAY_COUNT}.
212      */
213     public function setValue($timestamp, $type = self::UNIX_TIMESTAMP)
214     {
215         switch ($type) {
216             case self::UNIX_TIMESTAMP:
217                 $this->day_count = $this->convertUnixToJd($timestamp);
218                 $this->seconds = $timestamp % 86400;
219                 break;
220
221             case self::EXIF_STRING:
222                 /* Clean the timestamp: some timestamps are broken other
223                  * separators than ':' and ' '. */
224                 $d = preg_split('/[^0-9]+/', $timestamp);
225                 for ($i = 0; $i < 6; $i ++) {
226                     if (empty($d[$i])) {
227                         $d[$i] = 0;
228                     }
229                 }
230                 $this->day_count = $this->convertGregorianToJd($d[0], $d[1], $d[2]);
231                 $this->seconds = $d[3] * 3600 + $d[4] * 60 + $d[5];
232                 break;
233
234             case self::JULIAN_DAY_COUNT:
235                 $this->day_count = (int) floor($timestamp);
236                 $this->seconds = (int) (86400 * ($timestamp - floor($timestamp)));
237                 break;
238
239             default:
240                 throw new PelInvalidArgumentException(
241                     'Expected UNIX_TIMESTAMP (%d), ' . 'EXIF_STRING (%d), or ' . 'JULIAN_DAY_COUNT (%d) for $type, ' .
242                          'got %d.',
243                         self::UNIX_TIMESTAMP,
244                         self::EXIF_STRING,
245                         self::JULIAN_DAY_COUNT,
246                         $type);
247         }
248
249         /*
250          * Now finally update the string which will be used when this is
251          * turned into bytes.
252          */
253         parent::setValue($this->getValue(self::EXIF_STRING));
254     }
255
256     // The following four functions are used for converting back and
257     // forth between the date formats. They are used in preference to
258     // the ones from the PHP calendar extension to avoid having to
259     // fiddle with timezones and to avoid depending on the extension.
260     //
261     // See http://www.hermetic.ch/cal_stud/jdn.htm#comp for a reference.
262
263     /**
264      * Converts a date in year/month/day format to a Julian Day count.
265      *
266      * @param integer $year
267      *            the year.
268      * @param integer $month
269      *            the month, 1 to 12.
270      * @param integer $day
271      *            the day in the month.
272      * @return integer the Julian Day count.
273      */
274     public function convertGregorianToJd($year, $month, $day)
275     {
276         // Special case mapping 0/0/0 -> 0
277         if ($year == 0 || $month == 0 || $day == 0) {
278             return 0;
279         }
280
281         $m1412 = ($month <= 2) ? - 1 : 0;
282         return floor((1461 * ($year + 4800 + $m1412)) / 4) + floor((367 * ($month - 2 - 12 * $m1412)) / 12) -
283              floor((3 * floor(($year + 4900 + $m1412) / 100)) / 4) + $day - 32075;
284     }
285
286     /**
287      * Converts a Julian Day count to a year/month/day triple.
288      *
289      * @param
290      *            int the Julian Day count.
291      * @return array an array with three entries: year, month, day.
292      */
293     public function convertJdToGregorian($jd)
294     {
295         // Special case mapping 0 -> 0/0/0
296         if ($jd == 0) {
297             return array(
298                 0,
299                 0,
300                 0
301             );
302         }
303
304         $l = $jd + 68569;
305         $n = floor((4 * $l) / 146097);
306         $l = $l - floor((146097 * $n + 3) / 4);
307         $i = floor((4000 * ($l + 1)) / 1461001);
308         $l = $l - floor((1461 * $i) / 4) + 31;
309         $j = floor((80 * $l) / 2447);
310         $d = $l - floor((2447 * $j) / 80);
311         $l = floor($j / 11);
312         $m = $j + 2 - (12 * $l);
313         $y = 100 * ($n - 49) + $i + $l;
314         return array(
315             $y,
316             $m,
317             $d
318         );
319     }
320
321     /**
322      * Converts a UNIX timestamp to a Julian Day count.
323      *
324      * @param integer $timestamp
325      *            the timestamp.
326      * @return integer the Julian Day count.
327      */
328     public function convertUnixToJd($timestamp)
329     {
330         return (int) (floor($timestamp / 86400) + 2440588);
331     }
332
333     /**
334      * Converts a Julian Day count to a UNIX timestamp.
335      *
336      * @param integer $jd
337      *            the Julian Day count.
338      *
339      * @return mixed $timestamp the integer timestamp or false if the
340      *         day count cannot be represented as a UNIX timestamp.
341      */
342     public function convertJdToUnix($jd)
343     {
344         if ($jd > 0) {
345             $timestamp = ($jd - 2440588) * 86400;
346             if ($timestamp >= 0) {
347                 return $timestamp;
348             }
349         }
350         return false;
351     }
352 }