13

On my Windows development machine, I have set the locale to ita:

setlocale(LC_TIME, 'ita');
echo strftime('%b'); // dic

While (I suppose, can't test right now) on a *nix system, I should use it:

setlocale(LC_TIME, 'it');

If I try to set it on my Windows it doesn't work, printing Dec.

It seems I can't rely on setlocale(), so I should use IntlDateFormatter as suggested by @hakre. However, I can find the constant that gives me the month name and the short one:

IntlDateFormatter::NONE (integer)
Do not include this element

IntlDateFormatter::FULL (integer)
Completely specified style (Tuesday, April 12, 1952 AD or 3:30:42pm PST)

IntlDateFormatter::LONG (integer)
Long style (January 12, 1952 or 3:30:32pm)

IntlDateFormatter::MEDIUM (integer)
Medium style (Jan 12, 1952)

IntlDateFormatter::SHORT (integer)
Most abbreviated style, only essential data (12/13/52 or 3:30pm)
gremo
  • 47,186
  • 75
  • 257
  • 421
  • We already had this today. Please use the search. – hakre Dec 21 '12 at 14:59
  • 1
    @hakre sorry, can't find. If you point me to the right question I'll delete this... – gremo Dec 21 '12 at 15:04
  • 1
    @hakre I forgot to say that i need only month names and abbreviated ones, not a full date format. Can't find this options in IntlDateFormatter. – gremo Dec 21 '12 at 15:17

2 Answers2

33

From the reference, some month formatting codes:

Symbol     Meaning             Example:            

M          month in year       M or MM    09       
                               MMM        Sept     
                               MMMM       September
                               MMMMM      S        

The PHP function to set the format is: IntlDateFormatter::setPattern, some examples:

class LocaleDateFormat
{
    private $locale;
    private $pattern;

    public function __construct($pattern, $locale = 'en_US') {
        $this->setLocale($locale);
        $this->setPattern($pattern);
    }

    public function setLocale($locale) {
        $this->locale = $locale;
    }

    public function setPattern($pattern) {
        $this->pattern = $pattern;
    }

    public function localeFormat($locale, $date) {
        $this->setLocale($locale);
        return $this->format($date);
    }

    public function format($date) {
        $formatter = new IntlDateFormatter($this->locale, IntlDateFormatter::FULL, IntlDateFormatter::FULL);
        $formatter->setPattern($this->pattern);
        return $formatter->format($date);
    }
}

$dateFormat = new LocaleDateFormat('MMMM'); # Long Month Names

$date = new DateTime(); # Now

$locales = ["en_US", "de_DE", "sv_SE", "ru_RU"];
foreach ($locales as $i => $locale) {
    $month = $dateFormat->localeFormat($locale, $date);
    printf("%d. %s - %s\n", $i+1, $locale, $month);
}

Output:

1. en_US - December
2. de_DE - Dezember
3. sv_SE - december
4. ru_RU - декабря

For a list of locales see here:


The actual example for the short monthnames across different locales:

$locales    = ["en_US", "de_DE", "sv_SE", "ru_RU", 'it', 'it_IT', 'it_CH'];
$dateFormat = new LocaleDateFormat('MMM'); # Short Month Names

$date = new DateTime(); # Now

foreach (range(1, 12) as $monthNumber)
{
    $date->setDate(2012, $monthNumber, 1);

    printf("%02d:    ", $monthNumber);

    foreach ($locales as $locale)
    {
        $monthLabel = $dateFormat->localeFormat($locale, $date);
        $pad = str_repeat(' ', max(0, 8 - mb_strlen($monthLabel, 'UTF-8')));
        printf("%s: %s%s  ", $locale, $monthLabel, $pad);
    }

    echo "\n";
}

Exemplary output:

01:    en_US: Jan       de_DE: Jan       sv_SE: jan       ru_RU: янв.      it: gen       it_IT: gen       it_CH: gen       
02:    en_US: Feb       de_DE: Feb       sv_SE: feb       ru_RU: февр.     it: feb       it_IT: feb       it_CH: feb       
03:    en_US: Mar       de_DE: Mär       sv_SE: mar       ru_RU: марта     it: mar       it_IT: mar       it_CH: mar       
04:    en_US: Apr       de_DE: Apr       sv_SE: apr       ru_RU: апр.      it: apr       it_IT: apr       it_CH: apr       
05:    en_US: May       de_DE: Mai       sv_SE: maj       ru_RU: мая       it: mag       it_IT: mag       it_CH: mag       
06:    en_US: Jun       de_DE: Jun       sv_SE: jun       ru_RU: июня      it: giu       it_IT: giu       it_CH: giu       
07:    en_US: Jul       de_DE: Jul       sv_SE: jul       ru_RU: июля      it: lug       it_IT: lug       it_CH: lug       
08:    en_US: Aug       de_DE: Aug       sv_SE: aug       ru_RU: авг.      it: ago       it_IT: ago       it_CH: ago       
09:    en_US: Sep       de_DE: Sep       sv_SE: sep       ru_RU: сент.     it: set       it_IT: set       it_CH: set       
10:    en_US: Oct       de_DE: Okt       sv_SE: okt       ru_RU: окт.      it: ott       it_IT: ott       it_CH: ott       
11:    en_US: Nov       de_DE: Nov       sv_SE: nov       ru_RU: нояб.     it: nov       it_IT: nov       it_CH: nov       
12:    en_US: Dec       de_DE: Dez       sv_SE: dec       ru_RU: дек.      it: dic       it_IT: dic       it_CH: dic      
hakre
  • 193,403
  • 52
  • 435
  • 836
  • Quite the same answer at the same time :) i was looking for all month names, not for a given date by the way :) – gremo Dec 21 '12 at 15:54
  • @Gremo: I extended the answer. If you're missing translations, you need to look upstream in the [ICU project](http://site.icu-project.org/) or the [Unicode CLDR Project](http://cldr.unicode.org/) if they exist. Another alternative is that you keep translations for your own for the monthnames, but I'd say it's worth to get data into CLDR if missing. *Edit:* Here is the current list of short monthnames translations, Gregorian calendar: http://www.unicode.org/cldr/charts/by_type/calendars.gregorian.html#Months:_format-abbreviated – hakre Dec 21 '12 at 16:14
  • I wish all answer on the Network would be so clear and detailed ;) – Slava Fomin II Aug 13 '14 at 14:50
  • The formatting guide has moved here: https://unicode-org.github.io/icu/userguide/format_parse/datetime/ – Blaise Jan 05 '22 at 08:09
3

Quite ugly, but it works:

$formatter = \IntlDateFormatter::create(
    'it',
    \IntlDateFormatter::LONG,
    \IntlDateFormatter::NONE,
    \DateTimeZone::UTC, // Doesn't matter
    \IntlDateFormatter::GREGORIAN,
    'MMM'
);

$months = array_map(
    function($m) use($formatter){
        return $formatter->format(mktime(0, 0, 0, $m, 2, 1970));
    },
    range(1, 12)
);

var_dump($months);

Strange thing is with it month names are lower case, with en they have the right case. I'll leave the question unanswered looking for a better solution!

gremo
  • 47,186
  • 75
  • 257
  • 421