我用PHP为在线电子竞技联赛编写了一个循环赛生成器,我需要计算锦标赛中每场比赛的日期。比赛在每周四和周日进行,持续数周(周数取决于参赛队伍的数量)。给定起始周和周数,计算这些日期的最佳方法是什么?
我猜它需要使用DateTime, DateInterval和DatePeriod的一些组合;但是我不知道该怎么做。
更新:很抱歉之前没有提供代码。这是我最初想到的解决方案。我不知道是否有更简单的方法。生成日期的函数名为submitSchedule。
<html>
<body>
<?php
function roundRobin($teams) {
$len = count($teams);
$schedule = array();
for ($i = 0; $i < $len - 1; $i++)
{
$home = array_slice($teams, 0, $len / 2);
$away = array_slice($teams, $len / 2);
$day = array();
for ($j = 0; $j < $len / 2; $j++)
{
array_push($day, array($home[$j], $away[$j]));
}
array_push($schedule, $day);
$temp = $away[0];
for ($j = 0; $j < count($away) - 1; $j++)
{
$away[$j] = $away[$j + 1];
}
$away[count($away) - 1] = $home[count($home) - 1];
for ($j = count($home) - 1; $j > 1; $j--)
{
$home[$j] = $home[$j - 1];
}
$home[1] = $temp;
$teams = array_merge($home, $away);
}
return $schedule;
}
function roundRobinBalanced($teams)
{
$schedule = roundRobin($teams);
for ($i = 1; $i < count($schedule); $i+=2)
{
$schedule[$i][0] = array_reverse($schedule[$i][0]);
}
return $schedule;
}
function doubleRoundRobinBalanced($teams)
{
$sched2 = roundRobinBalanced($teams);
for ($i = 0; $i < count($sched2); $i++)
{
$sched2[$i] = array_reverse($sched2[$i]);
}
return array_merge(roundRobinBalanced($teams), $sched2);
}
function tripleRoundRobinBalanced($teams)
{
return array_merge(doubleRoundRobinBalanced($teams), roundRobinBalanced($teams));
}
function submitSchedule($schedule, $start, $intervals, &$con)
{
mysqli_query($con, "TRUNCATE TABLE matches");
$curDate = $start;
echo "<pre>";
for ($i = 0; $i < count($schedule); $i++)
{
for ($j = 0; $j < count($schedule[$i]); $j++)
{
$temp0 = $schedule[$i][$j][0];
$temp1 = $schedule[$i][$j][1];
$temp2 = date_format($curDate, "Y-m-d");
mysqli_query($con,"INSERT INTO matches (T1ID, T2ID, gameDate) VALUES ('$temp0', '$temp1', '$temp2')");
echo "<span style="background:lightblue;">( " . date_format(new DateTime(), "Y-m-d H:i:s") . " )</span>" . "> INSERT INTO matches (T1ID, T2ID, gameDate) VALUES (". $schedule[$i][$j][0] . ", " . $schedule[$i][$j][1] . ", "" . date_format($curDate, "Y-m-d") . "")<br>";
}
date_add($curDate, date_interval_create_from_date_string($intervals[$i % count($intervals)]));
}
echo "</pre>";
}
$teams = array();
$con=mysqli_connect("localhost:3306","root","REMOVED","schedule");
// Check connection
if (mysqli_connect_errno()) {
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
//Select all items from the 'teams' table and order them first in descending order by points, then in ascending order by 'teamName'
$result = mysqli_query($con,"SELECT * FROM teams");
while($row = mysqli_fetch_array($result))
{
array_push($teams, $row['TID']);
}
if (count($teams) % 2 == 1)
{
array_push($teams, null);
}
shuffle($teams);
$schedule = tripleRoundRobinBalanced($teams);
// echo "<pre>" . json_encode($schedule, JSON_PRETTY_PRINT, JSON_FORCE_OBJECT) . "</pre>";
echo "<pre>";
print_r($schedule);
echo "</pre>";
// ---- List of possible DateTime expressions ----
// thursday
// next thursday
// YYYY-MM-DD
// DD/MM/yy
// thursday + 1 day
$start = new DateTime("thursday"); // Indicates the date of the first game
$jump = array("3 days", "4 days"); // Indicates the time intervals of each game (e.g. If day 1 starts on thursday, day 2 starts on sunday, day 3 starts on thursday, etc.)
submitSchedule($schedule, $start, $jump, $con);
mysqli_close($con);
?>
</body>
</html>
实现这一点的方法是使用PHP的DateTime类。它们真的非常有用。我建议用这样一个小函数:-
/**
* @param $startWeek ISO week number of the first week
* @param $numWeeks The number of weeks to run including the first
*
* @return DateTime[] An array of DateTime objects
*/
function getPlayDays($startWeek, $numWeeks)
{
$numWeeks --;
$result = [];
$currYear = (int)(new DateTime())->format('Y');
$oneDay = new DateInterval('P1D');
// Start on the first Thursday of the given week.
$startDate = (new DateTime())->setISODate($currYear, $startWeek, 4);
$endDate = clone $startDate;
$endDate->add(new DateInterval("P{$numWeeks}W"));
// End on the Sunday of the last week.
$endDate->setISODate((int)$endDate->format('o'), (int)$endDate->format('W'), 7);
$period = new DatePeriod($startDate, $oneDay, $endDate->add($oneDay));
foreach($period as $day){
if(4 === (int)$day->format('N') || 7 === (int)$day->format('N') ){
$result[] = $day;
}
}
return $result;
}
foreach(getPlayDays(1, 3) as $playDay){
var_dump($playDay->format('D m-d-Y'));
}
您没有指定如何确定起始周,所以我假设是ISO周号。
输出: -
string 'Thu 01-02-2014' (length=14)
string 'Sun 01-05-2014' (length=14)
string 'Thu 01-09-2014' (length=14)
string 'Sun 01-12-2014' (length=14)
string 'Thu 01-16-2014' (length=14)
string 'Sun 01-19-2014' (length=14)
看到它在工作
DateTime手册。
由于内置的DateTime类的魔力,该函数将非常愉快地处理DST更改,闰年和接近一年开始和结束的星期:)
证明或STFU
看一下strtotime函数:
http://www.php.net/manual/en/function.strtotime.php你可以这样做:
$startDate = "May 15, 2014";
$startDate = strtotime($startDate);
你可以通过简单地加上三天来得到周日比赛的开始:
$nextDate = strtotime("+3 day", $startDate);
你的问题有点模糊,但我认为这就是你要问的。
假设您有起始周当天的时间戳(06:00 AM时间)…以后每隔一个日期为7天(86400秒* 7)。
让我们假设你将运行这个52周(1年)
$firstThu = 1234567890;
$firstSun = 9876543210;
$nextThus = array();
$nextSuns = array();
for($i=0; $i<52; $i++) {
$nextThus[] = date('d/m/Y', $firstThu + (86400 * 7 * $i));
$nextSuns[] = date('d/m/Y', $firstSun + (86400 * 7 * $i));
}
在循环结束时,您将得到包含所有52周日期的两个数组。