Home » Php » php – strftime doesn't show PM or AM

php – strftime doesn't show PM or AM

Posted by: admin July 12, 2020 Leave a comment


This is the code I use to get the date (in spanish):

$fecha = strftime("%d de %B, %Y, a las %l:%M %p");

and I get:

27 de julio, 2011, a las 7:10

So the question is, where is my PM (or AM)?

My application is running on Linux.

How to&Answers:

Well,, the php manual says

Not all conversion specifiers may be supported by your C library, in which case they will not be supported by PHP’s strftime(). Additionally, not all platforms support negative timestamps, so your date

This could be your problem. In that case you could do something like this to get the AM/PM:

$time = time();
$fecha = strftime("%d de %B, %Y, a las %l:%M ", $time).(($time%86400) < 43200 ? 'AM' : 'PM');


This answer is assuming you want a UTC time string (if you want another timezone, you should also include the timezone in the string if you are storing it or sending it anywhere), and that your php.ini has date.timezone set to UTC . If you are not using UTC, you should compute an offset. See @Soylent17’s answer.


The question is old, but in case someone else needs it, it also happened to me.

It seems that the spanish locale has not implementation for %p, so make sure that your line is before the line setting the locale to spanish. Probably you will need to fraction your code like this.

 $hora = strftime(" a las %l:%M %p");
 $loc_sp = setlocale (LC_TIME,'es_ES');
 $fecha = strftime("%d de %B, %Y");
 echo $fecha.$hora;


I don’t have enough rep to add a comment to PaulPro’s answer, so I’ll just have to expand on it. When working with the timestamp directly, you will need to adjust for your timezone offset. So where PaulPro put $time%86400, you need something like ($time+date('Z'))%86400

$time = time();
$fecha = strftime("%d de %B, %Y, a las %l:%M ", $time).(($time+date('Z'))%86400 < 43200 ? 'AM' : 'PM');


Are you on OSX? If so %p or %P isn’t supported


you can try using another value on setlocale(), because es_MX dont work for me but es_CO do the job, it has support for %p and %P, it depends on the server configuration :v

possible values list


Thanks to @iyepes, I resolved to completely bypass the Locale if you have the site in multiple languages, %P or %p are both worthless in locales other than those in English I suppose, at least that’s the case for Spanish

Separate %P or %p from the locale, if you have a while loop, set locale to en_US, extract times in en_US strftime including %P then set back to locale defined by user.

$day1 =  strtotime($row["day1"]);
$day2 = strtotime($row["day2"]);
$day3 = strtotime($row["day3"]);

  setlocale(LC_ALL, "en_US");

$time1 = strftime("%l:%M %P", $day1);
$time2 = strftime("%l:%M %P", $day2);
$time3 = strftime("%l:%M %P", $day3);

  setlocale(LC_ALL, $defined_locale);

$day1 - strftime("%d de %B, %Y, " $day1).$time1;
$day2 - strftime("%d de %B, %Y, " $day2).$time2;


my solution

function mystrftime($format, $time=null){
    if(!$time) $time = time();
    preg_match_all('/%[a-zA-Z]/', $format, $placeholders);
    foreach ($placeholders[0] as $placeholder){
        if(strftime($placeholder, $time)==''){
            $format = str_replace($placeholder, '%'.$placeholder, $format);
    $format = strftime($format, $time);
    preg_match_all('/%[a-zA-Z]/', $format, $placeholders);
    $locale = setlocale('LC_TIME', '0');
    setlocale('LC_TIME', 'en_US.UTF8');
    foreach ($placeholders[0] as $placeholder){
        $format = str_replace($placeholder, strftime($placeholder, $time), $format);
    setlocale('LC_TIME', $locale);
    return $format;


simple and ugly

$date="2016-11-15 12:34";    
$fecha=strftime("%A, %d de %B de %Y %l:%M", strtotime("$date")).date(' a', strtotime("$date"));

results in: martes, 15 de noviembre de 2016 12:34 pm


Make sure the locale is spelled the right way. For me, en_US.utf8 worked fine, en_US did not work at all.
Try to check installed locales on unix machines by calling

locale -a 

on the command prompt.


I was looking for an answer to my question here when I figured out how to solve it.

This was my default setting for language.

// Set Default Timezone
// Set Date Language -> Unix
setlocale(LC_TIME, 'es_ES.UTF-8');
// Set Date Language -> Windows
setlocale(LC_TIME, 'spanish');

Then, I was trying to display the current date with AM and PM but it wasn’t working.

echo strftime("%d de %b de %Y, %H:%M %p", strtotime($sqlDate);

This was showing an empty field because of the %p parameter. When I read AgelessEssence’s comment I started to switch between these options:

  • es_MX ~ México
  • es_ES ~ España
  • es_RA ~ Argentina
  • es_CO ~ Colombia

None of them were working, while I was thinking I left this field empty and saved.

 // Set Date Language -> Windows
    setlocale(LC_TIME, '');

Then, it worked like a charm.


        $formato = "%A, %e de %B de %Y, %I:%M:%S %p";
        // Comprobación para Windows para hallar y remplazar el
        // modificador %e adecuadamente
        if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') {
            $formato = preg_replace('#(?<!%)((?:%%)*)%e#', '%#d', $formato);
        $formato = preg_replace('#(?<!%)((?:%%)*)%p#', '#p', $formato);
        $x = @strftime($formato);
        $y = date('A');
        $x = str_replace('#p', $y, $x);