DateTimeConverter   A
last analyzed

Complexity

Total Complexity 6

Size/Duplication

Total Lines 70
Duplicated Lines 0 %

Test Coverage

Coverage 88%

Importance

Changes 0
Metric Value
eloc 27
dl 0
loc 70
ccs 22
cts 25
cp 0.88
rs 10
c 0
b 0
f 0
wmc 6

2 Methods

Rating   Name   Duplication   Size   Complexity  
A msDosToUnix() 0 15 3
A unixToMsDos() 0 21 3
1
<?php
2
3
namespace PhpZip\Util;
4
5
/**
6
 * Convert unix timestamp values to DOS date/time values and vice versa.
7
 *
8
 * The DOS date/time format is a bitmask:
9
 *
10
 * 24                16                 8                 0
11
 * +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
12
 * |Y|Y|Y|Y|Y|Y|Y|M| |M|M|M|D|D|D|D|D| |h|h|h|h|h|m|m|m| |m|m|m|s|s|s|s|s|
13
 * +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
14
 * \___________/\________/\_________/ \________/\____________/\_________/
15
 * year        month       day      hour       minute        second
16
 *
17
 * The year is stored as an offset from 1980.
18
 * Seconds are stored in two-second increments.
19
 * (So if the "second" value is 15, it actually represents 30 seconds.)
20
 *
21
 * @see https://docs.microsoft.com/ru-ru/windows/win32/api/winbase/nf-winbase-filetimetodosdatetime?redirectedfrom=MSDN
22
 *
23
 * @author Ne-Lexa [email protected]
24
 * @license MIT
25
 *
26
 * @internal
27
 */
28
class DateTimeConverter
29
{
30
    /**
31
     * Smallest supported DOS date/time value in a ZIP file,
32
     * which is January 1st, 1980 AD 00:00:00 local time.
33
     */
34
    const MIN_DOS_TIME = 0x210000; // (1 << 21) | (1 << 16)
35
36
    /**
37
     * Largest supported DOS date/time value in a ZIP file,
38
     * which is December 31st, 2107 AD 23:59:58 local time.
39
     */
40
    const MAX_DOS_TIME = 0xff9fbf7d; // ((2107 - 1980) << 25) | (12 << 21) | (31 << 16) | (23 << 11) | (59 << 5) | (58 >> 1);
41
42
    /**
43
     * Convert a 32 bit integer DOS date/time value to a UNIX timestamp value.
44
     *
45
     * @param int $dosTime Dos date/time
46
     *
47
     * @return int Unix timestamp
48
     */
49 14
    public static function msDosToUnix($dosTime)
50
    {
51 14
        if ($dosTime <= self::MIN_DOS_TIME) {
52
            $dosTime = 0;
53 14
        } elseif ($dosTime > self::MAX_DOS_TIME) {
54
            $dosTime = self::MAX_DOS_TIME;
55
        }
56
//        date_default_timezone_set('UTC');
57 14
        return mktime(
58 14
            (($dosTime >> 11) & 0x1f),         // hours
59 14
            (($dosTime >> 5) & 0x3f),          // minutes
60 14
            (($dosTime << 1) & 0x3e),          // seconds
61 14
            (($dosTime >> 21) & 0x0f),         // month
62 14
            (($dosTime >> 16) & 0x1f),         // day
63 14
            ((($dosTime >> 25) & 0x7f) + 1980) // year
64
        );
65
    }
66
67
    /**
68
     * Converts a UNIX timestamp value to a DOS date/time value.
69
     *
70
     * @param int $unixTimestamp the number of seconds since midnight, January 1st,
71
     *                           1970 AD UTC
72
     *
73
     * @return int a DOS date/time value reflecting the local time zone and
74
     *             rounded down to even seconds
75
     *             and is in between DateTimeConverter::MIN_DOS_TIME and DateTimeConverter::MAX_DOS_TIME
76
     */
77 164
    public static function unixToMsDos($unixTimestamp)
78
    {
79 164
        if ($unixTimestamp < 0) {
80
            throw new \InvalidArgumentException('Negative unix timestamp: ' . $unixTimestamp);
81
        }
82
83 164
        $date = getdate($unixTimestamp);
84
        $dosTime = (
85 164
            (($date['year'] - 1980) << 25) |
86 164
            ($date['mon'] << 21) |
87 164
            ($date['mday'] << 16) |
88 164
            ($date['hours'] << 11) |
89 164
            ($date['minutes'] << 5) |
90 164
            ($date['seconds'] >> 1)
91
        );
92
93 164
        if ($dosTime <= self::MIN_DOS_TIME) {
94 1
            $dosTime = 0;
95
        }
96
97 164
        return $dosTime;
98
    }
99
}
100