Optional month or day in MySQL date field from PHP - php

I have a problem where I need to handle dates where the month and day parts are optional. For example, the year will always be known but sometimes the day or month and day will be unknown.
In MySQL I can create a table with a date field and while I can't find any reference in the MySQL Manual it will accept the following as valid:
(YYYY-MM-DD format):
2011-02-10 // Current date
2011-02-00 // Day unknown so replaced with 00
2011-00-00 // Day and month unkown so replaced with 00-00
Test calculations from within the database work fine so I can still sort results easily. In the manual it says that month needs to be between 01 and 12, and day between 01 and 31 - but it does accept 00.
First question: Am I going to run into trouble using 00 in the month or day parts or is this perfectly acceptable?
Next question: Is there a PHP function (or MySQL format command) that will automatically format the following dates into the required format string?
2011 becomes 2011-00-00
2011-02 becomes 2011-02-00
Or do I need write a special function to handle this?
The following doesn't work:
<?php
$date = date_create_from_format('Y-m-d', '2011-00-00');
echo date_format($date, 'Y-m-d');
// Returns 2010-11-30
$date = date_create_from_format('Y-m-d', '2011-02-00');
echo date_format($date, 'Y-m-d');
// Returns 2011-01-31
?>
Third question: Is there a PHP function (or MySQL command) to format the dates for use in PHP?
Finally, is this the best approach? Or is there a 'best practise' method?
EDIT:
Here is what I'm currently doing:
A date field can accept a date in the format YYYY, YYYY-MM, or YYYY-MM-DD and before sending to the database it is processed in this function:
/**
* Takes a date string in the form:
* YYYY or
* YYYY-MM or
* YYYY-MM-DD
* and validates it
*
* Use date_format($date, $format); to reverse.
*
* #param string $phpDate Date format [YYYY | YYYY-MM | YYYY-MM-DD]
*
* #return array 'date' as YYYY-MM-DD, 'format' as ['Y' | 'Y-m' | 'Y-m-d'] or returns false if invalid
*/
function date_php2mysql($phpDate) {
$dateArr = false;
// Pattern match
if (preg_match('%^(?P<year>\d{4})[- _/.]?(?P<month>\d{0,2})[- _/.]?(?P<day>\d{0,2})%im', trim($phpDate), $parts)) {
if (empty($parts['month'])) {
// Only year valid
$date = $parts['year']."-01-01";
$format = "Y";
} elseif (empty($parts['day'])) {
// Year and month valid
$date = $parts['year']."-".$parts['month']."-01";
$format = "Y-m";
} else {
// Year month and day valid
$date = $parts['year']."-".$parts['month']."-".$parts['day'];
$format = "Y-m-d";
}
// Double check that it is a valid date
if (strtotime($date)) {
// Valid date and format
$dateArr = array('date' => $date, 'format' => $format);
}
} else {
// Didn't match
// Maybe it is still a valid date
if (($timestamp = strtotime($phpDate)) !== false) {
$dateArr = array('date' => date('Y-m-d', $timestamp), 'format' => "Y-m-d");
}
}
// Return result
return $dateArr;
}
So it pattern matches the input $phpDate where it must begin with 4 digits, then optionally pairs of digits for the month and the day. These are stored in an array called $parts.
It then checks if months or days exist, specifying the format string and creating the date.
Finally, if everything checks out, it returns a valid date as well as a format string. Otherwise it returns FALSE.
I end up with a valid date format for my database and I have a way of using it again when it comes back out.
Anyone think of a better way to do this?

I have a problem where I need to handle dates where the month and day parts are optional.
For example, the year will always be known but sometimes the day or month and day will be
unknown.
In many occasions, we do need such 'more or less precise' dates, and I use such dates as 2011-04-01 (precise), as well as 2011-04 (= April 2011) and 2011 (year-only date) in archives metadata. As you mention it, MySQL date field tolerates '2011-00-00' though no FAQs tell about it, and it's fine.
But then, I had to interface the MySQL database via ODBC and the date fields
are correctly translated, except the 'tolerated' dates (Ex: '2011-04-00' results empty in the resulting MySQL-ODBC-connected ACCESS database.
For that reason, I came to the conclusion that the MySQL date field could be converted in a plain VARCHAR(10) field : As long as we don't need specific MySQL date functions, it works fine, and of course, we can still use php date functions and your fine date_php2mysql() function.
I would say that the only case when a MySQL date field is needed
is when one needs complex SQL queries, using MySQL date functions in the query itself.
(But such queries would not work anymore on 'more or less precise' dates!...)
Conclusion : For 'more or less precise' dates,
I presently discard MySQL date field and use plain VARCHAR(10) field
with aaaa-mm-jj formated data. Simple is beautiful.

Since the data parts are all optional, would it be tedious to store the month, day, and year portions in separate integer fields? Or in a VARCHAR field? 2011-02-00 is not a valid date, and I wouldnt't think mysql or PHP would be excited about it. Test it out with str_to_time and see what kind of results you get, also, did you verify that the sorting worked right in MySQL? If the docs say that 1 through 31 is required, and it is taking 00, you might be relying on what is, in essence, a bug.
Since 2011-02-00 is not a valid date, none of PHP's formatting functions will give you this result. If it handled it at all, I wouldn't be surprised if you got 2001-01-31 if you tried. All the more reason to either store it as a string in the database, or put the month, day, and year in separate integer fields. If you went with the latter route, you could still do sorting on those columns.

I have also encountered this problem. I ended up using the PEAR Date package. Most date classes won't work with optional months or optional days, but the PEAR Date package does. This also means you don't need custom formatting functions and can use the fancy formatting methods provided by the Date package.

I have found this link in a textbook. This states that month and day values can be zero to allow for the possiblity of storing incomplete or unknown data
http://books.google.co.uk/books?id=s_87mv-Eo4AC&pg=PA145&lpg=PA145&dq=mysql+date+of+death+when+month+unknown&source=bl&ots=tcRGz3UDtg&sig=YkwpkAlDtBP1KKTDtqSyZCl63hs&hl=en&ei=Btf5TbL1NIexhAfkveyTAw&sa=X&oi=book_result&ct=result&resnum=8&ved=0CFMQ6AEwBw#v=onepage&q&f=false

If you pull your date in pieces from the database you can get it as if it's 3 fields.
YEAR(dateField) as Year, MONTH(dateField) as Month, DAY(dateField) as DAY
Then pushing those into the corresponding fields in the next bit of PHP will give you the result you're looking for.
$day = 0;
$month = 0;
$year = 2013;
echo $datestring;
$format = "Y";
if($month)
{
$format .= "-m";
if($day)
$format .="-d";
else
$day = 1;
}
else
{
$month = 1;
$day = 1;
}
$datestring = strval($year)."-".strval($month)."-".strval($day);
$date = date($format, strtotime($datestring));
echo $date; // "2013", if $month = 1, "2013-01", if $day and $month = 1, "2013-01-01"

Related

Adding leading zeroes to a string date in PHP

I have a string "date" which can be DD.MM.YYYY or D.M.YYYY (with or without leading zeros), it depends what a user types.
Then I use it in a condition to send another email when the day is today.
if($_POST["date"]== date("d.m.Y")){
$headers.="Bcc: another#mail.cz\r\n";
}
The problem is that the mail is send when the date format DD.MM.YYYY (with leading zeros) only.
My proposed solution
As I'm not very good in PHP, I only know the solution theoretically but not how to write the code - I would spend a week trying to figure it out on my own.
What's in my mind is dividing the date into three parts (day, month, year), then checking the first two parts if there's just one digit and adding leading zeros if it's the case. I don't know how to implement that to the condition above, though. I have read a few topics about how to do this, but they were a bit more different than my case is.
You should equalize to same format d.m.Y and you can do this with strtotime and date function:
$post_date = date("d.m.Y", strtotime($_POST["date"]));
if($post_date == date("d.m.Y")){
$headers.="Bcc: another#mail.cz\r\n";
}
I changed date to $post_date for more clear. I'll try to explain difference with outputs
echo $_POST["date"]; // lets say: 8.7.2013
echo date("d.m.Y"); // 09.09.2013 > it's current day
strtotime($_POST["date"]); // 1373230800 > it's given date with unix time
$post_date = date("d.m.Y", strtotime($_POST["date"])); // 08.07.2013 > it's given date as right format
If you use date function without param, it returns as current date.
Otherwise if you use with param like date('d.m.Y', strtotime('given_date'));, it returns as given date.
$post_date = date("d.m.Y", strtotime($_POST["date"]));
At first, we converted your date string to unix with strtotime then equalized and converted format that you used in if clause.
first set date format with leading Zero
$postdate = strtotime('DD.MM.YY', $_POST['date']);
and also matching date will be in same format
$matching_date = date('DD.MM.YY', strtotime('whatever the date'));
then
if ( $postdate === $matching_date )
{
// send mail
}
Why don't you just check the length of the _POST (it can be either 8 or 10)
if (strlen($_POST["date"]) == 10) {
$headers.="Bcc: another#mail.cz\r\n";
}

Adjust a PHP date to the current year

I have a PHP date in a database, for example 8th August 2011. I have this date in a strtotime() format so I can display it as I please.
I need to adjust this date to make it 8th August 2013 (current year). What is the best way of doing this? So far, I've been racking my brains but to no avail.
Some of the answers you have so far have missed the point that you want to update any given date to the current year and have concentrated on turning 2011 into 2013, excluding the accepted answer. However, I feel that examples using the DateTime classes are always of use in these cases.
The accepted answer will result in a Notice:-
Notice: A non well formed numeric value encountered......
if your supplied date is the 29th February on a Leapyear, although it should still give the correct result.
Here is a generic function that will take any valid date and return the same date in the current year:-
/**
* #param String $dateString
* #return DateTime
*/
function updateDate($dateString){
$suppliedDate = new \DateTime($dateString);
$currentYear = (int)(new \DateTime())->format('Y');
return (new \DateTime())->setDate($currentYear, (int)$suppliedDate->format('m'), (int)$suppliedDate->format('d'));
}
For example:-
var_dump(updateDate('8th August 2011'));
See it working here and see the PHP manual for more information on the DateTime classes.
You don't say how you want to use the updated date, but DateTime is flexible enough to allow you to do with it as you wish. I would draw your attention to the DateTime::format() method as being particularly useful.
strtotime( date( 'd M ', $originaleDate ) . date( 'Y' ) );
This takes the day and month of the original time, adds the current year, and converts it to the new date.
You can also add the amount of seconds you want to add to the original timestamp. For 2 years this would be 63 113 852 seconds.
You could retrieve the timestamp of the same date two years later with strtotime() first parameter and then convert it in the format you want to display.
<?php
$date = "11/08/2011";
$time = strtotime($date);
$time_future = strtotime("+2 years", $time);
$future = date("d/m/Y", $time_future);
echo "NEW DATE : " . $future;
?>
You can for instance output it like this:
date('2013-m-d', strtotime($myTime))
Just like that... or use
$year = date('Y');
$myMonthDay = date('m-d', strtotime($myTime));
echo $year . '-' . $myMonthDay;
Use the date modify function Like this
$date = new DateTime('2011-08-08');
$date->modify('+2 years');
echo $date->format('Y-m-d') . "\n";
//will give "2013-08-08"

How to determine if a date is more than three months past current date

I am getting a date back from a mysql query in the format YYYY-MM-DD.
I need to determine if that is more than three months in the past from the current month.
I currently have this code:
$passwordResetDate = $row['passwordReset'];
$today = date('Y-m-d');
$splitCurrentDate = explode('-',$today);
$currentMonth = $splitCurrentDate[1];
$splitResetDate = explode('-', $passwordResetDate);
$resetMonth = $splitResetDate[1];
$diferenceInMonths = $splitCurrentDate[1] - $splitResetDate[1];
if ($diferenceInMonths > 3) {
$log->lwrite('Need to reset password');
}
The problem with this is that, if the current month is in January, for instance, giving a month value of 01, and $resetMonth is November, giving a month value of 11, then $differenceInMonths will be -10, which won't pass the if() statement.
How do I fix this to allow for months in the previous year(s)?
Or is there a better way to do this entire routine?
Use strtotime(), like so:
$today = time(); //todays date
$twoMonthsLater = strtotime("+3 months", $today); //3 months later
Now, you can easily compare them and determine.
I’d use PHP’s built-in DateTime and DateInterval classes for this.
<?php
// create a DateTime representation of your start date
// where $date is date in database
$resetDate = new DateTime($date);
// create a DateIntveral representation of 3 months
$passwordExpiry = new DateInterval('3M');
// add DateInterval to DateTime
$resetDate->add($passwordExpiry);
// compare $resetDate to today’s date
$difference = $resetDate->diff(new DateTime());
if ($difference->m > 3) {
// date is more than three months apart
}
I would do the date comparison in your SQL expression.
Otherwise, PHP has a host of functions that allow easy manipulation of date strings:
PHP: Date/Time Functions - Manual

PHP - checking if two dates match but ignoring the year

I have an array which will output a date. This date is outputted in the mm/dd/yyyy format. I have no control over how this outputted so I cant change this.
Array
(
[date] => 04/06/1989
)
I want to use php to check if this date matches the current date (today), but ignoring the year. So in the above example I just want to check if today is the 6th April. I am just struggling to find anything which documents how to ignore the years.
if( substr( $date, 0, 5 ) == date( 'm/d' ) ) { ...
Works only if it's certain that the month and date are both two characters long.
Came in a little late, but here’s one that doesn’t care what format the other date is in (e.g. “Sep 26, 1989”). It could come in handy should the format change.
if (date('m/d') === date('m/d', strtotime($date))) {
echo 'same as today';
} else {
echo 'not same as today';
}
this will retrieve the date in the same format:
$today = date('m/d');
Use this:
$my_date = YOUR_ARRAY[date];
$my_date_string = explode('/', $my_date);
$curr_date = date('m,d,o');
$curr_date_string = explode(',', $date);
if (($my_date_string[0] == $curr_date_string[0]) && ($my_date_string[1] == $curr_date_string[1]))
{
DO IT
}
This way, you convert the dates into strings (day, month, year) which are saved in an array. Then you can easily compare the first two elements of each array which contains the day and month.
You can use for compare duple conversion if you have a date.
$currentDate = strtotime(date('m/d',time())); --> returns current date without care for year.
//$someDateTime - variable pointing to some date some years ago, like birthday.
$someDateTimeUNIX = strtotime($someDateTime) --> converts to unix time format.
now we convert this timeunix to a date with only showing the day and month:
$dateConversionWithoutYear = date('m/d',$someDateTimeUNIX );
$dateWithoutRegardForYear = strtotime($dateConversionWithoutYear); -->voila!, we can now compare with current year values.
for example: $dateWithoutRegardForYear == $currentDate , direct comparison
You can convert the other date into its timestamp equivalent, and then use date() formatting to compare. Might be a better way to do this, but this will work as long as the original date is formatted sanely.
$today = date('m/Y', time());
$other_date = date('m/Y', strtotime('04/06/1989'));
if($today == $other_date) {
//date matched
}
hi you can just compare the dates like this
if(date('m/d',strtotime($array['date']])) == date('m/d',strtotime(date('Y-m-d H:i:s',time()))) )

Looping through dates until a free one is found

I have a function which checks my database to see if a date exists, if it does exist, i want to display the next date which isnt in the database.
Is this possible?
My function returns 1 if there is a date in the database and 0 if there isnt, im using codeigniter, but not using any built in functions.
Its basically an availability checker, it allows us to input many different dates in the database, so calling my function i use
$availcheck = $ci->availability->check_availability_by_date(date('d/m/Y'));
The i use a if statement to check if the first time it runs it returns a value, this is how i have it
if($availcheck > 0){
// loop through the next dates and run the function again to see if it returns 0
} else {
echo 'available now';
}
I guess i would add 1 to the current date, check that one, then add another 1 and check that and so on.
Im just not sure how.
Cheers,
if i understand you correct , your problem is adding the day ?
if so i would suggest using the epoch or unix time
so convert the date to unix time using mktime than just add 1 day in seconds (24*60*60)
and then convert back to d/m/y format.
you can use the date function.
$date = time(); // get current timestamp
while ($availcheck) // while date IS found in database
{
$availcheck = $ci->availability->check_availability_by_date(date('d/m/Y',$date));
$date = $date + (24*60*60); // add one day
}
$date = $date - (24*60*60); // reduce one day
echo date('d/m/Y',$date); // prints the first date that is not in the DB
This SQL code could work for me.
$today = date("Y-m-d"); //today
$sql = "SELECT date FROM calendar WHERE date>'{$today}' AND date<='2100-12-31' AND date='0000-00-00' LIMIT 1";
Since you can't determine the ending date, 2100 could be for testing.

Categories