1<?php 2 3/** 4 * This file is part of the Carbon package. 5 * 6 * (c) Brian Nesbitt <brian@nesbot.com> 7 * 8 * For the full copyright and license information, please view the LICENSE 9 * file that was distributed with this source code. 10 */ 11 12namespace Carbon\Traits; 13 14/** 15 * Trait Timestamp. 16 */ 17trait Timestamp 18{ 19 /** 20 * Create a Carbon instance from a timestamp and set the timezone (use default one if not specified). 21 * 22 * Timestamp input can be given as int, float or a string containing one or more numbers. 23 * 24 * @param float|int|string $timestamp 25 * @param \DateTimeZone|string|null $tz 26 * 27 * @return static 28 */ 29 public static function createFromTimestamp($timestamp, $tz = null) 30 { 31 return static::createFromTimestampUTC($timestamp)->setTimezone($tz); 32 } 33 34 /** 35 * Create a Carbon instance from an timestamp keeping the timezone to UTC. 36 * 37 * Timestamp input can be given as int, float or a string containing one or more numbers. 38 * 39 * @param float|int|string $timestamp 40 * 41 * @return static 42 */ 43 public static function createFromTimestampUTC($timestamp) 44 { 45 [$integer, $decimal] = self::getIntegerAndDecimalParts($timestamp); 46 $delta = floor($decimal / static::MICROSECONDS_PER_SECOND); 47 $integer += $delta; 48 $decimal -= $delta * static::MICROSECONDS_PER_SECOND; 49 $decimal = str_pad((string) $decimal, 6, '0', STR_PAD_LEFT); 50 51 return static::rawCreateFromFormat('U u', "$integer $decimal"); 52 } 53 54 /** 55 * Create a Carbon instance from a timestamp in milliseconds. 56 * 57 * Timestamp input can be given as int, float or a string containing one or more numbers. 58 * 59 * @param float|int|string $timestamp 60 * 61 * @return static 62 */ 63 public static function createFromTimestampMsUTC($timestamp) 64 { 65 [$milliseconds, $microseconds] = self::getIntegerAndDecimalParts($timestamp, 3); 66 $sign = $milliseconds < 0 || $milliseconds === 0.0 && $microseconds < 0 ? -1 : 1; 67 $milliseconds = abs($milliseconds); 68 $microseconds = $sign * abs($microseconds) + static::MICROSECONDS_PER_MILLISECOND * ($milliseconds % static::MILLISECONDS_PER_SECOND); 69 $seconds = $sign * floor($milliseconds / static::MILLISECONDS_PER_SECOND); 70 $delta = floor($microseconds / static::MICROSECONDS_PER_SECOND); 71 $seconds += $delta; 72 $microseconds -= $delta * static::MICROSECONDS_PER_SECOND; 73 $microseconds = str_pad($microseconds, 6, '0', STR_PAD_LEFT); 74 75 return static::rawCreateFromFormat('U u', "$seconds $microseconds"); 76 } 77 78 /** 79 * Create a Carbon instance from a timestamp in milliseconds. 80 * 81 * Timestamp input can be given as int, float or a string containing one or more numbers. 82 * 83 * @param float|int|string $timestamp 84 * @param \DateTimeZone|string|null $tz 85 * 86 * @return static 87 */ 88 public static function createFromTimestampMs($timestamp, $tz = null) 89 { 90 return static::createFromTimestampMsUTC($timestamp) 91 ->setTimezone($tz); 92 } 93 94 /** 95 * Set the instance's timestamp. 96 * 97 * Timestamp input can be given as int, float or a string containing one or more numbers. 98 * 99 * @param float|int|string $unixTimestamp 100 * 101 * @return static 102 */ 103 public function timestamp($unixTimestamp) 104 { 105 return $this->setTimestamp($unixTimestamp); 106 } 107 108 /** 109 * Returns a timestamp rounded with the given precision (6 by default). 110 * 111 * @example getPreciseTimestamp() 1532087464437474 (microsecond maximum precision) 112 * @example getPreciseTimestamp(6) 1532087464437474 113 * @example getPreciseTimestamp(5) 153208746443747 (1/100000 second precision) 114 * @example getPreciseTimestamp(4) 15320874644375 (1/10000 second precision) 115 * @example getPreciseTimestamp(3) 1532087464437 (millisecond precision) 116 * @example getPreciseTimestamp(2) 153208746444 (1/100 second precision) 117 * @example getPreciseTimestamp(1) 15320874644 (1/10 second precision) 118 * @example getPreciseTimestamp(0) 1532087464 (second precision) 119 * @example getPreciseTimestamp(-1) 153208746 (10 second precision) 120 * @example getPreciseTimestamp(-2) 15320875 (100 second precision) 121 * 122 * @param int $precision 123 * 124 * @return float 125 */ 126 public function getPreciseTimestamp($precision = 6) 127 { 128 return round($this->rawFormat('Uu') / pow(10, 6 - $precision)); 129 } 130 131 /** 132 * Returns the milliseconds timestamps used amongst other by Date javascript objects. 133 * 134 * @return float 135 */ 136 public function valueOf() 137 { 138 return $this->getPreciseTimestamp(3); 139 } 140 141 /** 142 * Returns the timestamp with millisecond precision. 143 * 144 * @return int 145 */ 146 public function getTimestampMs() 147 { 148 return (int) $this->getPreciseTimestamp(3); 149 } 150 151 /** 152 * @alias getTimestamp 153 * 154 * Returns the UNIX timestamp for the current date. 155 * 156 * @return int 157 */ 158 public function unix() 159 { 160 return $this->getTimestamp(); 161 } 162 163 /** 164 * Return an array with integer part digits and decimals digits split from one or more positive numbers 165 * (such as timestamps) as string with the given number of decimals (6 by default). 166 * 167 * By splitting integer and decimal, this method obtain a better precision than 168 * number_format when the input is a string. 169 * 170 * @param float|int|string $numbers one or more numbers 171 * @param int $decimals number of decimals precision (6 by default) 172 * 173 * @return array 0-index is integer part, 1-index is decimal part digits 174 */ 175 private static function getIntegerAndDecimalParts($numbers, $decimals = 6) 176 { 177 if (\is_int($numbers) || \is_float($numbers)) { 178 $numbers = number_format($numbers, $decimals, '.', ''); 179 } 180 181 $sign = str_starts_with($numbers, '-') ? -1 : 1; 182 $integer = 0; 183 $decimal = 0; 184 185 foreach (preg_split('`[^0-9.]+`', $numbers) as $chunk) { 186 [$integerPart, $decimalPart] = explode('.', "$chunk."); 187 188 $integer += (int) $integerPart; 189 $decimal += (float) ("0.$decimalPart"); 190 } 191 192 $overflow = floor($decimal); 193 $integer += $overflow; 194 $decimal -= $overflow; 195 196 return [$sign * $integer, $decimal === 0.0 ? 0.0 : $sign * round($decimal * pow(10, $decimals))]; 197 } 198} 199