我有一些代码在特定日期开始的10年范围内每天循环。只有在符合表格中的选定条件时才应添加日期。
表单包含要选择的月份和工作日的字段。在每个工作日内,每个,第一个,第二个等都有选项。我在每个工作日添加一个“每隔一个”选项以及一个开始日期字段。
我正在尝试确定根据开始日期检查当前日期是否在“每隔一个”标准范围内的最佳方式。
在查看其他问题之后,我找不到考虑到53周的年份的理想答案。我能够提出一些似乎给我准确结果的测试代码,但我想知道是否有更简单的方法来执行此检查。
测试代码:
// set start date
$date = new \DateTime('2019-12-15');
// get start date week of year and modulus
$start_week = date('W', $date->getTimestamp());
$start_mod = $start_week % 2;
// set end time (10 years from start date)
$end_time = strtotime('+10 years', $date->getTimestamp());
// init previous year and week modifier
$prev_year = false;
$week_modifier = 1;
// each day in range
while($date->getTimestamp() <= $end_time){
// get year
$y = $date->format('Y');
// previous year doesn't match current year
if($prev_year != $y){
// previous year set
if($prev_year){
// get number of weeks in year
$weeks_in_year = date('W', mktime(0, 0, 0, 12, 28, $prev_year));
// year has odd number of weeks
if($weeks_in_year % 2){
// increment week modifier
$week_modifier++;
}
}
// update previous year
$prev_year = $y;
}
// get week of year
$w = $date->format('W') + $week_modifier;
// check if meets every other criteria (based on start date)
$every_other = false;
if( ($w % 2) == $start_mod ){
$every_other = true;
}
// print date if it is part of every other Tuesday
if($date->format('w') == 2 && $every_other){
echo $date->format('Y-m-d');
echo '<br/>';
}
// increment day
$date->modify('+1 day');
}
注1:2020年是下一年,共有53周。
注意2:我在这个测试代码中输入了一个拼写错误,它增加了周修饰符,而不是将其初始化为0.如果修饰符初始化为0,那么这段代码将更有意义。 ,但它只在初始化为奇数时才有效。
答案 0 :(得分:1)
自&#34;每隔一个&#34;在连续循环中进行评估,您可能只是跟踪日期:
$odd = [ true, true, true, true, true, true, true ];
...
// Flip the appropriate day of the week.
$odd[date('w')] = !$odd[date('w')];
// Or start with all 1's, then $odd[date('w')] ^= 1;
if ($odd[date('w')]) {
// This is the "not-other" day
}
这一天是$w
,我们会将其标记为:
$odd[$w] = !$odd[$w];
现在我们前进了不明的天数$d
。我们需要在这段时间内适当地翻转所有的日子。
这样做的一种方法是循环使用所有的日子。但很明显,这可能是必要的 - 我们一周有七天,它们要么是奇数,要么是偶数;即使我们全部翻过来,也会有七次更新。一年的骑行将是365或366次更新。
一方面,365周期解决方案具有简单的优势。运行7翻转而不是3652真的值得我们这么做吗?如果不是,我们就完成了。所以,让我们假设;但是应该为每个项目重新进行评估。
请注意,如果我们提前1天,我们无需做任何事情。如果我们提前2天,则必须翻转[w + 1]天。如果我们提前5天,则需要翻转从w + 1到w + 4的天数。通常,需要翻转从w + 1到w + d-1的天数:
for ($i = 1; $i < $w+$d; $i++) {
$odd[$i % 7] = !$odd[$i % 7];
}
但现在注意到,如果我们提前15天,我们将再次无需做任何事情,好像我们只提前一天,因为一周中的每一天都会发现自己被翻了两次:
d need to flip w+...
1 (none)
2 1
3 1, 2
4 1, 2, 3
5 1, 2, 3, 4
6 1, 2, 3, 4, 5
7 1, 2, 3, 4, 5, 6
8 1, 2, 3, 4, 5, 6, 0 (or 7)
9 2, 3, 4, 5, 6, 0
10 3, 4, 5, 6, 0
11 4, 5, 6, 0
12 5, 6, 0
13 6, 0
14 0
15 (none)
所以这是一个非常合理的妥协:如果我们需要提前X天,那就好像我们必须提前(X%14)天。所以现在我们将运行最多13次更新。现在停止 意味着我们的代码是琐碎的版本,由战略性地放置&#34;%14&#34;增强。我们从3652次更新到14次更新,间隔十年,我们希望最好的是7次更新。我们得到了几乎所有的爆炸声,只有很少的降压。
如果我们想要满足于最好的一切,我们继续(但请注意,额外的算术可能最终比从最差值13到更新中的保存更加昂贵,最多为零。单词,进行额外的检查意味着我们将最多保存13个更新;如果这些检查花费超过13个更新,我们最好不要不检查并盲目地进行检查。
因此,如果(1
// increase by d days
d1 = (d%14) < 9 ? 1 : (d%7);
d2 = (d%14) < 8 ? (d%14-1) : 7;
for (dd = d1; dd <= d2; dd++) {
odd[(w+dd)%7)] = !odd[(w+dd)%7)];
}
以上内容应正确翻转&#34;其他所有XXX&#34;无论d的值如何,最多可执行7次写操作。大概的成本大约是6-7次更新,所以如果我们在内存中这样做,那么平均而言,如果与&#34;%14&#34;进行比较,那么它并不值得。捷径。另一方面,如果我们将单独的SQL查询翻转到持久层,那么......
(你真的想看看我没有犯错......)