Определение периодов времени по текущей дате

    Как-то недавно появилась задача сделать выборки из БД по разным периодам времени в зависимости от текущей даты. Для этих целей я реализовал класс с некоторым набором функций, определяющих концевые участки необходимых временных отрезков.

    На мой взгляд такие задачи возникают довольно часто и иметь один инструмент, который можно впоследствии дополнять новыми функциями, соответствующими различным врменным интервалам, очень удобно. Конечно в этом нет ничего сложного, но думаю это поможет кому-то сэкономить время на этой рутинной работе. Кроме того в нете ничего готового я просто не нашёл.
    /**
    * Class for making different periods of date without time.
    *
    * @author Anton Vasilyev <anton.vasilyev@gtmdevelopments.com>
    */
    class DatePeriod
    {
      /**
       * Unix timestamp for date without time.
       *
       * @var int
       */
      private $_timestamp;
      
      /**
       * Year.
       *
       * @var int
       */
      private $_year;
      
      /**
       * Month.
       *
       * @var int
       */
      private $_month;
      
      /**
       * Day.
       *
       * @var int
       */
      private $_day;
      
      /**
       * Number of seconds for one day.
       */
      const DAY_SECONDS = 86400;
      
      /**
       * Constructor.
       *
       * @param string $date   String containing a US English date format (used in function strtotime).
       * @author Anton Vasilyev <anton.vasilyev@gtmdevelopments.com>
       */
      public function __construct($date = null)
      {
        // Using today
        
        if ($date == null) {
          $this->_timestamp = strtotime(date('Y-m-d'));
        } else {
          $this->_timestamp = strtotime($date); 
        }
        
        $this->_day  = date('j', $this->_timestamp);
        $this->_month = date('n', $this->_timestamp);
        $this->_year = date('Y', $this->_timestamp);
      }
      
      /**
       * Calculates start and end date of week.
       * Returns array with two values: from date and to date.
       *
       * @param string $format  Format of the date (used in function date).
       * @return array      Array with two keys: from and to. Example:
       *             array(
       *               'from' => ...
       *               'to'  => ...
       *             )
       * @author Anton Vasilyev <anton.vasilyev@gtmdevelopments.com>
       */
      public function getWeek($format)
      {
        $dayOfWeek = date('w', $this->_timestamp);

        return array(
          'from' => date($format, $this->_timestamp - $dayOfWeek*self::DAY_SECONDS),
          'to'  => date($format, $this->_timestamp + (6 - $dayOfWeek)*self::DAY_SECONDS)
        );
      }
      
      /**
       * Calculates start and end date of month.
       * Return array with two values: from date and to date.
       *
       * @param string $format  Format of the date (used in function date).
       * @return array      Array with two keys: from and to. Example:
       *             array(
       *               'from' => ...
       *               'to'  => ...
       *             )
       * @author Anton Vasilyev <anton.vasilyev@gtmdevelopments.com>
       */
      public function getMonth($format)
      {
        $monthDays = date('t', $this->_timestamp);

        return array(
          'from' => date($format, strtotime($this->_year . '-' . $this->_month . '-01')),
          'to'  => date($format, strtotime($this->_year . '-' . $this->_month . '-' . $monthDays))
        );
      }
      
      /**
       * Calculates start and end date of current quarter.
       * Return array with two values: from date and to date.
       *
       * @param string $format  Format of the date (used in function date).
       * @return array      Array with two keys: from and to. Example:
       *             array(
       *               'from' => ...
       *               'to'  => ...
       *             )
       * @author Anton Vasilyev <anton.vasilyev@gtmdevelopments.com>
       */
      public function getCurrentQuarter($format)
      {
        $quarter  = (int)($this->_month/4) + 1;

        $fromMonth = ($quarter - 1)*3 + 1;
        $toMonth  = $quarter*3;
        
        // Number of days in last quarter month.
        
        $daysInToMonth = date('t', strtotime($this->_year . '-' . $toMonth . '-01'));
        
        return array(
          'from' => date($format, strtotime($this->_year . '-' . $fromMonth . '-01')),
          'to'  => date($format, strtotime($this->_year . '-' . $toMonth . '-' . $daysInToMonth))
        );
      }
      
      /**
       * Calculates start and end date of previous quarter.
       * Return array with two values: from date and to date.
       *
       * @param string $format  Format of the date (used in function date).
       * @return array      Array with two keys: from and to. Example:
       *             array(
       *               'from' => ...
       *               'to'  => ...
       *             )
       * @author Anton Vasilyev <anton.vasilyev@gtmdevelopments.com>
       */
      public function getPrevQuarter($format)
      {
        $quarter = (int)($this->_month/4) + 1;

        if ($quarter == 1) {
          $quarter = 4;
          $year  = $this->_year - 1;
        } else {
          $quarter -= 1;
          $year   = $this->_year;
        }
        
        
        $fromMonth = ($quarter - 1)*3 + 1;
        $toMonth  = $quarter*3;
        
        // Number of days in last quarter month.
        
        $daysInToMonth = date('t', strtotime($year . '-' . $toMonth . '-01'));
        
        return array(
          'from' => date($format, strtotime($year . '-' . $fromMonth . '-01')),
          'to'  => date($format, strtotime($year . '-' . $toMonth . '-' . $daysInToMonth))
        );
      }
      
      /**
       * Calculates start and end date of current calendar year to date.
       * Return array with two values: from date and to date.
       *
       * @param string $format  Format of the date (used in function date).
       * @return array      Array with two keys: from and to. Example:
       *             array(
       *               'from' => ...
       *               'to'  => ...
       *             )
       * @author Anton Vasilyev <anton.vasilyev@gtmdevelopments.com>
       */
      public function getYearToDate($format)
      {
        return array(
          'from' => date($format, strtotime($this->_year . '-01-01')),
          'to'  => date($format, $this->_timestamp)
        );
      }
      
      /**
       * Calculates start and end date of the last calendar year.
       * Return array with two values: from date and to date.
       *
       * @param string $format  Format of the date (used in function date).
       * @return array      Array with two keys: from and to. Example:
       *             array(
       *               'from' => ...
       *               'to'  => ...
       *             )
       * @author Anton Vasilyev <anton.vasilyev@gtmdevelopments.com>
       */
      public function getLastYear($format)
      {
        return array(
          'from' => date($format, strtotime($this->_year - 1 . '-01-01')),
          'to'  => date($format, strtotime($this->_year - 1 . '-12-31'))
        );
      }
      
      /**
       * Calculates start and end date of last calendar year to date.
       * Return array with two values: from date and to date.
       *
       * @param string $format  Format of the date (used in function date).
       * @return array      Array with two keys: from and to. Example:
       *             array(
       *               'from' => ...
       *               'to'  => ...
       *             )
       * @author Anton Vasilyev <anton.vasilyev@gtmdevelopments.com>
       */
      public function getTwelveMonths($format)
      {
        $fromMonth = (12 + ($this->_month - 11))%12 == 0 ? 1 : (12 + ($this->_month - 11))%12;
        
        if ($fromMonth > 1) {
          $year = $this->_year - 1;
        } else {
          $year = $this->_year;
        }
        
        // Number of days in last quarter month.
        
        $daysInToMonth = date('t', strtotime($this->_year . '-' . $this->_month . '-01'));
        
        return array(
          'from' => date($format, strtotime($year . '-' . $fromMonth . '-01')),
          'to'  => date($format, $this->_timestamp)
        );
      }
    }


    * This source code was highlighted with Source Code Highlighter.
    Share post

    Similar posts

    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 19

      0
      Отлично документированный и оформленный код.
        0
        Спасибо. Критика кода — это была одна из целей зачем я выкладывал один из своих классов. Примером для меня всегда служил Zend Framework.
          0
          Не совсем понятен стиль. Вы то используете сокращенную форму записи условий, то не используете.

          public function getTwelveMonths($format)
          {
          $fromMonth = (12 + ($this->_month — 11))%12 == 0? 1: (12 + ($this->_month — 11))%12;
          if ($fromMonth > 1) {
          $year = $this->_year — 1;
          } else {
          $year = $this->_year;
          }
            0
            Честно говоря не могу дать адекватного ответа почему так. Думаю, что во втором случае будет лучше также применить сокращённую запись, т.к. это условие используется только для определения значения переменной, как и в первом случае.
            0
            Раз зенд, тогда бы и расширяли бы Zend_Date.

            А то в конструкторе немного индусы потоптались:
            $this->_timestamp = strtotime(date('Y-m-d'));

            вместо человеческого

            $this->_timestamp = time();

            Плюс не решен вопрос с зонами/gmt и daylight savings
              0
              Zend_Date не стал расширять, т.к. не было опыта работы с данным классом, а проблему надо было решить максимально быстро.

              >> $this->_timestamp = strtotime(date('Y-m-d'));
              Это было сделано для того, чтобы отсечь время и оставить только дату.
          +1
          Симпатично конечно. Однако для большенства задач хватает strtotime с нужной строчкой.
          echo strtotime("+1 day"), "\n";
          echo strtotime("+1 week"), "\n";
          echo strtotime("+1 week 2 days 4 hours 2 seconds"), "\n";
          echo strtotime(«next Thursday»), "\n";
          echo strtotime(«last Monday»), "\n";
          и т.п. (украдено из мануала)
            +1
            Угу. А если как в постановке, выборки из БД, то, ссотвественно,
            NOW() + INTERVAL 1 DAY
            NOW() — INTERVAL 1 MONTH
            и т.п.
              0
              А как быть при выборке по кварталам?
              • UFO just landed and posted this here
                • UFO just landed and posted this here
                    –1
                    Вы ничего не путаете. Я догадывался, что можно это реализовать только средствами SQL. Но не нашёл тогда функции. Спасибо, буду знать, что они всё таки есть.
                    • UFO just landed and posted this here
                        –1
                        =)) А я-то думал — где же они описаны!
                        • UFO just landed and posted this here
                            –1
                            На самом деле я всё понимаю. Вы не поверите я просмотрел мануал первым делом, но как-то не заметил стандартных… наверное я был не в духе тогда…
                    0
                    Часто при разработке с использованием абрстракций на уровне БД и выше (различные фреймворки, CMS, библиотеки классов/функций и т. п.) использование SQL напрямую затруднено. Потом уже, на стадии оптимизации, можно определять текущую БД и для тех из них, которые поддерживают специфические функции/синтаксис писать их нативные выражения (если это обещает дать выигрыш по оптимизируемому параметру), а для тех, которые не поддерживают (частный «кандидат» SQLite) оставлять обработку на уровне PHP.

                    Можно и наоборот, конечно, сначала «завязаться» на конкретную БД, тот же MySQL 5, а потом реализовывать независимость от реализации БД, но, по личному опыту, обычно приходится много изменений вносить в PHP-код, если слишком сильно «интегрировать» приложение и БД
                –1
                Спасибо. Не знал, что возможно такое использование данной функции.
                0
                const DAY_SECONDS = 86400;

                бывает другое кол-во секунд?

                Only users with full accounts can post comments. Log in, please.