【问题标题】:How to display anything in php in between particular time duration?如何在特定时间段之间在 php 中显示任何内容?
【发布时间】:2020-01-28 19:05:48
【问题描述】:

我有一个如下所示的 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_daysun $start_time as 143400 $end_day as wed $end_time as 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 小时

【问题讨论】:

  • 来自 JSON。它是一个单独的管理门户。我正在添加更多代码以使其清晰。
  • 是的,也许更有意义,但你为什么要使用大括号?为什么不$data->select_start_day
  • 这只是一种习惯。我同意我们可以不使用大括号。
  • 你的一周从什么时候开始?范围可以是周四到周三吗?
  • 我已经阐述了答案。

标签: php date if-statement time and-operator


【解决方案1】:

这个问题的难点在于处理在周末“环绕”的范围,即您的示例案例 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(索引 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;

【讨论】:

  • 我想知道您是否可以根据我在上述问题中给出的输入来修改代码。这是我尝试过的3v4l.org/56SZt 如果它看起来不错,请告诉我。
  • @flash 是的,就我所见,看起来不错,我在答案的底部附上了一个图例,表明我已重命名了哪些变量:)
  • 您的答案看起来非常好,它对我有用。谢谢你的帮助。我想出了一个条件。抱歉,要求超出了我的控制范围。假设它的Thursday 160000Thursday 140000 在技术上不正确。在这种情况下,当星期几相同时,那么 $endTime 应该总是大于 $startTime。当星期几相同时,我们是否可以验证$endTime 应始终大于$startTime
  • @flash 很高兴为您提供帮助,如果答案有帮助,请考虑对其进行投票和/或标记为已接受。回复:验证,你应该有一些东西来检查用户的输入是否有意义(实际上是适当的日期和时间)并且如果($startDay == $endDay &amp;&amp; $startTime &gt; $endTime也失败)。任何错误都可以报告给用户,让他们有机会选择不同的输入:)
【解决方案2】:

这是我的尝试,使用映射表和字符串连接。如果日子顺序颠倒,它就不起作用。例如如果今天是星期天,select_start_day 的值为Friselect_end_day 的值为Mon,那就不行了。

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

【讨论】:

  • 您好,这种情况下失败了。 Tuesday 6pmFriday 6pm。现在是美国东部标准时间晚上 10 点。
  • 我认为你是根据日期编写代码,而不是根据星期几,这就是它失败的原因。
  • 我调试好了,Start Date : DateTime Object ( [date] =&gt; 2019-09-25 11:30:00.000000 [timezone_type] =&gt; 3 [timezone] =&gt; America/Toronto ) End Date : DateTime Object ( [date] =&gt; 2019-09-25 11:35:00.000000 [timezone_type] =&gt; 3 [timezone] =&gt; America/Toronto ) Server Time : DateTime Object ( [date] =&gt; 2019-10-02 11:37:39.000000 [timezone_type] =&gt; 3 [timezone] =&gt; America/Toronto )
  • 我承认,我的解决方案并非万无一失。稍后我会看看它。
  • 好的,如果您查看此3v4l.org/4X480 我在美国东部标准时间,今天是星期三。我输入了wednesday 130000wednesday 140000。该代码将在 9 月 25 日星期三进行,而不是今天。简而言之,应该根据星期几而不是日期来完成。
【解决方案3】:

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

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'));

您可以在sandbox查看演示

【讨论】:

    【解决方案4】:

    试试这个:

    $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";  
    }
    
    

    【讨论】:

    • 我认为这种逻辑在某些情况下是失败的。
    • 时间逻辑没有问题。我在星期几的逻辑中发现了一些问题。在这个$arradateNum &gt;= $start_dayNum$arradateNum &gt;= $end_dayNum
    • 当一周的开始日期是Monday时间111300,一周的结束日期是Saturday时间115702时,这个逻辑失败了
    • 你在吗?
    • 我已经修改了我的问题。让我知道它是否有意义
    【解决方案5】:

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

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

    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);
    

    您可以在Manual 中查看可用于 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 格式以及Manual 中可用的其他选项

    我们需要检查时间是在星期二下午 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查看在线演示

    【讨论】:

    • 我已经编辑了我的问题。这只是一个示例。用户可以输入一周中的任何一天和时间。用户不必输入mon 111300sat 114500
    • @flash 是的,该代码适用于任何用户输入。您需要使用 $_POST 捕获用户输入
    • 我想知道您是否可以更新答案。我也是从我这边做的。
    • 我可以更新,但您面临的问题是什么?
    • 第一部分应该是这样的if ( $startDay &gt;= $arradate &amp;&amp; $endDay &lt;= $arradate &amp;&amp; $startHour &gt;= 18 and $endHour &lt;= 18 ) { echo 'In Range'; } else { echo 'out of Range'; }用户输入的时间是hhmmss而不是小时。
    【解决方案6】:

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

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

    ↓↓↓↓新编辑↓↓↓

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

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

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

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

    i 分钟,前导零 00 到 59

    s 秒,前导零 00 到 59

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

    所以你只需要一个参数来调用当前日期。两者都可以:

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

    最后,在阅读了有关 Unix 时间的内容后,您会发现您存储的日期是倒数的。您的 end_time 是第 0 天,而您的开始时间是之后的两天。

    【讨论】:

    • 只有一种方法。 $arradate = strtolower(date('D')); 提取日期。用户在这里输入了日期$start_day=$data-&gt;{select_start_day};$end_day=$data-&gt;{select_end_day};
    • 用一个例子编辑。
    • 我已经修改了我的问题。让我知道它是否有意义
    • 是的,您还打开了一个副本。解决方案保持不变。
    【解决方案7】:

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

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

    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";
     }
    }
    

    希望这篇文章对你有帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-01-08
      • 2019-12-01
      • 1970-01-01
      • 2019-09-14
      • 1970-01-01
      • 2019-08-18
      • 2016-05-20
      相关资源
      最近更新 更多