Since PHP uses data from ICU in the intl extension, are there ways to get localized month names from within PHP?
While I can get the data from ICU's xml files and extract them into my own set of files, I would much prefer a clean and easier solution if possible.
Finally, are there ways to get the date format (MM/DD/YYYY or DD/MM/YYYY), given the locale from the intl extension?
Not sure what you need the month names for, but if you just want to use translated names for months, strftime() uses the names according to the current locale (use the %B modifier).
If you want a list of month names for some other use you can use strftime() for that too:
$months = array();
for( $i = 1; $i <= 12; $i++ ) {
$months[ $i ] = strftime( '%B', mktime( 0, 0, 0, $i, 1 ) );
}
For the second question there might be a native function for it but it's not hard to make one yourself:
$currentDate = strftime( '%x', strtotime( '2011-12-13' ) );
$localFormat = str_replace(
array( '13', '12', '2011', '11' ),
array( 'DD', 'MM', 'YYYY', 'YY' ),
$currentDate
);
Could you use IntlDateFormatter::getPattern to get the pattern? I don't know about strftime, but I would use the suggestion of formatting with a pattern MMMM to get the month name, through each month. Looks like php.intl doesn't expose the data directly.
(This is not a real answer, it would be a comment to Steven R. Loomis' answer. I write it only because I can't format code in comments)
Thank you Steven R. Loomis, this is my solution:
function local_month_name($locale, $monthnum)
{
/**
* Return the localized name of the given month
*
* #author Lucas Malor
* #param string $locale The locale identifier (for example 'en_US')
* #param int $monthnum The month as number
* #return string The localized string
*/
$fmt = new IntlDateFormatter($locale, IntlDateFormatter::LONG,
IntlDateFormatter::NONE);
$fmt->setPattern('MMMM');
return $fmt->format(mktime(0, 0, 0, $monthnum, 1, 1970));
}
For English or other languages that does not use declination it will work fine, but for all of them that use declination the output will not be valid.
For Polish i.e. the output for March will be marca instead of marzec
For Russian i.e. the output for March will be Мартa instead of Март
This method will not work through ALL languages which most probably is required and may not be easily tested by person not speaking the language.
If you only need names of the months it is better to use:
setlocale(LC_TIME, 'pl_PL');
$month_name = strftime('%B', mktime(0, 0, 0, $month_number));
Please have in mind that locale change may impact other parts of your application.
setlocale(LC_ALL, 'en_US.ISO_8859-1');
and so on
Related
I have this part of the function, which gives me name of the months in English. How can I translate them to my local language (Serbian)?
$month_name = date('F', mktime(0, 0, 0, $i));
Where $i is the number of the month (values 1 - 12). See also PHP:mktime.
You should use setlocale():
setlocale(LC_TIME, 'fr_FR');
$month_name = date('F', mktime(0, 0, 0, $i));
In this case it would set it to French. For your case it should be one of the following:
sr_BA - Serbian (Montenegro)
sr_CS - Serbian (Serbia)
sr_ME - Serbian (Serbia and Montenegro)
You should use setlocale() and strftime():
setlocale(LC_TIME, 'sr_CS');
$month_name = strftime('%B', mktime(0, 0, 0, $i));
Here is an example with IntlDateFormatter
$format = new IntlDateFormatter('sr_CS', IntlDateFormatter::NONE,
IntlDateFormatter::NONE, NULL, NULL, "MMM");
$monthName = datefmt_format($format, mktime(0, 0, 0, $i));
For all who struggle with German (and de_DE), make sure you are using the right language code. Login to your server and run locale -a to see a list of all available ones. For me it shows:
CC.UTF-8de_AT.utf8de_BE.utf8de_CH.utf8de_DE.utf8de_LI.utf8de_LU.utf8...
You need to use one of those codes.
Then you can use:
date_default_timezone_set('Europe/Berlin');
setlocale(LC_ALL, 'de_DE.utf8');
$date_now = date('Y-m-d');
$month_available = strftime('%B %Y', strtotime($date_now));
$month_next = strftime('%B %Y', strtotime($date_now.' +1 month'));
and "März 2020" etc. get displayed correctly.
This question asks how to get a list of months, I only see hints, not a complete code answer so:
If you have IntlDateFormatter available - which is available in most of the cases, you can create a formatter in a given locale and repeatedly push a date to it created just based on month number
// or any other locales like pl_PL, cs_CZ, fr_FR, zh, zh_Hans, ...
$locale = 'en_GB';
$dateFormatter = new IntlDateFormatter(
$locale,
IntlDateFormatter::LONG, // date type
IntlDateFormatter::NONE // time type
);
$dateFormatter->setPattern('LLLL'); // full month name with NO DECLENSION ;-)
$months_locale = [];
for ($month_number = 1; $month_number <= 12; ++$month_number) {
$months_locale[] = $dateFormatter->format(
// 'n' => month number with no leading zeros
DateTime::createFromFormat('n', (string)$month_number)
);
}
// test output
echo "<pre>";
var_dump($months_locale);
echo "</pre>";
Note: LLLL takes care of not-declining, but it does not take care of the lowercase/uppercase of the first letter if the languages has such things.Good example is that you can get January for en_GB but leden for cs_CZ
If you want all letters lowercase => use mb_strtolower($month_name); - docs
If you want just the FIRST letter to be upper case =>
=> use mb_convert_case($month_name, MB_CASE_TITLE, 'UTF-8'); - docs
Always use mb_* functions or their variations for locale-originating strings !
So no, don't use ucfirst !
It is good idea to pass the encoding when setting the locale:
<?php
date_default_timezone_set('Europe/Belgrade');
setlocale(LC_TIME, array('sr_CS.UTF-8', 'sr.UTF-8'));
I'm trying to figure out a way how to take a string and be able to use it in a DateTime. This is an example (obviously giving an error because of incorrect parameters):
$string = sprintf('strtotime("second monday of october", mktime(0, 0, 0, 10, 1, %d))', 2014);
$date = DateTime::createFromFormat('Y-m-d', $string);
echo $date->format('Y-m-d');
The reason why I want to achieve this is to be able to have the year be determined by other factors depending where it is located in my class: meaning that $string will be created on the fly and will be used later to output a date. My question, is there an alternative to this or is it just not possible and the year must be pre-determined. Any hand would be appreciated.
If you mean you want to get second october of a dynamic year, try doing:
$my_year = 2014;
$string = strtotime(sprintf('second monday of october %d', $my_year));
and use the $string to get formatted date
I have this part of the function, which gives me name of the months in English. How can I translate them to my local language (Serbian)?
$month_name = date('F', mktime(0, 0, 0, $i));
Where $i is the number of the month (values 1 - 12). See also PHP:mktime.
You should use setlocale():
setlocale(LC_TIME, 'fr_FR');
$month_name = date('F', mktime(0, 0, 0, $i));
In this case it would set it to French. For your case it should be one of the following:
sr_BA - Serbian (Montenegro)
sr_CS - Serbian (Serbia)
sr_ME - Serbian (Serbia and Montenegro)
You should use setlocale() and strftime():
setlocale(LC_TIME, 'sr_CS');
$month_name = strftime('%B', mktime(0, 0, 0, $i));
Here is an example with IntlDateFormatter
$format = new IntlDateFormatter('sr_CS', IntlDateFormatter::NONE,
IntlDateFormatter::NONE, NULL, NULL, "MMM");
$monthName = datefmt_format($format, mktime(0, 0, 0, $i));
For all who struggle with German (and de_DE), make sure you are using the right language code. Login to your server and run locale -a to see a list of all available ones. For me it shows:
CC.UTF-8de_AT.utf8de_BE.utf8de_CH.utf8de_DE.utf8de_LI.utf8de_LU.utf8...
You need to use one of those codes.
Then you can use:
date_default_timezone_set('Europe/Berlin');
setlocale(LC_ALL, 'de_DE.utf8');
$date_now = date('Y-m-d');
$month_available = strftime('%B %Y', strtotime($date_now));
$month_next = strftime('%B %Y', strtotime($date_now.' +1 month'));
and "März 2020" etc. get displayed correctly.
This question asks how to get a list of months, I only see hints, not a complete code answer so:
If you have IntlDateFormatter available - which is available in most of the cases, you can create a formatter in a given locale and repeatedly push a date to it created just based on month number
// or any other locales like pl_PL, cs_CZ, fr_FR, zh, zh_Hans, ...
$locale = 'en_GB';
$dateFormatter = new IntlDateFormatter(
$locale,
IntlDateFormatter::LONG, // date type
IntlDateFormatter::NONE // time type
);
$dateFormatter->setPattern('LLLL'); // full month name with NO DECLENSION ;-)
$months_locale = [];
for ($month_number = 1; $month_number <= 12; ++$month_number) {
$months_locale[] = $dateFormatter->format(
// 'n' => month number with no leading zeros
DateTime::createFromFormat('n', (string)$month_number)
);
}
// test output
echo "<pre>";
var_dump($months_locale);
echo "</pre>";
Note: LLLL takes care of not-declining, but it does not take care of the lowercase/uppercase of the first letter if the languages has such things.Good example is that you can get January for en_GB but leden for cs_CZ
If you want all letters lowercase => use mb_strtolower($month_name); - docs
If you want just the FIRST letter to be upper case =>
=> use mb_convert_case($month_name, MB_CASE_TITLE, 'UTF-8'); - docs
Always use mb_* functions or their variations for locale-originating strings !
So no, don't use ucfirst !
It is good idea to pass the encoding when setting the locale:
<?php
date_default_timezone_set('Europe/Belgrade');
setlocale(LC_TIME, array('sr_CS.UTF-8', 'sr.UTF-8'));
Does strtotime only work in the default language on the server? The below code should resolve to august 11, 2005, however it uses the french "aout" instead of the english "aug".
Any ideas how to handle this?
<?php
$date = strtotime('11 aout 05');
echo date('d M Y',$date);
?>
As mentioned strtotime does not take locale into account. However you could use strptime (see http://ca1.php.net/manual/en/function.strptime.php), since according to the docs:
Month and weekday names and other language dependent strings respect the current locale set with setlocale() (LC_TIME).
Note that depending on your system, locale and encoding you will have to account for accented characters.
French month dates are:
janvier février mars avril mai juin juillet août septembre octobre
novembre décembre
Hence, for the very specific case where months are in French you could use
function myStrtotime($date_string) { return strtotime(strtr(strtolower($date_string), array('janvier'=>'jan','février'=>'feb','mars'=>'march','avril'=>'apr','mai'=>'may','juin'=>'jun','juillet'=>'jul','août'=>'aug','septembre'=>'sep','octobre'=>'oct','novembre'=>'nov','décembre'=>'dec'))); }
The function anyway does not break if you pass $date_string in English, because it won't do any substitution.
From the docs
Parse about any English textual datetime description into a Unix
timestamp
Edit: Six years down the road now, and what was meant to be a side-note about why strtotime() was an inappropriate solution for the issue at hand became the accepted answer 😲
To better answer the actual question I want to echo Marc B's answer: despite the downvotes, date_create_from_format, paired with a custom Month interpreter will provide the most reliable solution
However it appears that there is still no silver-bullet for international date parsing built-in to PHP for the time being.
This method should work for you using strftime:
setlocale (LC_TIME, "fr_FR.utf8"); //Setting the locale to French with UTF-8
echo strftime(" %d %h %Y",strtotime($date));
strftime
I wrote a simple function partially solves this problem.
It does not work as a full strtotme(), but it determines the number of months names in the dates.
<?php
// For example, I get the name of the month from a
// date "1 January 2015" and set him (with different languages):
echo month_to_number('January').PHP_EOL; // returns "01" (January)
echo month_to_number('Января', 'ru_RU').PHP_EOL; // returns "01" (January)
echo month_to_number('Мая', 'ru_RU').PHP_EOL; // returns "05" (May)
echo month_to_number('Gennaio', 'it_IT').PHP_EOL; // returns "01" (January)
echo month_to_number('janvier', 'fr_FR').PHP_EOL; // returns "01" (January)
echo month_to_number('Août', 'fr_FR').PHP_EOL; // returns "08" (August)
echo month_to_number('Décembre', 'fr_FR').PHP_EOL; // returns "12" (December)
Similarly, we can proceed to determine the numbers and days of the week, etc.
Function:
<?php
function month_to_number($month, $locale_set = 'ru_RU')
{
$month = mb_convert_case($month, MB_CASE_LOWER, 'UTF-8');
$month = preg_replace('/я$/', 'й', $month); // fix for 'ru_RU'
$locale =
setlocale(LC_TIME, '0');
setlocale(LC_TIME, $locale_set.'.UTF-8');
$month_number = FALSE;
for ($i = 1; $i <= 12; $i++)
{
$time_month = mktime(0, 0, 0, $i, 1, 1970);
$short_month = date('M', $time_month);
$short_month_lc = strftime('%b', $time_month);
if (stripos($month, $short_month) === 0 OR
stripos($month, $short_month_lc) === 0)
{
$month_number = sprintf("%02d", $i);
break;
}
}
setlocale(LC_TIME, $locale); // return locale back
return $month_number;
}
The key to solving this question is to convert foreign textual representations to their English counterparts. I also needed this, so inspired by the answers already given I wrote a nice and clean function which would work for retrieving the English month name.
function getEnglishMonthName($foreignMonthName,$setlocale='nl_NL'){
setlocale(LC_ALL, 'en_US');
$month_numbers = range(1,12);
foreach($month_numbers as $month)
$english_months[] = strftime('%B',mktime(0,0,0,$month,1,2011));
setlocale(LC_ALL, $setlocale);
foreach($month_numbers as $month)
$foreign_months[] = strftime('%B',mktime(0,0,0,$month,1,2011));
return str_replace($foreign_months, $english_months, $foreignMonthName);
}
echo getEnglishMonthName('juli');
// Outputs July
You can adjust this for days of the week aswell and for any other locale.
Adding this as an extended version of Marco Demaio answer. Added french days of the week and months abbreviations:
<?php
public function frenchStrtotime($date_string) {
$date_string = str_replace('.', '', $date_string); // to remove dots in short names of months, such as in 'janv.', 'févr.', 'avr.', ...
return strtotime(
strtr(
strtolower($date_string), [
'janvier'=>'jan',
'février'=>'feb',
'mars'=>'march',
'avril'=>'apr',
'mai'=>'may',
'juin'=>'jun',
'juillet'=>'jul',
'août'=>'aug',
'septembre'=>'sep',
'octobre'=>'oct',
'novembre'=>'nov',
'décembre'=>'dec',
'janv'=>'jan',
'févr'=>'feb',
'avr'=>'apr',
'juil'=>'jul',
'sept'=>'sep',
'déc'=>'dec',
'lundi' => 'monday',
'mardi' => 'tuesday',
'mercredi' => 'wednesday',
'jeudi' => 'thursday',
'vendredi' => 'friday',
'samedi' => 'saturday',
'dimanche' => 'sunday',
]
)
);
}
It's locale dependent. If it had to check every language for every parse, it'd take nigh-on FOREVER to parse even the simplest of date strings.
If you've got a string with known format, consider using date_create_from_format(), which'll be far more efficient and less error-print
Try to set the locale before conversion:
setlocale(LC_TIME, "fr_FR");
I'm working with PHP 5.3 on my local machine and needed to parse a UK date format (dd/mm/yyyy). I found that strtotime didn't work with that date format, so I used date_create_from_format instead - which works great.
Now, my problem is that my staging server is running PHP 5.2, and date_create_from_format doesn't work on that version. (It's a shared server, and wouldn't have a clue how to upgrade it to PHP 5.3)
So is there a similar function to date_create_from_format that I can use? Bespoke or PHP native?
If strptime is not available to you, then here is a different idea. It is similar to Col. Shrapnel's approach but instead uses sscanf to parse the date-part values into variables and uses those to construct a new DateTime object.
list($day, $month, $year) = sscanf('12/04/2010', '%02d/%02d/%04d');
$datetime = new DateTime("$year-$month-$day");
echo $datetime->format('r');
Try strptime() which is available in PHP 5.1 and above.
include this code:
function DEFINE_date_create_from_format()
{
function date_create_from_format( $dformat, $dvalue )
{
$schedule = $dvalue;
$schedule_format = str_replace(array('Y','m','d', 'H', 'i','a'),array('%Y','%m','%d', '%I', '%M', '%p' ) ,$dformat);
// %Y, %m and %d correspond to date()'s Y m and d.
// %I corresponds to H, %M to i and %p to a
$ugly = strptime($schedule, $schedule_format);
$ymd = sprintf(
// This is a format string that takes six total decimal
// arguments, then left-pads them with zeros to either
// 4 or 2 characters, as needed
'%04d-%02d-%02d %02d:%02d:%02d',
$ugly['tm_year'] + 1900, // This will be "111", so we need to add 1900.
$ugly['tm_mon'] + 1, // This will be the month minus one, so we add one.
$ugly['tm_mday'],
$ugly['tm_hour'],
$ugly['tm_min'],
$ugly['tm_sec']
);
$new_schedule = new DateTime($ymd);
return $new_schedule;
}
}
if( !function_exists("date_create_from_format") )
DEFINE_date_create_from_format();
If you need to parse only one particular format, it's elementary string operation.
list($d,$m,$y)=explode("/",$datestr);
use format DD-MM-YY and timestamp, I think it will be easier for you
$date="31-11-2015";
$timestamp=strtotime($date);
$dateConvert=date('d-m-Y', $timestamp);
echo $dateConvert;
I've used it