Related
I have done this function so that I have as a result the working days without counting the weekend between two dates, in the database I have the date fields as DATATIME, but at the time of executing I get this error:
A non well formed numeric value encountered
The function is as follows:
function diashabiles ($fecha_inicio, $fecha_fin) {
list ($year, $month, $day) = explode ("/", $fecha_inicio);
$ini = mktime (0, 0, 0, $month, $day, $year);
list ($yearf, $mesf, $diaf) = explode ("/", $fecha_fin);
$fin = mktime (0, 0, 0, $mesf, $diaf, $yearf);
$newArray = array ();
$r = 1; $i = 0; $dia2 = 0;
while ($ini! = $fin) {
$ini = mktime (0, 0, 0, $month, $day + $r, $year);
$newArray [$i] = $ini;
$r++; $i++;
}
for ($i = 0; $i <count($newArray); $i++) {
$day = $newArray [$i];
$date = getdate($day);
if ($date["wday"] == 0 or $date["wday"] == 6) {
$dia2++;
}
}
$rlt = count($newArray) - $dia2;
return $rlt;
}
Thank You!!
The problem is with this code:
list ($year, $month, $day) = explode ("/", $fecha_inicio);
$ini = mktime (0, 0, 0, $month, $day, $year);
list ($yearf, $mesf, $diaf) = explode ("/", $fecha_fin);
$fin = mktime (0, 0, 0, $mesf, $diaf, $yearf);
You stated that initially, the data stored was in DATE format, which means that what was coming out of the database was simply a year, month and a day. Then, you changed the data type to be DATETIME, which obviously changes what is stored in the database, and obviously changes what is retrieved.
In short, your explode function will leave you with the following:
$year = whatever year is in the database. Can be numeric.
$month = whatever month is in the database. Can be numeric.
$day = the rest, which will include day, hour, minute, second. Definitely not numeric.
When you use the above information (with the day being a string rather than a number) then mktime() fails.
Script works well if you replace
while ($ini != $fin)
with this
while ($ini <= $fin).
But i still suggest you to check this link Use DateTime, DateInterval and DatePeriod
Is there a PHP function to turn month numbers into localised month names?
My current solution is as follows, but I feel there is a better way.
class num2month {
static function month($num){
$m = array(1=>"Январь",
2=>"Февраль",
3=>"Март",
4=>"Апрель",
5=>"Май",
6=>"Июнь",
7=>"Июль",
8=>"Август",
9=>"Сентябрь",
10=>"Октябрь",
11=>"Ноябрь",
12=>"Декабрь");
return $m[$num];
}
}
You can do:
echo date('F', mktime(0, 0, 0, $month, 1, date('Y')));
For example:
$m = 1;
$month = date("F", mktime(0, 0, 0, $m, 10));
$month == "January", but you still need to provide some translating array or table in database to translate to needed language.
Your code is working just fine. See this php fiddle (click on run) http://phpfiddle.org/main/code/6v6-iuz
<?php
$test = new num2month;
$test->month(3);
class num2month {
function month($num) {
$m = array(1=>"Январь",
2=>"Февраль",
3=>"Март",
4=>"Апрель",
5=>"Май",
6=>"Июнь",
7=>"Июль",
8=>"Август",
9=>"Сентябрь",
10=>"Октябрь",
11=>"Ноябрь",
12=>"Декабрь");
echo $m[$num];
}
}
?>
Im using Github's api to get my latest commits, and the date format returned looks like this
2012-01-25T11:23:28-08:00
I tried to do it like this:
$date = explode('T', $next['commit']['author']['date']);
$time = strtotime($date[0] .' '. $date[1]);
$date = date('M j, Y g:i a', $time);
But it didnt turn out right as php thought I was subtracting 8 hours from the time (because of the timezone). I would like to keep the timezone but i have no clue how to parse that. Does anyone know how to have it where the time is correct and shows the time zone abbreviation (GMT, PST etc etc )?
It cannot get any simpler than this:
$a = new DateTime("2012-01-25T11:23:28-08:00");
echo $a->format("Y-m-d H:i:s");
//outputs 2012-01-25 11:23:28
See the documentation of the DateTime class for more info.
The simple, mechanical, solution is to break the date down yourself completely:
$date = substr($next['commit']['author']['date'], 0, 10);
$time = substr($next['commit']['author']['date'], 11, 9);
$zone = substr($next['commit']['author']['date'], 20, 6);
list($y, $m, $d) = explode('-', $date);
list($h, $i, $s) = explode(':', $time);
$zh = substr($zone, 1, 2);
$zm = substr($zone, 4, 2);
if (substr($zone, 0, 1) == '-'){
$h -= $zh;
$m -= $zm;
}else{
$h += $zh;
$m += $zm;
}
$ts = gmmktime($h,$i,$s,$m,$d,$y);
This will give you a timestamp in UTC.
The issue is with "shows the time zone abbreviation" - you can't find a abbreviation for a given offset, because there can be several - you can't tell which of the e.g. +01:00 timezones the date is in - could be european, african, or bristish summer time.
It really depends what you want to do with the data.
I have a start date of 20090101 and an end date of 20091130 and I'm trying to build and array of all the months in between, which would look like this:
<?php
/* ... */
$arrDates['Jan'] = 2009;
$arrDates['Feb'] = 2009;
$arrDates['Mar'] = 2009;
/* ... */
?>
How can I do this?
I don't fully understand your array structure.
But maybe this helps: When using PHP 5.3 you can use code like below to get an iterator with all months in the given range:
<?php
$db = new DateTime( '2009-01-01 00:00:00' );
$de = new DateTime( '2009-11-30 23:59:59' );
$di = DateInterval::createFromDateString( 'first day of next month' );
foreach ( $di as $dt )
{
echo $dt->format( "Y-m\n" );
}
?>
The following snippet creates such an array:
$startDate = '20090101';
$endDate = '20091130';
$arrDates = array();
$cur = strtotime($startDate);
$end = strtotime($endDate);
while ($cur < $end) {
$arrDates[date('M', $cur)] = date('Y', $cur);
$cur = mktime(0, 0, 0, date('m', $cur) + 1, 1, date('Y', $cur));
}
// If you want to add the 'end' month too...
$arrDates[date('M', $end)] = date('Y', $end);
However, note that, as danii commented, you are unclear about how you want to handle a timespan that is larger than a year. The code above will simply use the last year in the range you provide.
This code will work with pretty much any version of PHP (PHP 4+). If you want a more elegant solution and are using PHP 5.2+, I recommend the solution offered by GZipp.
I had a similar situation for a website i was building for travelagency. You need timestamps, arrays and looping. Take a look at the date function PHP provides. It gives you some interesting options to play with dates. E.g. the no. of days in a specified month.
You say "the months in between", but since your example includes the starting month, I assume you mean "the months in between plus the starting and ending months".
$dt_start = new DateTime('20090101');
$dt_end = new DateTime('20091130');
$arrDates[] = $dt_start->format('M');
while ($dt_start->modify('first day of next month') <= $dt_end) {
$arrDates[] = $dt_start->format('M'); // Or whatever you want to do with it.
}
(This is essentially johannes' solution with a little manual reading applied to adapt it for PHP 5.2.)
You can't use the month as a key, the key must be unique or if your range spans more than a year it won't work correctly.
This will return an array with Mon-Year as the key
function foo($startdate, $enddate) {
// create a timestamp for start date
if(!preg_match('/^(\d{4})(\d{2})(\d{2})$/', $startdate, $m)) die('Invalid start date format');
$start_time = mktime(0, 0, 0, $m[2], $m[3], $m[1]);
// create a timestamp for end date
if(!preg_match('/^(\d{4})(\d{2})(\d{2})$/', $enddate, $m)) die('Invalid end date format');
$end_time = mktime(23, 59, 59, $m[2], $m[3], $m[1]);
// build the array of months by incrementing $start_time by one month through each iteration
$ret = array();
while($start_time < $end_time) {
$ret[date('M-Y', $start_time)] = date('Y', $start_time);
$start_time = strtotime(date('m/d/Y', $start_time).' +1month');
}
return $ret;
}
$arrDates = foo('20090101', '20111130');
print_r($arrDates);
Array(
[Jan-2009] => 2009
[Feb-2009] => 2009
[Mar-2009] => 2009
[Apr-2009] => 2009
[May-2009] => 2009
[Jun-2009] => 2009
[Jul-2009] => 2009
[Aug-2009] => 2009
....
)
A bit convoluted but works...:
function buildDateRange($strStartDate, $strEndDate)
{
$strStartM = date('M', $strStartDate);
$strStartY = date('Y', $strStartDate);
$strEndM = date('M', $strEndDate);
$strEndY = date('Y', $strEndDate);
$intCurMN = date('m', $strStartDate);
$ii = 0;
$blnFinished = FALSE;
while(!$blnFinished)
{
$strCurM = date('M', mktime(0, 0, 0, $intCurMN , "01", $strStartY));
$strCurY = date('Y' ,mktime(0, 0, 0, $intCurMN , "01", $strStartY));
$arrSearchDates [$strCurM] = $strCurY;
$intCurMN = date('m', mktime(0, 0, 0, $intCurMN+1 , "01", $strStartY));
if($strEndM == $strCurM && $strEndY == $strCurY)
{
$blnFinished = TRUE;
}
}
Return ($arrSearchDates);
}
Is there a way to check to see if a date/time is valid you would think these would be easy to check:
$date = '0000-00-00';
$time = '00:00:00';
$dateTime = $date . ' ' . $time;
if(strtotime($dateTime)) {
// why is this valid?
}
what really gets me is this:
echo date('Y-m-d', strtotime($date));
results in: "1999-11-30",
huh? i went from 0000-00-00 to 1999-11-30 ???
I know i could do comparison to see if the date is either of those values is equal to the date i have but it isn't a very robust way to check. Is there a good way to check to see if i have a valid date? Anyone have a good function to check this?
Edit:
People are asking what i'm running:
Running PHP 5.2.5 (cli) (built: Jul 23 2008 11:32:27) on Linux localhost 2.6.18-53.1.14.el5 #1 SMP Wed Mar 5 11:36:49 EST 2008 i686 i686 i386 GNU/Linux
From php.net
<?php
function isValidDateTime($dateTime)
{
if (preg_match("/^(\d{4})-(\d{2})-(\d{2}) ([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$/", $dateTime, $matches)) {
if (checkdate($matches[2], $matches[3], $matches[1])) {
return true;
}
}
return false;
}
?>
As mentioned here: https://bugs.php.net/bug.php?id=45647
There is no bug here, 00-00-00 means 2000-00-00, which is 1999-12-00,
which is 1999-11-30. No bug, perfectly normal.
And as shown with a few tests, rolling backwards is expected behavior, if a little unsettling:
>> date('Y-m-d', strtotime('2012-03-00'))
string: '2012-02-29'
>> date('Y-m-d', strtotime('2012-02-00'))
string: '2012-01-31'
>> date('Y-m-d', strtotime('2012-01-00'))
string: '2011-12-31'
>> date('Y-m-d', strtotime('2012-00-00'))
string: '2011-11-30'
echo date('Y-m-d', strtotime($date));
results in: "1999-11-30"
The result of strtotime is 943920000 - this is the number of seconds, roughly, between the Unix epoch (base from which time is measured) to 1999-11-30.
There is a documented mysql bug on mktime(), localtime(), strtotime() all returning this odd value when you try a pre-epoch time (including "0000-00-00 00:00:00"). There's some debate on the linked thread as to whether this is actually a bug:
Since the time stamp is started from 1970, I don't think it supposed to
work in anyways.
Below is a function that I use for converting dateTimes such as the above to a timestamp for comparisons, etc, which may be of some use to you, for dates beyond "0000-00-00 00:00:00"
/**
* Converts strings of the format "YYYY-MM-DD HH:MM:SS" into php dates
*/
function convert_date_string($date_string)
{
list($date, $time) = explode(" ", $date_string);
list($hours, $minutes, $seconds) = explode(":", $time);
list($year, $month, $day) = explode("-", $date);
return mktime($hours, $minutes, $seconds, $month, $day, $year);
}
Don't expect coherent results when you're out of range:
cf strtotime
cf Gnu Calendar-date-items.html
"For numeric months, the ISO 8601
format ‘year-month-day’ is allowed,
where year is any positive number,
month is a number between 01
and 12, and day is a
number between 01 and 31. A
leading zero must be present if a
number is less than ten."
So '0000-00-00' gives weird results, that's logical!
"Additionally, not all
platforms support negative timestamps,
therefore your date range may be
limited to no earlier than the Unix
epoch. This means that e.g.
%e, %T, %R and %D (there might be
more) and dates prior to Jan
1, 1970 will not work on Windows, some
Linux distributions, and a few other
operating systems."
cf strftime
Use checkdate function instead (more robust):
month:
The month is between 1 and 12 inclusive.
day:
The day is within the allowed number of days for the given
month. Leap year s are taken
into consideration.
year:
The year is between 1 and 32767 inclusive.
This version allows for the field to be empty, has dates in mm/dd/yy or mm/dd/yyyy format, allow for single digit hours, adds optional am/pm, and corrects some subtle flaws in the time match.
Still allows some pathological times like '23:14 AM'.
function isValidDateTime($dateTime) {
if (trim($dateTime) == '') {
return true;
}
if (preg_match('/^(\d{1,2})\/(\d{1,2})\/(\d{2,4})(\s+(([01]?[0-9])|(2[0-3]))(:[0-5][0-9]){0,2}(\s+(am|pm))?)?$/i', $dateTime, $matches)) {
list($all,$mm,$dd,$year) = $matches;
if ($year <= 99) {
$year += 2000;
}
return checkdate($mm, $dd, $year);
}
return false;
}
If you just want to handle a date conversion without the time for a mysql date field, you can modify this great code as I did.
On my version of PHP without performing this function I get "0000-00-00" every time. Annoying.
function ConvertDateString ($DateString)
{
list($year, $month, $day) = explode("-", $DateString);
return date ("Y-m-d, mktime (0, 0, 0, $month, $day, $year));
}
<?php
function is_valid_date($user_date=false, $valid_date = "1900-01-01") {
$user_date = date("Y-m-d H:i:s",strtotime($user_date));
return strtotime($user_date) >= strtotime($valid_date) ? true : false;
}
echo is_valid_date("00-00-00") ? 1 : 0; // return 0
echo is_valid_date("3/5/2011") ? 1 : 0; // return 1
I have been just changing the martin answer above, which will validate any type of date and return in the format you like.
Just change the format by editing below line of script
strftime("10-10-2012", strtotime($dt));
<?php
echo is_date("13/04/10");
function is_date( $str ) {
$flag = strpos($str, '/');
if(intval($flag)<=0){
$stamp = strtotime( $str );
} else {
list($d, $m, $y) = explode('/', $str);
$stamp = strtotime("$d-$m-$y");
}
//var_dump($stamp) ;
if (!is_numeric($stamp)) {
//echo "ho" ;
return "not a date" ;
}
$month = date( 'n', $stamp ); // use n to get date in correct format
$day = date( 'd', $stamp );
$year = date( 'Y', $stamp );
if (checkdate($month, $day, $year)) {
$dt = "$year-$month-$day" ;
return strftime("%d-%b-%Y", strtotime($dt));
//return TRUE;
} else {
return "not a date" ;
}
}
?>
I have used the following code to validate dates coming from ExtJS applications.
function check_sql_date_format($date) {
$date = substr($date, 0, 10);
list($year, $month, $day) = explode('-', $date);
if (!is_numeric($year) || !is_numeric($month) || !is_numeric($day)) {
return false;
}
return checkdate($month, $day, $year);
}
<?php
function is_date( $str ) {
$stamp = strtotime( $str );
if (!is_numeric($stamp)) {
return FALSE;
}
$month = date( 'm', $stamp );
$day = date( 'd', $stamp );
$year = date( 'Y', $stamp );
if (checkdate($month, $day, $year)) {
return TRUE;
}
return FALSE;
}
?>