. * * @param $remote * @param null $local * @param null $now * @return int * @throws \Exception */ public static function offset($remote, $local = null, $now = null) { if ($local === null) { // Use the default timezone $local = date_default_timezone_get(); } if (is_int($now)) { // Convert the timestamp into a string $now = date(DateTime::RFC2822, $now); } // Create timezone objects $zone_remote = new DateTimeZone($remote); $zone_local = new DateTimeZone($local); // Create date objects from timezones $time_remote = new DateTime($now, $zone_remote); $time_local = new DateTime($now, $zone_local); // Find the offset $offset = $zone_remote->getOffset($time_remote) - $zone_local->getOffset($time_local); return $offset; } /** * 计算两个时间戳之间相差的时间 * * $span = self::span(60, 182, 'minutes,seconds'); // array('minutes' => 2, 'seconds' => 2) * $span = self::span(60, 182, 'minutes'); // 2 * * @param int $remote timestamp to find the span of * @param int $local timestamp to use as the baseline * @param string $output formatting string * @return string when only a single output is requested * @return array associative list of all outputs requested * @from https://github.com/kohana/ohanzee-helpers/blob/master/src/Date.php */ public static function span($remote, $local = null, $output = 'years,months,weeks,days,hours,minutes,seconds') { // Normalize output $output = trim(strtolower((string)$output)); if (!$output) { // Invalid output return false; } // Array with the output formats $output = preg_split('/[^a-z]+/', $output); // Convert the list of outputs to an associative array $output = array_combine($output, array_fill(0, count($output), 0)); // Make the output values into keys extract(array_flip($output), EXTR_SKIP); if ($local === null) { // Calculate the span from the current time $local = time(); } // Calculate timespan (seconds) $timespan = abs($remote - $local); if (isset($output['years'])) { $timespan -= self::YEAR * ($output['years'] = (int)floor($timespan / self::YEAR)); } if (isset($output['months'])) { $timespan -= self::MONTH * ($output['months'] = (int)floor($timespan / self::MONTH)); } if (isset($output['weeks'])) { $timespan -= self::WEEK * ($output['weeks'] = (int)floor($timespan / self::WEEK)); } if (isset($output['days'])) { $timespan -= self::DAY * ($output['days'] = (int)floor($timespan / self::DAY)); } if (isset($output['hours'])) { $timespan -= self::HOUR * ($output['hours'] = (int)floor($timespan / self::HOUR)); } if (isset($output['minutes'])) { $timespan -= self::MINUTE * ($output['minutes'] = (int)floor($timespan / self::MINUTE)); } // Seconds ago, 1 if (isset($output['seconds'])) { $output['seconds'] = $timespan; } if (count($output) === 1) { // Only a single output was requested, return it return array_pop($output); } // Return array return $output; } /** * 格式化 UNIX 时间戳为人易读的字符串 * * @param int Unix 时间戳 * @param mixed $local 本地时间 * * @return string 格式化的日期字符串 */ public static function human($remote, $local = null) { $timediff = (is_null($local) || $local ? time() : $local) - $remote; $chunks = [ [60 * 60 * 24 * 365, 'year'], [60 * 60 * 24 * 30, 'month'], [60 * 60 * 24 * 7, 'week'], [60 * 60 * 24, 'day'], [60 * 60, 'hour'], [60, 'minute'], [1, 'second'], ]; for ($i = 0, $j = count($chunks); $i < $j; $i++) { $seconds = $chunks[$i][0]; $name = $chunks[$i][1]; if (($count = floor($timediff / $seconds)) != 0) { break; } } return __("%d {$name}%s ago", $count, ($count > 1 ? 's' : '')); } /** * 获取一个基于时间偏移的Unix时间戳 * * @param string $type 时间类型,默认为day,可选minute,hour,day,week,month,quarter,year * @param int $offset 时间偏移量 默认为0,正数表示当前type之后,负数表示当前type之前 * @param string $position 时间的开始或结束,默认为begin,可选前(begin,start,first,front),end * @param int $year 基准年,默认为null,即以当前年为基准 * @param int $month 基准月,默认为null,即以当前月为基准 * @param int $day 基准天,默认为null,即以当前天为基准 * @param int $hour 基准小时,默认为null,即以当前年小时基准 * @param int $minute 基准分钟,默认为null,即以当前分钟为基准 * @return int 处理后的Unix时间戳 */ public static function unixtime($type = 'day', $offset = 0, $position = 'begin', $year = null, $month = null, $day = null, $hour = null, $minute = null) { $year = is_null($year) ? date('Y') : $year; $month = is_null($month) ? date('m') : $month; $day = is_null($day) ? date('d') : $day; $hour = is_null($hour) ? date('H') : $hour; $minute = is_null($minute) ? date('i') : $minute; $position = in_array($position, ['begin', 'start', 'first', 'front']); switch ($type) { case 'minute': $time = $position ? mktime($hour, $minute + $offset, 0, $month, $day, $year) : mktime($hour, $minute + $offset, 59, $month, $day, $year); break; case 'hour': $time = $position ? mktime($hour + $offset, 0, 0, $month, $day, $year) : mktime($hour + $offset, 59, 59, $month, $day, $year); break; case 'day': $time = $position ? mktime(0, 0, 0, $month, $day + $offset, $year) : mktime(23, 59, 59, $month, $day + $offset, $year); break; case 'week': $time = $position ? mktime(0, 0, 0, $month, $day - date("w", mktime(0, 0, 0, $month, $day, $year)) + 1 - 7 * (-$offset), $year) : mktime(23, 59, 59, $month, $day - date("w", mktime(0, 0, 0, $month, $day, $year)) + 7 - 7 * (-$offset), $year); break; case 'month': $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); break; case 'quarter': $time = $position ? mktime(0, 0, 0, 1 + ((ceil(date('n', mktime(0, 0, 0, $month, $day, $year)) / 3) + $offset) - 1) * 3, 1, $year) : 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); break; case 'year': $time = $position ? mktime(0, 0, 0, 1, 1, $year + $offset) : mktime(23, 59, 59, 12, 31, $year + $offset); break; default: $time = mktime($hour, $minute, 0, $month, $day, $year); break; } return $time; } /** * 获取某个日期属于一年中的第几周 * @param $date * @return false|int|string */ public static function getWeekNum($date='') { $date = $date ? $date : date('Y-m-d'); $year = date('Y', strtotime($date)); $yearBegin = strtotime($year.'-1-1'); $month = intval(date('m', strtotime($date))); if( date('W', $yearBegin) == 1 ){ return date('W', strtotime($date)); }else if($month == 1 && date('W', $yearBegin) > 50){ return 1; }else{ return date('W', strtotime($date)) + 1; } } /** * 根据日期,获取周信息 * @param $now string 日期,举例: 2021-01-01 * @return array */ public static function getWeekInfo($now) { $str = []; //$first =1 表示每周星期一为开始日期 0表示每周日为开始日期 $str['year'] = date('Y', strtotime($now)); $first = 1; //当日在整年中的第几周 $str['week'] = date('W', strtotime($now)); //获取当前周的第几天 周日是 0 周一到周六是 1 - 6 $w = date('w', strtotime($now)); //获取本周开始日期,如果$w是0,则表示周日,减去 6 天 $weekStart = date('Y-m-d', strtotime("$now -" . ($w ? $w - $first : 6) . ' days')); $str['week_start'] = $weekStart; //本周结束日期 $weekEnd = date('Y-m-d', strtotime("$weekStart +6 days")); $str['week_end'] = $weekEnd; return $str; } /** * 某去某年第几周的周信息 * @param $year * @param int $week * @return mixed */ public static function weekDay($year, $week=1){ $yearStart = mktime(0,0,0,1,1, $year); $yearEnd = mktime(0,0,0,12,31, $year); $start = $yearStart;//把第一天做为第一周的开始 $end = strtotime('+1 sunday', $yearStart);//把第一个周日作为第一周的结束 $lastStart = strtotime('-1 monday', $yearStart);//把最后一个周一作为最后一周的开始 $lastEnd = $yearEnd;//把最后一天作为最后一周的结束 $totalWeekNum = intval(date('W', $yearStart)); if($week == 1){ $weekday['begin'] = $start;//把第一天做为第一周的开始 $weekday['begin_date'] = date('Y-m-d', $start);//把第一天做为第一周的开始 $weekday['end'] = $end;//把第一个周日作为第一周的结束 $weekday['end_date'] = date('Y-m-d', $end);//把第一个周日作为第一周的结束 }else if($week == $totalWeekNum){ $weekday['begin'] = $lastStart;//把最后一个周一作为最后一周的开始 $weekday['begin_date'] = date('Y-m-d', $lastStart);//把第一天做为第一周的开始 $weekday['end'] = $lastEnd;//把第一个周日作为第一周的结束 $weekday['end_date'] = date('Y-m-d', $lastEnd);//把第一个周日作为第一周的结束 }else if($week > 1 && $week < $totalWeekNum){ $weekday['begin'] = strtotime('+' . ($week-1) . ' monday', $end); $weekday['begin_date'] = date('Y-m-d', $weekday['begin']); $weekday['end'] = strtotime('+' . ($week-1) . ' sunday', $end + 24 * 60 * 60); $weekday['end_date'] = date('Y-m-d', $weekday['end']); }else{ return false; } $weekday['week'] = $week; $weekday['totalWeekNum'] = $totalWeekNum; return $weekday; } /** * 友好的时间显示 * * @param int $sTime 待显示的时间 * @param string $type 类型. normal | mohu | full | ymd | other * @param string $alt 已失效 * @return string */ public static function friendlyDate($sTime,$type = 'default',$alt = 'false') { //sTime=源时间,cTime=当前时间,dTime=时间差 $cTime = time(); $dTime = $cTime - $sTime; $dDay = intval(date("z",$cTime)) - intval(date("z",$sTime)); //$dDay = intval($dTime/3600/24); $dYear = intval(date("Y",$cTime)) - intval(date("Y",$sTime)); //normal:n秒前,n分钟前,n小时前,日期 if($type=='normal'){ if($dTime == 0){ return '现在'; }elseif( $dTime < 60 ){ return $dTime."秒前"; }elseif( $dTime < 3600 ){ return intval($dTime/60)."分钟前"; //今天的数据.年份相同.日期相同. }elseif( $dYear==0 && $dDay == 0 ){ //return intval($dTime/3600)."小时前"; return '今天'.date('H:i',$sTime); }elseif($dYear==0){ return date("m月d日 H:i",$sTime); }else{ return date("Y-m-d H:i",$sTime); } }elseif($type=='mohu'){ if( $dTime < 60 ){ return $dTime."秒前"; }elseif( $dTime < 3600 ){ return intval($dTime/60)."分钟前"; }elseif( $dTime >= 3600 && $dDay == 0 ){ return intval($dTime/3600)."小时前"; }elseif( $dDay > 0 && $dDay<=7 ){ return intval($dDay)."天前"; }elseif( $dDay > 7 && $dDay <= 30 ){ return intval($dDay/7) . '周前'; }elseif( $dDay > 30 ){ return intval($dDay/30) . '个月前'; } //full: Y-m-d , H:i:s }elseif($type=='full'){ return date("Y-m-d , H:i:s",$sTime); }elseif($type=='ymd'){ return date("Y-m-d",$sTime); }else{ if( $dTime < 60 ){ return $dTime."秒前"; }elseif( $dTime < 3600 ){ return intval($dTime/60)."分钟前"; }elseif( $dTime >= 3600 && $dDay == 0 ){ return intval($dTime/3600)."小时前"; }elseif($dYear==0){ return date("Y-m-d H:i:s",$sTime); }else{ return date("Y-m-d H:i:s",$sTime); } } } }