【问题标题】:Why is this addition function sometimes not working in PHP?为什么这个加法函数有时在 PHP 中不起作用?
【发布时间】:2019-11-11 11:34:57
【问题描述】:

我目前正在编写一个课程来以特定格式管理时间。输出始终采用以下格式:0000:00:0:00:00,代表YYYY:WW:D:HH:MM。 我有一个增加时间的功能,它似乎运行良好,直到我尝试多次调用它。

我使用此代码添加时间,它应该返回0000:00:0:00:42,但它返回了0000:00:0:03:60

这是我的完整课程。 https://3v4l.org/YiEQF上的代码演示

<?php

namespace Core\component\time;

final class TimeFactory {

    /** @var int */
    private $year;
    /** @var int */
    private $weekNumber;
    /** @var int */
    private $day;
    /** @var int */
    private $hour;
    /** @var int */
    private $minute;

    /**
     * @param string $formatted
     * @return static
     */
    public static function createFromString(string $formatted): self {
        if (!preg_match('/^(\d{4}):(\d{2}):(\d{1}):(\d{2}):(\d{2})$/', $formatted, $matches)) {
            throw new \InvalidArgumentException('Invalid currency format.');
        }
        return new self(...array_slice($matches, 1));
    }

   
    /**
     * TimeFactory constructor.
     * @param int $year
     * @param int $weekNumber
     * @param int $day
     * @param int $hour
     * @param int $minute
     */
    public function __construct(int $year, int $weekNumber, int $day, int $hour, int $minute)
    {
        $this->year = $year;
        $this->weekNumber = $weekNumber;
        $this->day = $day;
        $this->hour = $hour;
        $this->minute = $minute;
    }

    /**
     * @param int $addedYears
     * @return bool
     */
    public function addYears(int $addedYears): bool {
        $newYears = $this->year + $addedYears;
        if($newYears > 9999) {
            return false;
        } else {
            $this->year += $newYears;
        }
        return true;
    }

    /**
     * @param int $addedWeeks
     */
    public function addWeeks(int $addedWeeks): void {
        $newWeeks = $this->weekNumber + $addedWeeks;
        if($newWeeks >= 52) {
            $years = round($newWeeks / 52, 0, PHP_ROUND_HALF_DOWN);
            $this->addYears($years);
        }
        $this->weekNumber += $newWeeks % 52;
    }

    /**
     * @param int $addedDays
     */
    public function addDays(int $addedDays): void {
        $newDays = $this->day + $addedDays;
        if($newDays >= 7) {
            $weeks = round($newDays / 7, 0, PHP_ROUND_HALF_DOWN);
            $this->addWeeks($weeks);
        }
        $this->day += $newDays % 7;
    }

    /**
     * @param int $addedHours
     */
    public function addHours(int $addedHours): void {
        $newHours = $this->hour + $addedHours;
        if($newHours >= 24) {
            $days = round($newHours / 24, 0, PHP_ROUND_HALF_DOWN);
            $this->addDays($days);
        }
        $this->hour += $newHours % 24;
    }

    /**
     * @param int $addedMinutes
     */
    public function addMinutes(int $addedMinutes): void {
        $newMinutes = $this->minute + $addedMinutes;
        if($newMinutes >= 60) {
            $hours = round($newMinutes / 60, 0, PHP_ROUND_HALF_DOWN);
            $this->addHours($hours);
        }
        $this->minute += $newMinutes % 60;
    }

    /**
     * @return int
     */
    public function getYears(): int {
        return $this->year;
    }

    /**
     * @return int
     */
    public function getWeeks(): int {
        return $this->weekNumber;
    }

    /**
     * @return int
     */
    public function getDays(): int {
        return $this->day;
    }

    /**
     * @return int
     */
    public function getHours(): int {
        return $this->hour;
    }

    /**
     * @return int
     */
    public function getMinutes(): int {
        return $this->minute;
    }

    public function reduceTime(Int $amount, String $type) : bool {
        switch($type) {
            case "m":
                if($this->getMinutes() >= $amount) {
                    $this->minute -= $amount;
                    return true;
                } else {
                    if($this->getHours() > 0) {
                        $this->hour -= 1;
                        $minutesToAdd = 60 - $amount;
                        $this->addMinutes($minutesToAdd);
                        return true;
                    } elseif ($this->getDays() > 0) {
                        $this->day -= 1;
                        $hoursToAdd = 23;
                        $minutesToAdd = 60 - $amount;
                        $this->addHours($hoursToAdd);
                        $this->addMinutes($minutesToAdd);
                        return true;
                    } elseif ($this->getWeeks() > 0) {
                        $this->weekNumber -= 1;
                        $daysToAdd = 6;
                        $hoursToAdd = 23;
                        $minutesToAdd = 60 - $amount;
                        $this->addDays($daysToAdd);
                        $this->addHours($hoursToAdd);
                        $this->addMinutes($minutesToAdd);
                        return true;
                    }  elseif ($this->getYears() > 0) {
                        $this->year -= 1;
                        $weeksToAdd = 51;
                        $daysToAdd = 6;
                        $hoursToAdd = 23;
                        $minutesToAdd = 60 - $amount;
                        $this->addWeeks($weeksToAdd);
                        $this->addDays($daysToAdd);
                        $this->addHours($hoursToAdd);
                        $this->addMinutes($minutesToAdd);
                        return true;
                    }
                }
                break;
            case "h":
                if($this->getHours() >= $amount) {
                    $this->hour -= $amount;
                    return true;
                } else {
                    if ($this->getDays() > 0) {
                        $this->day -= 1;
                        $hoursToAdd = 24 - $amount;
                        $this->addHours($hoursToAdd);
                        return true;
                    } elseif ($this->getWeeks() > 0) {
                        $this->weekNumber -= 1;
                        $daysToAdd = 6;
                        $hoursToAdd = 24 - $amount;
                        $this->addDays($daysToAdd);
                        $this->addHours($hoursToAdd);
                        return true;
                    }  elseif ($this->getYears() > 0) {
                        $this->year -= 1;
                        $weeksToAdd = 51;
                        $daysToAdd = 6;
                        $hoursToAdd = 24 - $amount;
                        $this->addWeeks($weeksToAdd);
                        $this->addDays($daysToAdd);
                        $this->addHours($hoursToAdd);
                        return true;
                    }
                }
                break;
            case "d":
                if($this->getDays() >= $amount) {
                    $this->day -= $amount;
                    return true;
                } else {
                    if ($this->getWeeks() > 0) {
                        $this->weekNumber--;
                        $daysToAdd = 7 - $amount;
                        $this->addDays($daysToAdd);
                        return true;
                    } elseif ($this->getYears() > 0) {
                        $this->year--;
                        $weeksToAdd = 51;
                        $daysToAdd = 7 - $amount;
                        $this->addWeeks($weeksToAdd);
                        $this->addDays($daysToAdd);
                        return true;
                    }
                }
                break;
            case "w":
                if($this->getWeeks() >= $amount) {
                    $this->weekNumber -= $amount;
                    return true;
                } else {
                    if ($this->getYears() > 0) {
                        $weeksToAdd = 52 - $amount;
                        $this->addWeeks($weeksToAdd);
                        return true;
                    }
                }
                break;
            case "y":
                if($this->getYears() >= $amount) {
                    $this->year -= $amount;
                    return true;
                }
        }
        return false;
    }
    /**
     * @return string
     */
    public function __toString(): string {
        return sprintf('%04d:%02d:%d:%02d:%02d', $this->year, $this->weekNumber, $this->day, $this->hour, $this->minute);
    }
}
$factory = TimeFactory::createFromString("0000:00:0:00:00");
$factory->addMinutes(2);
$factory->addMinutes(4);
$factory->addMinutes(6);
$factory->addMinutes(8);
$factory->addMinutes(10);
$factory->addMinutes(12);

echo $factory;
echo "\n" . $factory->getMinutes();
echo "\n" . $factory->getHours();
echo "\n" . $factory->getDays();
echo "\n" . $factory->getWeeks();
echo "\n" . $factory->getYears();

任何帮助将不胜感激!

【问题讨论】:

  • 所以WW 部分应该是什么 - 周数?那么,为什么你首先要为此编写自己的类——而不是使用 PHP 的 DateTime?毕竟,显示日期的周数只是输出格式的问题。
  • @04FS 我之前用过 DateTime 类,但是不能显示零时间。
  • 是的,WW 是周数。
  • “但它不能显示零时间” - 究竟是什么意思?
  • @04FS PHP 的DateTime 类不能显示零时间,因为它遵循日历格式。不过,我的时间需要从零开始,而 DateTime 类不能这样做。

标签: php algorithm function math time


【解决方案1】:

不确定整个过程是否是实现您想要的最佳方法,但这是问题所在(我认为)。

仅以分钟代码为例...

public function addMinutes(int $addedMinutes): void {
    $newMinutes = $this->minute + $addedMinutes;
    if($newMinutes >= 60) {
        $hours = round($newMinutes / 60, 0, PHP_ROUND_HALF_DOWN);
        $this->addHours($hours);
    }
    $this->minute += $newMinutes % 60;
}

因此,首先将新分钟添加到现有时间...

$newMinutes = $this->minute + $addedMinutes;

处理小时翻转,然后再次添加新的分钟字段...

$this->minute += $newMinutes % 60;

这在每一层都重复。

所以我建议像

public function addMinutes(int $addedMinutes): void {
    $newMinutes = $this->minute + $addedMinutes;
    if($newMinutes >= 60) {
        $hours = floor($newMinutes / 60);
        $this->addHours($hours);
        $newMinutes -= ($hours * 60);
    }
    $this->minute = $newMinutes;
}

这做了类似的处理,但最后一部分只是分配新的分钟,而不是再次添加它们。

请注意,我还更改了计算下一级的方式 - 使用 floor() 而不是 round()

【讨论】:

  • 这行得通,但是当我尝试添加 400 分钟时,我会返回 0000:00:0:07:-20
  • 我已经更新了代码 - 将 $hours = floor($newMinutes / 60); 行更改为 floor() 是(恕我直言)正确的做法。
  • 太棒了,又成功了。非常感谢您的时间和帮助,这为我节省了很多挫败感。
猜你喜欢
  • 2021-10-28
  • 1970-01-01
  • 2022-12-03
  • 1970-01-01
  • 2016-06-25
  • 2021-06-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多