5

我有一个 php 代码,如下所示,我想在一周的两个日历日之间显示任何内容。

进入内部并由用户控制的$data->{"select_start_day"}; $data->{"start_time"}; $data->{"select_end_day"};$data->{"end_time"};

PHP代码:

    if (file_exists('feeds/ptp-ess_landing.json')) {
    $data = json_decode(file_get_contents('feeds/ptp-ess_landing.json'));
    }

    date_default_timezone_set('America/Toronto');
    $arradate = strtolower(date('D'));
    $nowtime = (int)date('His');


    $start_day=$data->{"select_start_day"};
    $start_time=$data->{"start_time"};

    $end_day=$data->{"select_end_day"};
    $end_time=$data->{"end_time"};

例如,让我们假设用户输入$start_dayas sun $start_timeas 143400 $end_dayas wed $end_timeas 。140000

上述持续时间意味着我们在范围内,它应该显示我们想要显示的任何内容,直到明天下午 2 点,因为明天是星期三。我在美国东部时间。

我正在使用以下代码来提取一周中的当前日期和时间

date_default_timezone_set('America/Toronto');
$arradate = strtolower(date('D'));
$nowtime = (int)date('His');

问题陈述:

我想知道如果我需要使用逻辑以使其打印任何内容Sunday 143400Wednesday 140000.

if()    {
    echo "Its in range";
}

案例:

  1. 如果本应在星期一上午 8 点星期一下午 6 点适用覆盖, 而今天是星期三,则覆盖不适用。

  2. 如果是周一下午 6 点周五下午 6 点,则覆盖将在周一周二全天周三全天周四全天周五至下午6 点工作6 小时。

  3. 如果是周日下午 6 点周一下午 6 点,则覆盖将在周一工作6 小时,周一工作18 小时

  4. 如果是周二下午 6 点周五下午 6 点,而今天是周二晚上 9 点,则将适用覆盖。

  5. 如果是星期四下午 6 点星期三下午 6 点,则覆盖将在星期四 6 小时星期五24 小时、星期六24 小时、星期日24 小时、星期一24 小时、星期二24 小时、星期三 24 小时18 小时工作。星期四

4

7 回答 7

2

这个问题的困难部分在于处理在周末“环绕”的范围,即您的示例案例 5

我建议设置一个涵盖两周的参考天数

$days = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun'];
$days = array_merge($days, $days);

对其进行切片,使其从起始点的那一天开始(将从 0 重新索引)

$days = array_slice($days, array_search($startDay, $days));

然后,您可以为现在和终点建立一个参考整数

$nowRef = (int) (array_search($nowDay, $days) . $nowTime);
$endRef = (int) (array_search($endDay, $days) . $endTime);

请注意,您可以对起点执行相同的操作,但由于 days 数组以$startDay(index 0) 开头,这相当于$startTime

那么你的 if 条件就变成了

if ($nowRef >= $startTime && $nowRef <= $endRef) {
   // IN RANGE
}

注意这假设您的用户输入已经过验证,并且如果开始日期和结束日期相同,则结束时间大于开始时间


您的命名约定有点不一致,因此我重命名了您的一些变量并切换为骆驼大小写以提高可读性

$nowDay = $arradate;
$nowTime = $nowtime;

$startDay = $start_day;
$startTime = $start_time;

$endDay = $end_day;
$endTime = $end_time;
于 2019-10-02T13:25:01.683 回答
1

这是我的尝试,使用映射表和字符串连接。如果日子顺序颠倒,它就不起作用。例如,如果今天是星期日,并且 is 的值和isselect_start_dayFri值,那么它将不起作用。select_end_dayMon

<?php

$arr = (object) [
    'select_start_day' => 'wed',
    'start_time' => 143400,
    'select_end_day' => 'wed',
    'end_time' => 220000
];

$map_daysToNumbers = ['sun'=>1, 'mon'=>2, 'tue'=>3, 'wed'=>4, 'thu'=>5, 'fri'=>6, 'sat'=>7];

$startString = $map_daysToNumbers[$arr->select_start_day] . str_pad($arr->start_time, 6, '0', STR_PAD_LEFT);
$endString = $map_daysToNumbers[$arr->select_end_day] . str_pad($arr->end_time, 6, '0', STR_PAD_LEFT);

$tz = new \DateTimeZone('America/Toronto');

$today = new \DateTime('now', $tz);

$todayString = ($today->format('w')+1) . $today->format('His');

if($startString <= $todayString && $todayString <= $endString){
    echo 'In range';
}

或基于日期的解决方案。它们都不能保证满足您的需求。

$arr = (object) [
    'select_start_day' => 'tue',
    'start_time' => 143400,
    'select_end_day' => 'wed',
    'end_time' => 220000
];

$tz = new \DateTimeZone('America/Toronto');

// extrapolate the start date looking 7 days back
$sDate = new \DateTime('tomorrow midnight', $tz);
$sDate->modify('last '.$arr->select_start_day);
$sDate->setTime(...str_split(str_pad($arr->start_time, 6, '0', STR_PAD_LEFT), 2));
// or bound the start date to be between last sunday and next saturday
$sDate = new \DateTime('Saturday last week', $tz);
$sDate->modify('next '.$arr->select_start_day);
$sDate->setTime(...str_split(str_pad($arr->start_time, 6, '0', STR_PAD_LEFT), 2));

// extrapolate the end date
$eDate =  clone $sDate;
$eDate->modify('yesterday'); // workaround to consider the same day possibility
$eDate->modify('next '.$arr->select_end_day);
$eDate->setTime(...str_split(str_pad($arr->end_time, 6, '0', STR_PAD_LEFT), 2));

// Test against today
$today = new \DateTime('now', $tz);

var_dump($sDate);
var_dump($eDate);
var_dump($today);

if($sDate <= $today && $today <= $eDate){
    echo 'In range';
}

第一种方式总是从过去开始,取决于你的范围,它可能包括今天或不包括。第二个将始终绑定到当前周,我相信这就是您想要的。

正如@mickmackusa 和我在评论中所说,给你的要求是模糊和不精确的。您需要更严格的规则或基于日期的解决方案,即给您两个精确的日期(时间戳),然后比较日期是否介于它们之间。这是我在第二个选项中尝试做的,但不知道日期应该是过去还是将来。

于 2019-10-01T23:13:59.103 回答
1

首先,我可以推荐你使用面向对象的编程来更好地结构化你的代码和分解任务。您可以创建一个抽象来处理工作日时间。例如:

class WeekDayTime
{
    /** @var string[] map of the name of days and their number */
    const DAY_MAP = [
        'Mon' => 1,
        'Tue' => 2,
        'Wed' => 3,
        'Thu' => 4,
        'Fri' => 5,
        'Sat' => 6,
        'Sun' => 7
    ];

    /** @var int number of the day */
    private $dayNumber;

    /** @var int amount of hours */
    private $hours;

    /** @var int amount of minutes */
    private $minutes;

    /** @var int amount of seconds */
    private $seconds;

    /**
     * Constuctor
     * @param string $day number of the day
     * @param int $hours amount of hours
     * @param int $minutes amount of minutes
     * @param int $seconds amount of seconds
     */ 
    public function __construct(string $day, int $hours, int $minutes, int $seconds)
    {
        assert(array_key_exists($day, static::DAY_MAP), 'The day is incorrect');
        assert($hours < 24, 'The hours must be less than 24');
        assert($minutes < 60, 'The hours must be less than 60');
        assert($seconds < 60, 'The hours must be less than 60');
        $this->dayNumber = static::DAY_MAP[$day];
        $this->hours = $hours;
        $this->minutes = $minutes;
        $this->seconds = $seconds;
    }

    /**
     * Get number of the day
     * @return int number of the day
     */
    public function getDayNumber(): int
    {
        return $this->dayNumber;
    }

    /**
     * Get amount of hours
     * @return int amount of hours
     */
    public function getHours(): int
    {
        return $this->hours;
    }

    /**
     * Get amount of minutes
     * @return int amount of minutes
     */
    public function getMinutes(): int
    {
        return $this->minutes;
    }

     /**
     * Get amount of seconds
     * @return int amount of seconds
     */
    public function getSeconds(): int
    {
        return $this->seconds;
    }

    /**
     * Check if the current week day time is less the a denined week day time
     * @param WeekDayTime $value value which will be compared
     * @return bool status of the checking
     */
    public function isLessOrEqual(WeekDayTime $value): bool
    {
        $isLess = $this->dayNumber < $value->dayNumber;
        $isLessOrEqual = $this->dayNumber === $value->getDayNumber()
            && $this->hours <= $value->getHours()
            && $this->minutes <= $value->getMinutes()
            && $this->seconds <= $value->getSeconds();
        return $isLess || $isLessOrEqual;
    }

    /**
     * Check if the current week day time is greater the a denined week day time
     * @param WeekDayTime $value value which will be compared
     * @return bool status of the checking
     */
    public function isGreaterOrEqual(WeekDayTime $value): bool
    {
        $isGreater = $this->dayNumber > $value->dayNumber;
        $isGreaterOrEqual = $this->dayNumber === $value->getDayNumber()
            && $this->hours >= $value->getHours()
            && $this->minutes >= $value->getMinutes()
            && $this->seconds >= $value->getSeconds();
        return $isGreater || $isGreaterOrEqual;
    }
}

它将是对象值,它将包含有关星期几和时间的信息以及比较此类对象的方法。在它之后,您可以创建一个包含一系列工作日时间的类。例如:

class WeekDayTimeRange
{
    /** WeekDayTime range start */
    private $start;

    /** WeekDayTime range end */
    private $end;

    /**
     * Constuctor
     * @param WeekDayTime $start range start
     * @param WeekDayTime $end range end
     */
    public function __construct(WeekDayTime $start, WeekDayTime $end)
    {
        $this->start = $start;
        $this->end = $end;
    }

    /**
     * Check if a date-time occurs into the range
     * @param DateTimeInterface the date-time which will be checked
     * @return bool status of the checking
     */
    public function inRange(DateTimeInterface $dateTime): bool
    {}
}

如您所见,此类包含有关范围开始、范围结束和检查范围内任何日期时间出现的方法的信息。如果您想检查开始值小于结束值的范围(例如从星期一到星期五)的出现,您可以执行以下inRange方法实现:

public function inRange(DateTimeInterface $dateTime): bool
{
    $day = $dateTime->format('D');
    $hours = $dateTime->format('H');
    $minutes = $dateTime->format('i');
    $seconds = $dateTime->format('s');
    $weekDayTime = new WeekDayTime($day, $hours, $minutes, $seconds);

    return $this->start->isLessOrEqual($weekDayTime) && $this->end->isGreaterOrEqual($weekDayTime);
}

但是,如果您想检查开始值大于结束值的范围(例如从星期五到星期一),您应该将范围分为两个范围:从范围开始到周末,从一周开始到范围结束,然后到检查日期时间在两个范围内的出现。例如:

public function inRange(DateTimeInterface $dateTime): bool
{
    $day = $dateTime->format('D');
    $hours = $dateTime->format('H');
    $minutes = $dateTime->format('i');
    $seconds = $dateTime->format('s');
    $weekDayTime = new WeekDayTime($day, $hours, $minutes, $seconds);

    // if the range end is less then range start we break the current range to two range
    if ($this->end->isLessOrEqual($this->start))  {
        $range1 = new WeekDayTimeRange($this->start, new WeekDayTime('Sun', 23,59,59));
        $range2 = new WeekDayTimeRange(new WeekDayTime('Mon', 0,0,0), $this->end);
        return $range1->inRange($dateTime) || $range2->inRange($dateTime);
    }

    return $this->start->isLessOrEqual($weekDayTime) && $this->end->isGreaterOrEqual($weekDayTime);
}

使用示例:

// Date occurs into the range from Tuesday to Friday
$start = new WeekDayTime('Tue', 10, 0,0);
$end = new WeekDayTime('Fri', 14, 0,0);
$range = new WeekDayTimeRange($start, $end);
$range->inRange(DateTime::createFromFormat('Y-m-d H:i:s', '2019-10-03 10:00:00'));

// Date doesn't occur into the range from Tuesday to Friday
$start = new WeekDayTime('Tue', 10, 0,0);
$end = new WeekDayTime('Fri', 14, 0,0);
$range = new WeekDayTimeRange($start, $end);
$range->inRange(DateTime::createFromFormat('Y-m-d H:i:s', '2019-10-05 10:00:00'));

// Date doesn't occur into the range from Friday to Tuesday
$start = new WeekDayTime('Fri', 14, 0,0);
$end = new WeekDayTime('Tue', 10, 0,0);
$range = new WeekDayTimeRange($start, $end);
$range->inRange(DateTime::createFromFormat('Y-m-d H:i:s', '2019-10-03 10:00:00'));

// Date occurs into the range from Friday to Tuesday
$start = new WeekDayTime('Fri', 14, 0,0);
$end = new WeekDayTime('Tue', 10, 0,0);
$range->inRange(DateTime::createFromFormat('Y-m-d H:i:s', '2019-10-05 10:00:00'));

你可以在沙盒看到演示

于 2019-10-04T12:47:37.050 回答
0

我会以相同的格式保留所有日期。Unix 时间是存储时间的好方法,因为您可以轻松地运行计算。

在您的示例中,您正在使用字符串和数字进行计算。事实上,你有 3 种不同的方式来表达日期。我建议仅使用 date() 来保存和比较所有值,并且在向最终用户显示时仅格式化该 Unix 时间戳。

↓↓↓↓新编辑↓↓↓</p>

仔细查看您的代码返回的内容:

$arradate = strtolower(date('D')); //echos the day ex: sun
$nowtime = (int)date('His'); //echos a different format ex: 25019

并仔细阅读日期函数的文档,特别是您现在选择的参数“他的”,它将返回:

H 小时的 24 小时格式,前导零 00 到 23

i 分钟,前导零 00 到 59

s 带前导零的秒数 00 到 59

现在考虑 date() 返回一个Unix时间戳,您将看到失败。您只需要在所有代码保存中删除显示给最终用户的元素的日期格式。知道现在是星期三,计算机没有任何好处。计算机仅从 1970 年开始计数。

所以你只需要一个参数来调用当前日期。要么工作:

$arradate = date(); 
$nowtime = date(); 

最后,在阅读了有关 Unix 时间的信息后,您将看到您存储的日期是倒数的。您的 end_time 是第 0 天,而您的开始时间是之后的两天。

于 2019-09-29T02:45:17.467 回答
0

试试这个:

$dowMap = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];

$arradate = date('D');

$arradateNum = array_search($arradate, $dowMap);

$start_dayNum = array_search($start_day, $dowMap);

$end_dayNum = array_search($end_day, $dowMap);

if(
    ($arradateNum >= $start_dayNum && $nowtime>=$data->{"start_time"}) && 
    ($arradateNum <= $end_dayNum && $nowtime <= $data->{"end_time"})
) {
    echo "Show Anything";  
}

于 2019-09-29T03:22:37.963 回答
0

您应该彻底阅读 PHP 手册并了解如何创建 DateTime 对象和各种可用的日期格式。

首先,您需要将用户输入转换为 DateTimeObjects。由于用户输入仅包含 Day(由 D 表示)和 Time(由 His 表示),您可以使用以下代码来获取这些对象。

date_default_timezone_set('America/Toronto'); //Setting the Timezone
//These are the User Inputs
$start_day = 'tue';
$start_time  = 181300;

$end_day = 'fri';
$end_time  = 134500;
//User Input Ends

//Create the Date Time Object for Start and End Date
$startDate = DateTime::createFromFormat ( 'D His', $start_day . ' '. $start_time);
$endDate = DateTime::createFromFormat ( 'D His', $end_day . ' '. $end_time);

您可以在手册中检查可用于 createFromFormat 的各种选项

现在您有了日期时间对象,您可以从中获得任何价值。让我们以数字格式获取星期几以及开始和结束日期的数字格式的小时。

$startHour = $startDate->format('G');  //24-hour format of an hour without leading zeros
$startDay = $startDate->format('N');  //numeric representation of the day of the week

$endHour = $endDate->format('G'); //24-hour format of an hour without leading zeros
$endDay = $endDate->format('N');  //numeric representation of the day of the week

您可以检查关于GN格式以及手册中可用的其他选项

我们需要检查时间是在星期二下午 6 点到星期五下午 6 点之间。

首先,我们将检查这一天是否在周二和周五之间。我们有上面的$startDay$endDay变量来确定这一点。周二对应的数值是 2,周五对应的数值是 5。

对于时间范围,我们有$startHour$endHour变量。格式中的 6PM 表示为 18 ( 12 + 6)。

所以我们可以使用以下代码检查这个条件:

if ( $startDay >= 2 && $endDay <= 5 && $startHour >= 18 and $endHour <= 18 ) {
    echo 'In Range';
} else {
    echo 'out of Range';
}

这样您就可以检查任何复杂的情况。您可以在3v4l看到在线演示

于 2019-10-01T06:04:37.193 回答
0

这是在持续时间之间显示任何内容的示例

在开始时间和结束时间添加多伦多的任何时间..您将在每周的这一天和持续时间之间获得输出。

date_default_timezone_set('America/Toronto');
$now     = new DateTime(); 
$date    = $now->format('Y-m-d');
$time    = $now->format('h:i A');
$dayname = strtolower(date('l', strtotime($date))); //it will give you today's day name


$start_day = "monday"; //lets consider your data will be come as startday="monday" from $data->{"select_start_day"};
$start_time = '07:50 AM'; //lets consider your data will be come as starttime="07:50 AM" from $data->{"start_time"}; 
$end_day = "tuesday"; //lets consider your data will be come as endday="monday" from $data->{"select_end_day"};
$end_time = '08:26 AM'; //lets consider your data will be come as endtime="08:26 AM" from $data->{"end_time"}; 

$todays_date_time    = strtotime($dayname);
$start_day_time      = strtotime($start_day);
$end_day_time        = strtotime($end_day);
$timeconvert         = strtotime($time);
$timeconvertstart    = strtotime($start_time);
$timeconvertend      = strtotime($end_time);

if($todays_date_time >= $start_day_time && $todays_date_time <= $end_day_time ) 
 {
  if ($timeconvert >= $timeconvertstart && $timeconvert <= $timeconvertend) { 
     echo "test";
 }
}

我希望这个对你有帮助!

于 2019-10-07T11:16:02.850 回答