0

I have built a function to change a given Y-m-d date like this: 2016-07-02 to this format: July 2nd.

The code:

// Format the given Y-M-D date
function format_date($date) {
    // Parse the date
    list($year, $month, $day) = array_values(date_parse($date));

    // Give the appropriate subscript to the day number
    $last_char = substr($day, -1);
    $pre_last_char = (strlen($day) > 1) ? substr($day, -2, -1) : null;
    $subscript = ($last_char === "1") ? "st" :
                 ($last_char === "2") ? "nd" :
                 ($last_char === "3") ? "rd" : "th";
    $subscript = ($pre_last_char === "1") ? "th" : $subscript;
    $day .= $subscript;

    // Get the month's name based on its number
    $months = [
        "1" => "January",
        "2" => "February",
        "3" => "March",
        "4" => "April",
        "5" => "May",
        "6" => "June",
        "7" => "July",
        "8" => "August",
        "9" => "September",
        "10" => "October",
        "11" => "November",
        "12" => "December"
    ];
    $month = $months[$month];

    // Omit the year if it's this year and assemble the date
    return $date = ($year === date("Y")) ? "$month $day $year" : "$month $day";
}

The function works as expected, but there's a catch. The first conditional ternary operator for $subscript returns "rd" for every number that ends in 1 and 2.

Example:

echo format_date("2016-01-01"); // It will output January 1rd

How can I fix that?

Angel Politis
  • 10,955
  • 14
  • 48
  • 66
  • Use [`daysuf`](http://php.net/manual/en/datetime.formats.date.php) – Jeff Puckett Jul 02 '16 at 15:31
  • 1
    Possible duplicate of [PHP ternary operator not working as expected](http://stackoverflow.com/questions/14214427/php-ternary-operator-not-working-as-expected) – u_mulder Jul 02 '16 at 15:33
  • 1
    In case you just want to fix your code, [take a look](https://eval.in/599572). Check the one line version for better visuals on where I opened/closed ( and ). – FirstOne Jul 02 '16 at 15:43
  • Thanks @FirstOne. I checked out your fix. I am going to edit the question to help anyone that may stumble upon it in the future. – Angel Politis Jul 02 '16 at 15:49

3 Answers3

5

Documentation reads:

Note: It is recommended that you avoid "stacking" ternary expressions. PHP's behaviour when using more than one ternary operator within a single statement is non-obvious:

<?php
// on first glance, the following appears to output 'true'
echo (true?'true':false?'t':'f');

// however, the actual output of the above is 't'
// this is because ternary expressions are evaluated from left to right

// the following is a more obvious version of the same code as above
echo ((true ? 'true' : false) ? 't' : 'f');

// here, you can see that the first expression is evaluated to 'true', which
// in turn evaluates to (bool)true, thus returning the true branch of the
// second ternary expression.
?>
Alex Blex
  • 34,704
  • 7
  • 48
  • 75
  • Alex, thanks for the detail you've gone into in your answer. It seems I've fallen once again in the same trap by not parenthesizing correctly. I tried your suggestion and it worked greatly! – Angel Politis Jul 02 '16 at 15:46
3

This is because PHP got the ternary operator wrong - it is left-associative instead of the right-associative of C, Java and so forth. Thus when converting C code to PHP you must parenthesize the "true" and "false" expressions.

Community
  • 1
  • 1
2

Not a direct answer to your question, but if you only need English like in your example, you can use php's standard date functions:

echo date('F jS', strtotime('2016-01-01'));

Output:

January 1st

See a working example here.

jeroen
  • 91,079
  • 21
  • 114
  • 132