Date.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. <?php
  2. namespace laytp\library;
  3. use DateTime;
  4. use DateTimeZone;
  5. /**
  6. * 日期时间处理类
  7. */
  8. class Date
  9. {
  10. const YEAR = 31536000;
  11. const MONTH = 2592000;
  12. const WEEK = 604800;
  13. const DAY = 86400;
  14. const HOUR = 3600;
  15. const MINUTE = 60;
  16. /**
  17. * 计算两个时区间相差的时长,单位为秒
  18. * $seconds = self::offset('America/Chicago', 'GMT');
  19. * [!!] A list of time zones that PHP supports can be found at
  20. * <http://php.net/timezones>.
  21. *
  22. * @param $remote
  23. * @param null $local
  24. * @param null $now
  25. * @return int
  26. * @throws \Exception
  27. */
  28. public static function offset($remote, $local = null, $now = null)
  29. {
  30. if ($local === null) {
  31. // Use the default timezone
  32. $local = date_default_timezone_get();
  33. }
  34. if (is_int($now)) {
  35. // Convert the timestamp into a string
  36. $now = date(DateTime::RFC2822, $now);
  37. }
  38. // Create timezone objects
  39. $zone_remote = new DateTimeZone($remote);
  40. $zone_local = new DateTimeZone($local);
  41. // Create date objects from timezones
  42. $time_remote = new DateTime($now, $zone_remote);
  43. $time_local = new DateTime($now, $zone_local);
  44. // Find the offset
  45. $offset = $zone_remote->getOffset($time_remote) - $zone_local->getOffset($time_local);
  46. return $offset;
  47. }
  48. /**
  49. * 计算两个时间戳之间相差的时间
  50. *
  51. * $span = self::span(60, 182, 'minutes,seconds'); // array('minutes' => 2, 'seconds' => 2)
  52. * $span = self::span(60, 182, 'minutes'); // 2
  53. *
  54. * @param int $remote timestamp to find the span of
  55. * @param int $local timestamp to use as the baseline
  56. * @param string $output formatting string
  57. * @return string when only a single output is requested
  58. * @return array associative list of all outputs requested
  59. * @from https://github.com/kohana/ohanzee-helpers/blob/master/src/Date.php
  60. */
  61. public static function span($remote, $local = null, $output = 'years,months,weeks,days,hours,minutes,seconds')
  62. {
  63. // Normalize output
  64. $output = trim(strtolower((string)$output));
  65. if (!$output) {
  66. // Invalid output
  67. return false;
  68. }
  69. // Array with the output formats
  70. $output = preg_split('/[^a-z]+/', $output);
  71. // Convert the list of outputs to an associative array
  72. $output = array_combine($output, array_fill(0, count($output), 0));
  73. // Make the output values into keys
  74. extract(array_flip($output), EXTR_SKIP);
  75. if ($local === null) {
  76. // Calculate the span from the current time
  77. $local = time();
  78. }
  79. // Calculate timespan (seconds)
  80. $timespan = abs($remote - $local);
  81. if (isset($output['years'])) {
  82. $timespan -= self::YEAR * ($output['years'] = (int)floor($timespan / self::YEAR));
  83. }
  84. if (isset($output['months'])) {
  85. $timespan -= self::MONTH * ($output['months'] = (int)floor($timespan / self::MONTH));
  86. }
  87. if (isset($output['weeks'])) {
  88. $timespan -= self::WEEK * ($output['weeks'] = (int)floor($timespan / self::WEEK));
  89. }
  90. if (isset($output['days'])) {
  91. $timespan -= self::DAY * ($output['days'] = (int)floor($timespan / self::DAY));
  92. }
  93. if (isset($output['hours'])) {
  94. $timespan -= self::HOUR * ($output['hours'] = (int)floor($timespan / self::HOUR));
  95. }
  96. if (isset($output['minutes'])) {
  97. $timespan -= self::MINUTE * ($output['minutes'] = (int)floor($timespan / self::MINUTE));
  98. }
  99. // Seconds ago, 1
  100. if (isset($output['seconds'])) {
  101. $output['seconds'] = $timespan;
  102. }
  103. if (count($output) === 1) {
  104. // Only a single output was requested, return it
  105. return array_pop($output);
  106. }
  107. // Return array
  108. return $output;
  109. }
  110. /**
  111. * 格式化 UNIX 时间戳为人易读的字符串
  112. *
  113. * @param int Unix 时间戳
  114. * @param mixed $local 本地时间
  115. *
  116. * @return string 格式化的日期字符串
  117. */
  118. public static function human($remote, $local = null)
  119. {
  120. $timediff = (is_null($local) || $local ? time() : $local) - $remote;
  121. $chunks = [
  122. [60 * 60 * 24 * 365, 'year'],
  123. [60 * 60 * 24 * 30, 'month'],
  124. [60 * 60 * 24 * 7, 'week'],
  125. [60 * 60 * 24, 'day'],
  126. [60 * 60, 'hour'],
  127. [60, 'minute'],
  128. [1, 'second'],
  129. ];
  130. for ($i = 0, $j = count($chunks); $i < $j; $i++) {
  131. $seconds = $chunks[$i][0];
  132. $name = $chunks[$i][1];
  133. if (($count = floor($timediff / $seconds)) != 0) {
  134. break;
  135. }
  136. }
  137. return __("%d {$name}%s ago", $count, ($count > 1 ? 's' : ''));
  138. }
  139. /**
  140. * 获取一个基于时间偏移的Unix时间戳
  141. *
  142. * @param string $type 时间类型,默认为day,可选minute,hour,day,week,month,quarter,year
  143. * @param int $offset 时间偏移量 默认为0,正数表示当前type之后,负数表示当前type之前
  144. * @param string $position 时间的开始或结束,默认为begin,可选前(begin,start,first,front),end
  145. * @param int $year 基准年,默认为null,即以当前年为基准
  146. * @param int $month 基准月,默认为null,即以当前月为基准
  147. * @param int $day 基准天,默认为null,即以当前天为基准
  148. * @param int $hour 基准小时,默认为null,即以当前年小时基准
  149. * @param int $minute 基准分钟,默认为null,即以当前分钟为基准
  150. * @return int 处理后的Unix时间戳
  151. */
  152. public static function unixtime($type = 'day', $offset = 0, $position = 'begin', $year = null, $month = null, $day = null, $hour = null, $minute = null)
  153. {
  154. $year = is_null($year) ? date('Y') : $year;
  155. $month = is_null($month) ? date('m') : $month;
  156. $day = is_null($day) ? date('d') : $day;
  157. $hour = is_null($hour) ? date('H') : $hour;
  158. $minute = is_null($minute) ? date('i') : $minute;
  159. $position = in_array($position, ['begin', 'start', 'first', 'front']);
  160. switch ($type) {
  161. case 'minute':
  162. $time = $position ? mktime($hour, $minute + $offset, 0, $month, $day, $year) : mktime($hour, $minute + $offset, 59, $month, $day, $year);
  163. break;
  164. case 'hour':
  165. $time = $position ? mktime($hour + $offset, 0, 0, $month, $day, $year) : mktime($hour + $offset, 59, 59, $month, $day, $year);
  166. break;
  167. case 'day':
  168. $time = $position ? mktime(0, 0, 0, $month, $day + $offset, $year) : mktime(23, 59, 59, $month, $day + $offset, $year);
  169. break;
  170. case 'week':
  171. $time = $position ?
  172. mktime(0, 0, 0, $month, $day - date("w", mktime(0, 0, 0, $month, $day, $year)) + 1 - 7 * (-$offset), $year) :
  173. mktime(23, 59, 59, $month, $day - date("w", mktime(0, 0, 0, $month, $day, $year)) + 7 - 7 * (-$offset), $year);
  174. break;
  175. case 'month':
  176. $time = $position ? mktime(0, 0, 0, $month + $offset, 1, $year) : mktime(23, 59, 59, $month + $offset, cal_days_in_month(CAL_GREGORIAN, $month + $offset, $year), $year);
  177. break;
  178. case 'quarter':
  179. $time = $position ?
  180. mktime(0, 0, 0, 1 + ((ceil(date('n', mktime(0, 0, 0, $month, $day, $year)) / 3) + $offset) - 1) * 3, 1, $year) :
  181. mktime(23, 59, 59, (ceil(date('n', mktime(0, 0, 0, $month, $day, $year)) / 3) + $offset) * 3, cal_days_in_month(CAL_GREGORIAN, (ceil(date('n', mktime(0, 0, 0, $month, $day, $year)) / 3) + $offset) * 3, $year), $year);
  182. break;
  183. case 'year':
  184. $time = $position ? mktime(0, 0, 0, 1, 1, $year + $offset) : mktime(23, 59, 59, 12, 31, $year + $offset);
  185. break;
  186. default:
  187. $time = mktime($hour, $minute, 0, $month, $day, $year);
  188. break;
  189. }
  190. return $time;
  191. }
  192. /**
  193. * 获取某个日期属于一年中的第几周
  194. * @param $date
  195. * @return false|int|string
  196. */
  197. public static function getWeekNum($date='')
  198. {
  199. $date = $date ? $date : date('Y-m-d');
  200. $year = date('Y', strtotime($date));
  201. $yearBegin = strtotime($year.'-1-1');
  202. $month = intval(date('m', strtotime($date)));
  203. if( date('W', $yearBegin) == 1 ){
  204. return date('W', strtotime($date));
  205. }else if($month == 1 && date('W', $yearBegin) > 50){
  206. return 1;
  207. }else{
  208. return date('W', strtotime($date)) + 1;
  209. }
  210. }
  211. /**
  212. * 根据日期,获取周信息
  213. * @param $now string 日期,举例: 2021-01-01
  214. * @return array
  215. */
  216. public static function getWeekInfo($now)
  217. {
  218. $str = [];
  219. //$first =1 表示每周星期一为开始日期 0表示每周日为开始日期
  220. $str['year'] = date('Y', strtotime($now));
  221. $first = 1;
  222. //当日在整年中的第几周
  223. $str['week'] = date('W', strtotime($now));
  224. //获取当前周的第几天 周日是 0 周一到周六是 1 - 6
  225. $w = date('w', strtotime($now));
  226. //获取本周开始日期,如果$w是0,则表示周日,减去 6 天
  227. $weekStart = date('Y-m-d', strtotime("$now -" . ($w ? $w - $first : 6) . ' days'));
  228. $str['week_start'] = $weekStart;
  229. //本周结束日期
  230. $weekEnd = date('Y-m-d', strtotime("$weekStart +6 days"));
  231. $str['week_end'] = $weekEnd;
  232. return $str;
  233. }
  234. /**
  235. * 某去某年第几周的周信息
  236. * @param $year
  237. * @param int $week
  238. * @return mixed
  239. */
  240. public static function weekDay($year, $week=1){
  241. $yearStart = mktime(0,0,0,1,1, $year);
  242. $yearEnd = mktime(0,0,0,12,31, $year);
  243. $start = $yearStart;//把第一天做为第一周的开始
  244. $end = strtotime('+1 sunday', $yearStart);//把第一个周日作为第一周的结束
  245. $lastStart = strtotime('-1 monday', $yearStart);//把最后一个周一作为最后一周的开始
  246. $lastEnd = $yearEnd;//把最后一天作为最后一周的结束
  247. $totalWeekNum = intval(date('W', $yearStart));
  248. if($week == 1){
  249. $weekday['begin'] = $start;//把第一天做为第一周的开始
  250. $weekday['begin_date'] = date('Y-m-d', $start);//把第一天做为第一周的开始
  251. $weekday['end'] = $end;//把第一个周日作为第一周的结束
  252. $weekday['end_date'] = date('Y-m-d', $end);//把第一个周日作为第一周的结束
  253. }else if($week == $totalWeekNum){
  254. $weekday['begin'] = $lastStart;//把最后一个周一作为最后一周的开始
  255. $weekday['begin_date'] = date('Y-m-d', $lastStart);//把第一天做为第一周的开始
  256. $weekday['end'] = $lastEnd;//把第一个周日作为第一周的结束
  257. $weekday['end_date'] = date('Y-m-d', $lastEnd);//把第一个周日作为第一周的结束
  258. }else if($week > 1 && $week < $totalWeekNum){
  259. $weekday['begin'] = strtotime('+' . ($week-1) . ' monday', $end);
  260. $weekday['begin_date'] = date('Y-m-d', $weekday['begin']);
  261. $weekday['end'] = strtotime('+' . ($week-1) . ' sunday', $end + 24 * 60 * 60);
  262. $weekday['end_date'] = date('Y-m-d', $weekday['end']);
  263. }else{
  264. return false;
  265. }
  266. $weekday['week'] = $week;
  267. $weekday['totalWeekNum'] = $totalWeekNum;
  268. return $weekday;
  269. }
  270. /**
  271. * 友好的时间显示
  272. *
  273. * @param int $sTime 待显示的时间
  274. * @param string $type 类型. normal | mohu | full | ymd | other
  275. * @param string $alt 已失效
  276. * @return string
  277. */
  278. public static function friendlyDate($sTime,$type = 'default',$alt = 'false') {
  279. //sTime=源时间,cTime=当前时间,dTime=时间差
  280. $cTime = time();
  281. $dTime = $cTime - $sTime;
  282. $dDay = intval(date("z",$cTime)) - intval(date("z",$sTime));
  283. //$dDay = intval($dTime/3600/24);
  284. $dYear = intval(date("Y",$cTime)) - intval(date("Y",$sTime));
  285. //normal:n秒前,n分钟前,n小时前,日期
  286. if($type=='normal'){
  287. if($dTime == 0){
  288. return '现在';
  289. }elseif( $dTime < 60 ){
  290. return $dTime."秒前";
  291. }elseif( $dTime < 3600 ){
  292. return intval($dTime/60)."分钟前";
  293. //今天的数据.年份相同.日期相同.
  294. }elseif( $dYear==0 && $dDay == 0 ){
  295. //return intval($dTime/3600)."小时前";
  296. return '今天'.date('H:i',$sTime);
  297. }elseif($dYear==0){
  298. return date("m月d日 H:i",$sTime);
  299. }else{
  300. return date("Y-m-d H:i",$sTime);
  301. }
  302. }elseif($type=='mohu'){
  303. if( $dTime < 60 ){
  304. return $dTime."秒前";
  305. }elseif( $dTime < 3600 ){
  306. return intval($dTime/60)."分钟前";
  307. }elseif( $dTime >= 3600 && $dDay == 0 ){
  308. return intval($dTime/3600)."小时前";
  309. }elseif( $dDay > 0 && $dDay<=7 ){
  310. return intval($dDay)."天前";
  311. }elseif( $dDay > 7 && $dDay <= 30 ){
  312. return intval($dDay/7) . '周前';
  313. }elseif( $dDay > 30 ){
  314. return intval($dDay/30) . '个月前';
  315. }
  316. //full: Y-m-d , H:i:s
  317. }elseif($type=='full'){
  318. return date("Y-m-d , H:i:s",$sTime);
  319. }elseif($type=='ymd'){
  320. return date("Y-m-d",$sTime);
  321. }else{
  322. if( $dTime < 60 ){
  323. return $dTime."秒前";
  324. }elseif( $dTime < 3600 ){
  325. return intval($dTime/60)."分钟前";
  326. }elseif( $dTime >= 3600 && $dDay == 0 ){
  327. return intval($dTime/3600)."小时前";
  328. }elseif($dYear==0){
  329. return date("Y-m-d H:i:s",$sTime);
  330. }else{
  331. return date("Y-m-d H:i:s",$sTime);
  332. }
  333. }
  334. }
  335. }