【问题标题】:PHP DateTime() class, change first day of the week to MondayPHP DateTime() 类,将一周的第一天改为星期一
【发布时间】:2012-10-29 20:08:37
【问题描述】:

只要您所在国家/地区一周的第一天是星期日,PHP (5.3+) 中的 DateTime 类就可以正常工作。在荷兰,一周的第一天是星期一,这使得课程无法用于构建具有周视图和计算的日历。

我似乎无法在 Stackoverflow 或 Internet 的其他地方找到关于如何让 DateTime 表现得好像一周的第一天是星期一的答案。

我在 Stackoverflow 上找到了这篇文章,但它并不能解决您遇到麻烦的所有方式,而且它不是一个优雅的解决方案。

$dateTime = new DateTime('2012-05-14');
$monday = clone $dateTime->modify(('Sunday' == $dateTime->format('l')) ? 'Monday last week' : 'Monday this week');

有没有办法改变这个或范围的日期时间?无法想象这不是一个环境,因为欧洲大部分地区都是从星期一开始的。

添加: 发布完整的日历和功能代码不会让事情变得更清楚。但这里以一行为例。 我经常需要检查一周的第一天是什么,或者计算从一周的第一天到该周的不同日期和时间。我的代码充满了这些:

$startOfWeek = $date->modify(('Sunday' == $date->format('l')) ? 'Monday last week' : 'Monday this week')->modify('+3 hours')->format(DATETIME);

我在尝试获取月份或年份的第一个完整周时也得到了不想要的结果。由于我的 $date 对象并不总是包含相同的日期,因此我必须以这种方式继续检查它,从而使代码难以阅读。在这个日历上还有很多编程要做,我无法预见它会再次出现错误。

编辑虽然有一些不一致之处。出于某种奇怪的原因,DateTime 确实得到了下一个正确的:

$test = new DateTime('2012-10-29'); // Monday
echo $test->modify('Sunday this week')->format('Y-m-d');  // 2012-11-04

// But...

$test = new DateTime('2012-11-04'); // Sunday
echo $test->modify('Monday this week')->format('Y-m-d');  // 2012-11-05 instead of 2012-10-29   

但我想我可以让问题更清楚: 可以将 DateTime() 类与星期一一起用作一周的第一天吗?如果没有,是否可以延长课程以使用星期一作为一周的第一天。

更新: 好的,我想我到了某个地方......我不是编码课程的专业人士......但这似乎可以持续数周。但它仍然需要第一天、第二天的规则......以及星期天本身的日期名称。我不认为这是万无一失的。如有任何帮助,我将不胜感激。

class EuroDateTime extends DateTime {

// Fields
private $weekModifiers = array (
    'this week',
    'next week',
    'previous week',
    'last week'
);

// Override "modify()"
public function modify($string) {

    // Search pattern
    $pattern = '/'.implode('|', $this->weekModifiers).'/';

    // Change the modifier string if needed
    if ( $this->format('N') == 7 ) { // It's Sunday
        $matches = array();
        if ( preg_match( $pattern, $string, $matches )) {
            $string = str_replace($matches[0], '-7 days '.$matches[0], $string);
        }
    }
    return parent::modify($string);

}

}
// This works
$test = new EuroDateTime('2012-11-04');
echo $test->modify('Monday this week')->format('Y-m-d');
// And I can still concatenate calls like the DateTime class was intended
echo $test->modify('Monday this week')->modify('+3 days')->format('Y-m-d');

【问题讨论】:

  • 您到底面临什么问题?
  • 听起来像是 XY 问题。星期日被映射到 0 的事实不应该阻止您使用不同的技术来确定星期的开始,就像其他任何一天一样。
  • 你的问题很抽象。提供用于创建日历的代码。至于你的问题目前没有答案
  • 我看不出问题; echo $dateTime->format( 'N' ); 将为您提供从 17"ISO-8601 numeric representation of the day of the week"(从星期一开始)。只需减去 1 即可获得零索引表示。

标签: php class datetime


【解决方案1】:

也可以通过setISODate获取一周的开始和结束,最后一个参数是一周的ISO-daynumber,周一是1,周日是7

$firstday = new \DateTime();
$lastday = clone($firstday);
$firstday->setISODate($firstday->format("Y"),$firstday->format("W"),1);
$lastday->setISODate($firstday->format("Y"),$firstday->format("W"),7);

【讨论】:

    【解决方案2】:

    我发现这可行,但 PHP 的 DateTime 类中存在一些不一致。

    如果出发日期是星期日,则前一个星期一不被视为同一周(由此类固定)。但是从星期一出发,下个星期日被认为是同一周。如果他们将来解决这个问题,这个类将需要一些补充。

    class EuroDateTime extends DateTime {
    
    // Override "modify()"
    public function modify($string) {
    
        // Change the modifier string if needed
        if ( $this->format('N') == 7 ) { // It's Sunday and we're calculating a day using relative weeks
            $matches = array();
            $pattern = '/this week|next week|previous week|last week/i';
            if ( preg_match( $pattern, $string, $matches )) {
                $string = str_replace($matches[0], '-7 days '.$matches[0], $string);
            }
        }
        return parent::modify($string);
    
    }
    
    }
    

    【讨论】:

      【解决方案3】:

      没有什么可以阻止您手动修改日期以获得一周的“第一”天,具体取决于您对“第一”的定义。例如:

      $firstDayOfWeek = 1; // Monday
      $dateTime = new DateTime('2012-05-16'); // Wednesday
      
      // calculate how many days to remove to get back to the "first" day
      $difference = ($firstDayOfWeek - $dateTime->format('N'));
      if ($difference > 0) { $difference -= 7; }
      $dateTime->modify("$difference days");
      
      var_dump($dateTime->format('r')); // "Mon, 14 May 2012 00:00:00 +0000"
      

      注意输出如何随着您的变化而变化$firstDayOfWeek;如果将其更改为上面(星期四)的4,那么它会将Thu, 10 May 2012 视为“第一”天。

      编辑:这是一个相当基本的示例。执行此操作的正确方法是使用用户/系统的语言环境为您提供“第一”天,然后从那里计算。请参阅this question 了解更多信息。

      【讨论】:

      • 感谢 cbuckley,这是否意味着 DateTime 类本身不能设置为原生使用星期一作为第一个工作日?
      • 对于任何更聪明的事情,正确的做法是使用语言环境。我已经为此添加了更新。
      • cbuckly,我认为语言环境更新没有通过。我现在正在尝试根据您的示例编写一个课程,该课程将拦截“下周”、“本周”、“上周”之类的任何内容并进行更改。不知道我是否只是在浪费时间..
      【解决方案4】:

      我也对问题出在哪里感到困惑,因为DateTime 确实有一个从星期一开始的星期的概念:N format 为您提供从星期一到星期几的日期星期天,星期一是 1,星期日是 7。此外,W 格式是获取周数的唯一方法,也从星期一开始一周。 (我似乎记得荷兰的周数与 ISO 周数不完全一样,但那是另一回事)。那么你到底缺少什么功能呢?

      编辑所以问题是(仅?)relative datetime formats,例如“本周星期一”在参考日期是星期日时给出错误的结果。从文档中听起来DateTime 只是遵循strtotime,它应该是依赖于语言环境的。所以如果你正确设置了你的语言环境并且这不起作用,这听起来像是一个错误(对于它的价值)。

      【讨论】:

      • 试试这个:$test = new DateTime('2012-11-04'); echo $test->modify('本周星期一')->format('Y-m-d'); // 2012-11-05 // 我希望得到 2012-10-29
      • 我明白了;因此,相对偏移量的英文规范不会出现在星期一优先的变体中。
      • 正是....对于所有认为星期一是一周的第一天的国家来说都是糟糕的。我刚刚发现 PHP DateTime 扩展是由一个荷兰人编写的......#WayToGoDerickRethans
      【解决方案5】:

      正确答案:

      $week_start_day; // 0 - Sunday, 1 - Monday
      
      $date_time_from = new DateTime('now');
      $date_time_to = clone $date_time_from;
      
      $this_week_first_day = $date_time_from->setISODate($date_time_from->format("Y"), $date_time_from->format("W"), $week_start_day);
      $this_week_last_day = $date_time_to->setISODate($date_time_to->format("Y"), $date_time_to->format("W"), (6 + $week_start_day));
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-01-18
        • 2015-12-11
        • 1970-01-01
        • 2019-08-30
        • 2013-06-05
        • 1970-01-01
        相关资源
        最近更新 更多