我有一个函数,它计算一个特定的时间字符串之前的秒、分钟、小时等等。
然而,我这样做是由一个庞大的if语句块组成的,它贯穿于它能够达到的每一个特定时间。
是否有更好的方法来编写这段代码,使其更高效,并且没有一个庞大的if语句块?
define('SECS_IN_MIN', 60);
define('SECS_IN_HR', 3600);
define('SECS_IN_DAY', 86400);
define('SECS_IN_WEEK', 604800); // 7 days
define('SECS_IN_MONTH', 2592000); // 30 days
define('SECS_IN_YEAR', 31536000); // 365 days
// Determines if a number is a plural
// Input: Takes in a number
// Output: Outputs a string which is either "s", if plural
// OR "" if not plural
function is_plural($num) {
if ($num != 1) return "s";
else return "";
}
// Gets a string line x minutes ago
// Input a date
// Output: a string which matches its time ago
function date_to_str($time) {
$currTime = time();
$pastTime = strtotime($time);
$diff = $currTime - $pastTime;
// Seconds Ago
if ($diff < SECS_IN_MIN) {
$plural = is_plural($diff);
return "$ans few second$plural ago";
// Minutes Ago
} else if($diff < SECS_IN_HR) {
$ans = floor($diff / SECS_IN_MIN);
$plural = is_plural($ans);
return "$ans minute$plural ago";
// Hours Ago
} else if ($diff < SECS_IN_DAY) {
$ans = floor($diff / SECS_IN_HR);
$plural = is_plural($ans);
return "$ans hour$plural ago";
// Days Ago
} else if ($diff < SECS_IN_WEEK) {
$ans = floor($diff / SECS_IN_DAY);
$plural = is_plural($ans);
return "$ans day$plural ago";
// Weeks ago
} else if ($diff < SECS_IN_MONTH) {
$ans = floor($diff / SECS_IN_WEEK);
$plural = is_plural($ans);
return "$ans week$plural ago";
// Months Ago
} else if ($diff < SECS_IN_YEAR) {
$ans = floor($diff / SECS_IN_MONTH);
$plural = is_plural($ans);
return "$ans month$plural ago";
// Years Ago
} else if ($diff > SECS_IN_YEAR * 10) {
$ans = floor($diff / SECS_IN_YEAR);
$plural = is_plural($ans);
return "$ans year$plural ago";
}
return "-1";
}
$time = "2020-08-25 13:02:32"
echo( date_to_str($time) );
// Outputs 4 days ago发布于 2020-08-29 06:07:59
首先,下面是我推荐的脚本替换(受这是如此的帖子启发)和一些测试用例:
代码:(演示)
function secondsToTime($seconds) {
$dtF = new DateTime('@0');
$dtT = new DateTime("@$seconds");
$diff = $dtF->diff($dtT);
$units = [
'y' => 'year',
'm' => 'month',
'd' => 'day',
'h' => 'hour',
'i' => 'minute',
's' => 'second'
];
foreach ($units as $char => $unit) {
if ($diff->$char) {
if ($char === 'd' && $diff->$char >= 7) {
$diff->$char = floor($diff->$char / 7);
$unit = 'week';
}
return sprintf(
'%d %s%s ago',
$diff->$char,
$unit,
$diff->$char !== 1 ? 's' : ''
);
}
}
}
$tests = [
53 => 53, // y=0, m=0, d=0, h=0, i=0, s=53
365 => 365, // y=0, m=0, d=0, h=0, i=6, s=5
7200 => 7200, // y=0, m=0, d=0, h=2, i=0, s=0
176455 => 176455, // y=0, m=0, d=2, h=1, i=0, s=55
2002000 => 2002000, // y=0, m=0, d=23, h=4, i=6, s=40
4592000 => 4592000, // y=0, m=1, d=22, h=3, i=33, s=20
66536000 => 66536000 // y=2, m=1, d=9, h=2, i=13, s=20
];
var_export(
array_map('secondsToTime', $tests)
);输出:
array (
53 => '53 seconds ago',
365 => '6 minutes ago',
7200 => '2 hours ago',
176455 => '2 days ago',
2002000 => '3 weeks ago',
4592000 => '1 month ago',
66536000 => '2 years ago',
)通过利用PHP对象的优点,您可以从DateTime计算中选择最大的非零单元,并从循环/函数中快速返回。作为一种奖励,您不需要担心夏时制或闰年之类的事情--相信diff()方法。
如果您调用var_export($diff),您将看到填充了其他属性,但您只需要其中的6个。
我不认为我会麻烦一个多元函数的开销,只需将条件写成内联条件(三元)即可。
如果你想让$unit成为常量,好吧,因为它不会变异。
唯一需要的特殊处理是周计算,因为这不是对象中立即可用的属性。执行简单的算法并更改要显示的单元,然后继续返回所需的字符串。
至于批评你的代码:
$ans总是返回,但并不总是声明的;我假设这是您忽略的错误。is_plural()条件块缺少它的大括号。else if作为两个词在php中是违反PSR-12编码标准的.你应该把一个词组成为elseif。-1返回永远不会达到,但如果达到了,那就意味着您需要验证传入的秒值。https://codereview.stackexchange.com/questions/248595
复制相似问题