【问题标题】:PHP DateTime credit card expirationPHP DateTime 信用卡过期
【发布时间】:2013-10-30 01:42:03
【问题描述】:

我正在尝试使用 DateTime 来检查信用卡到期日是否已过期,但我有点迷茫。

我只想比较 mm/yy 日期。

这是我目前的代码

$expmonth = $_POST['expMonth']; //e.g 08
$expyear = $_POST['expYear']; //e.g 15

$rawExpiry = $expmonth . $expyear;

$expiryDateTime = \DateTime::createFromFormat('my', $rawExpiry);
$expiryDate = $expiryDateTime->format('m y');

$currentDateTime = new \DateTime();
$currentDate = $currentDateTime->format('m y');

if ($expiryDate < $currentDate) {
    echo 'Expired';
} else {
    echo 'Valid';
}

我觉得我快到了,但 if 语句产生了不正确的结果。任何帮助将不胜感激。

【问题讨论】:

    标签: php date validation datetime credit-card


    【解决方案1】:

    它比你想象的要简单。您使用的日期格式并不重要,因为 PHP 会在内部进行比较。

    $expires = \DateTime::createFromFormat('my', $_POST['expMonth'].$_POST['expYear']);
    $now     = new \DateTime();
    
    if ($expires < $now) {
        // expired
    }
    

    【讨论】:

    • 当日期是当前月份时,这甚至可以工作!
    • 有点让我失望,请确保您的到期日期只有 2 位数。如果是 4 位数字(例如:2017 而不是 17),那么您需要使用:$expires = \DateTime::createFromFormat('mY', $_POST['expMonth'].$_POST['expYear']);(大写字母 Y,而不是小写)
    • 这是一个很好的答案,但没有考虑到信用卡/借记卡的实际到期日期。如果未指定,DateTime::createFromFormat 将使用当月的今天(例如 17)。这意味着信用卡在还剩几天时可能会出现过期。如果卡在 06/20(即 2020 年 6 月)到期,那么它实际上会在 2020 年 7 月 1 日 00:00:00 停止工作。修改方法可以解决此问题。
    • 我已经在下面发布了完整的答案。
    • 如果到期月份是个位数,这将不起作用......加上@featherbelly指出的问题。
    【解决方案2】:

    您可以使用DateTime class 使用DateTime::createFromFormat() 构造函数生成与给定日期字符串格式匹配的DateTime 对象。

    格式 ('my') 将匹配任何带有字符串模式 'mmyy' 的日期字符串,例如'0620'。或者对于具有 4 位数年份的日期,使用格式“mY”,它将匹配具有以下字符串模式“mmyyyy”的日期,例如'062020'。使用DateTimeZone 类指定时区也是明智之举。

    $expiryMonth = 06;
    $expiryYear = 20;
    $timezone = new DateTimeZone('Europe/London');
    $expiryTime = \DateTime::createFromFormat('my', $expiryMonth.$expiryYear, $timezone);
    

    查看DateTime::createFromFormat 页面了解更多格式。

    但是 - 对于信用卡/借记卡的到期日期,您还需要考虑完整的到期日期和时间 - 而不仅仅是月份和年份。

    DateTime::createFromFormat 如果未指定,默认使用当月的今天(例如 17)。这意味着信用卡在还剩几天时可能会出现过期。如果一张卡在 06/20(即 2020 年 6 月)到期,那么它实际上会在 2020 年 7 月 1 日 00:00:00 停止工作。modify 方法解决了这个问题。例如

    $expiryTime = \DateTime::createFromFormat('my', $expiryMonth.$expiryYear, $timezone)->modify('+1 month first day of midnight');
    

    字符串'+1 month first day of midnight' 做了三件事。

    • '+1 个月' - 添加一个月。
    • 'first day of' - 切换到当月的第一天
    • 'midnight' - 将时间更改为 00:00:00

    modify 方法对许多日期操作非常有用!

    所以要回答这个问题,这就是您所需要的——稍微调整格式以适应个位数月份:

    $expiryMonth = 6;
    $expiryYear = 20;
    $timezone = new DateTimeZone('Europe/London');
    $expiryTime = \DateTime::createFromFormat(
      'm-y',
       $expiryMonth.'-'.$expiryYear,
       $timezone
    )->modify('+1 month first day of midnight');
    
    $currentTime = new \DateTime('now', $timezone);
    
    if ($expiryTime < $currentTime) {
        // Card has expired.
    }
    

    【讨论】:

    • 如果月份是个位数,这将不起作用。一个简单的解决方法是使用“m-y”(如果年份是四位数,则使用“m-Y”。)
    • 信用卡/借记卡上的月份永远不是个位数——10 岁以下的数字以零开头,例如06.
    • 永远不要说“从不”。它们是写在信用卡上的两位数,是的;但你不能确定数据是什么。例如,Stripe API 在 4 月的到期月份返回 int(4) - 实际上是个位数。
    【解决方案3】:

    对上述答案的补充。 请注意,默认情况下,天数也将在计算中。 例如今天是2019-10-31,如果你运行这个:

    \DateTime::createFromFormat('Ym', '202111');
    

    它将输出 2021-12-01,因为 11 月不存在第 31 天,它会为您的 DateTime 对象增加 1 天,并产生副作用,即您将在 12 月而不是预期的 11 月。

    我的建议是始终在您的代码中使用日期。

    【讨论】:

      【解决方案4】:

      关于操作的问题:

      $y=15;
      $m=05;
      
      if(strtotime( substr(date('Y'), 0, 2)."{$y}-{$m}" ) < strtotime( date("Y-m")  ))
      {
        echo 'card is expired';
      }
      

      对于其他全年:

      $y=2015;
      $m=5;
      
      if(strtotime("{$y}-{$m}") < strtotime( date("Y-m")  ))
      {
        echo 'card is expired';
      }
      

      【讨论】:

        【解决方案5】:

        best answer 由上面的 John Conde 提供。它只做最少的处理:创建两个正确的DateTime 对象,比较它们,这就是它所需要的。

        它也可以在您开始时工作,但您必须以将年份放在首位的方式格式化日期。

        想一想:作为日期,08/15(2015 年 8 月)在 12/14(2014 年 12 月)之后,但作为字符串,'08 15''12 14' 之前。

        当年份在前面时,即使是字符串,也先比较年份,然后仅当年份相等时才比较月份:

        $expiryDate  = $expiryDateTime->format('y m');
        $currentDate = $currentDateTime->format('y m');
        
        if ($expiryDate < $currentDate) {
            echo 'Expired';
        } else {
            echo 'Valid';
        }
        

        【讨论】:

          【解决方案6】:

          将字符串“201709”与当前的年月进行比较不是更简单吗?我想创建日期时间对象会花费 php 一些精力。

          if($_POST['expYear']. str_pad($_POST['expMonth'],2,'0') < date('Ym')) {
             echo 'expired';
          
          }
          

          【讨论】:

          • 你必须使用 STR_PAD_LEFT 作为str_pad 的第四个参数,否则你会得到10 而不是01
          【解决方案7】:

          保持简单,就像我上面的答案所说的那样,除了你需要把 pad 放在左边:

          isCardExpired($month, $year)
          {
              $expires = $year.str_pad($month, 2, '0', STR_PAD_LEFT);
              $now = date('Ym');
          
              return $expires < $now;
          }
          

          无需使用DateTime添加额外的 PHP 负载

          【讨论】:

          • 处理日期时,最好使用专门为此目的设计的 DateTime。开销可以忽略不计。
          • 我同意我在日期方面做了很多工作,但我发现这更像是一个整数比较,我喜欢它的简单性。
          猜你喜欢
          • 2019-05-09
          • 1970-01-01
          • 2011-03-14
          • 2012-01-14
          • 2011-07-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-01-14
          相关资源
          最近更新 更多