Sometimes I'm unable to format an Excel cell data as date using $date wiht format 'yyyy-mm-dd' (eg. 2017-07-12)
if ($date != '') {
$t_date = PhpOffice\PhpSpreadsheet\Shared\Date::stringToExcel($date);
$sheet->setCellValueByColumnAndRow($column,$row, $t_date);
$sheet->getStyleByColumnAndRow($column,$row)->getNumberFormat()->setFormatCode(PhpOffice\PhpSpreadsheet\Style\NumberFormat::FORMAT_DATE_DDMMYYYY);
}
The previous code fails when a $date is not valid (eg. 0000-00-00), and keeps failing in all sequent applies.
My solution is
if ($date != '') {
$t_date = PhpOffice\PhpSpreadsheet\Shared\Date::stringToExcel($date);
if ($t_date !== false) {
$sheet->setCellValueByColumnAndRow($column,$row, $t_date);
$sheet->getStyleByColumnAndRow($column,$row)->getNumberFormat()->setFormatCode(PhpOffice\PhpSpreadsheet\Style\NumberFormat::FORMAT_DATE_DDMMYYYY);
$sheet->getStyleByColumnAndRow($column,$row)->getFont()->setBold(true);
$sheet->getStyleByColumnAndRow($column,$row)->getFont()->setBold(false);
}
}
Settting and unsetting the bold stile kwwpd working the setFormatCode in moste fo the cases ... I do not know why.
Related
I have a csv that has a series of dates in it. I've taken the dates and moved them into an array($data). Specifically the data for the dates are $data[0]. I'm trying to convert them from the m/d/Y way to the UTF (Y/m/d) while writing that data to another csv(which will be the target for inserting into a db). Here's what i've tried to far:
$dt = date('Y/m/d', strtotime($data[0])); //Didn't work
//Then i tried this:
$dt = DateTime::CreateFromFormat('m/d/Y', $data[0]);
$dt = $dt->format('Y/m/d');
The second function doesn't work as i get an error: "Call to a member function format() on boolean".
I'm not sure why i'm getting that error. Some help would be greatly appreciated.
Edit: Adding code to show the writing to csv. This isn't every single possible line i used but as a quick note I'm using glob to put files into an array(csvs).
foreach($files as $file)
{
if(($handle = fopen($file, "r")) !== FALSE)
{
preg_match("/^.*([0-9]{4}-[0-9]{2}-[0-9]{2}).-.([0-9]{4}-[0-9]{2}-[0-9]{2}).*/", $file, $matches);
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE)
{
if($data[0] != preg_match("/^.*([0-9]{2}-[0-9]{2}-[0-9]{4}).*/", $file))
{
$num = count($data);
$row++;
if(!file_exists($filename))
{
$newFile = fopen($filename, "w");
fputcsv($newFile, $headers);
}
if(strlen($data[0]) == 9 || strlen($data[0]) == 10)
{
$dt = DateTime::CreateFromFormat('m/d/Y', $data[0]);
$dt = $dt->format('Y/m/d');
}else{
$dt = $data[0];
echo "Something went wrong. Check the csv";
}
fputcsv($newFile, [$defaults[0], $defaults[1], $defaults[2], $defaults[3], $defaults[4], $defaults[5], $defaults[6], $defaults[7],$defaults[8],$dt, $data[1], $data[4], $data[14], $data[7], $data[2], $data[3], $data[5], $data[6]]);
}
}
}
fclose($handle);
fclose($newFile);
}
Basically what this does is match files that have a date range in their name, store that date range in matches, check the specific rows to see if a row to find the m/d/Y row to start placing data in the new csv. Again its not every possible line of code but i think this would give you a good idea of what im doing. In the fputcsv you can see $dt there instead of data[0].
This is wrong:
if(strlen($data[0] == 9) || strlen($data[0] == 10))
== should not be inside the call to strlen(). It should be
if(strlen($data[0]) == 9 || strlen($data[0]) == 10)
Because of this, you're never going into that if block, so it never fixes up $dt.
Also, you need to assign $dt when this if test fails, so you should have:
else {
$dt = $data[0];
}
This line also makes no sense to me:
if($data[0] != preg_match("/^.*([0-9]{2}-[0-9]{2}-[0-9]{4}).*/", $file))
preg_match() returns the number of matches that were found. $file is the filename, so this is the number of times a date-like pattern is in the filename. $data[0] is the contents of the first field in the CSV -- either a date or the field heading for dates. Unless this field contains a number, it will never be equal to the result of preg_match(), so this condition will always succeed. If your intent was to skip the heading line, it won't do that, so the new file will contain headings.
If you want to test if the first field contains a date, use:
if (preg_match('/([0-9]{2}-[0-9]{2}-[0-9]{4})/', $data[0]))
BTW, there's no need for .* when matching, it matches anywhere in the string when there's no anchors.
Ahhh..... I figured it out. I'm a big fool. Excel is a parser that's just automatically tuning itself to fit the way it would be read when looking at the average excel file(american format). When i look at the data through a text editor, it shows the date formatted the way it should be. That means that with another script i'd be able to target the data properly.
I am troubleshooting a search bar to return rows within a period chosen from 'To' and 'From' datepickers.
I initially got this error :
Error: Method Doctrine\ORM\Query\Expr\Comparison::__toString() must not throw an exception, caught Symfony\Component\Debug\Exception\ContextErrorException: Catchable Fatal Error: Object of class DateTime could not be converted to string
I converted the relevant query to a string using ->format() function:
if (is_array($value) && isset($value['to'])) {
$to = \DateTime::createFromFormat('d/m/Y H:i:s', $value['from'] . ' 23:59:59');
var_dump($value, $to);die;
if ($to <> false) {
$query->andWhere(
$query->expr()->lte($path, $to->format('Y-m-d H:i:s'))
);
}
}
Now doctrine throws the following error:
[Syntax Error] line 0, col 977: Error: Expected end of string, got '00'
Is there something else I need to do to format the date to make it acceptable to the querybuilder? I've tried using / instead of : but this causes an issue.
If I recall correctly, you should either use literal(), or query parameter. And since the lte argument is not constant, using literal() is highly discouraged (due to potential SQL injection).
Anyway, something like this should probably work:
if (is_array($value) && isset($value['to'])) {
if (is_array($value) && isset($value['to'])) {
$to = \DateTime::createFromFormat('d/m/Y H:i:s', $value['from'] . ' 23:59:59');
if ($to <> false) {
$query->andWhere($query->expr()->lte($path, ':to'));
$query->setParameter('to', $to->format('Y-m-d H:i:s'));
}
}
Does it work?
Hope it helps...
I have created a new date column and it defaults it to 0000-00-00 and I want to check if it has a valid date or all zeros, but none of these codes seem to work for me and I can't figure out why. I know it sees the date, cause when I echo it, it displayed as zeros. How do I check to see if the date column is 0000-00-00? Here is what I tried and none of them have worked.
if (trim($row['date']) == '' || substr($row['date'],0,10) == '0000-00-00') {
// empty date
}
if (strtotime($row['date']) == '0000-00-00'){
// empty date
}
if ($row['date'] == '0000-00-00'){
// empty date
}
EDIT
Looks like it might just be a problem with my godaddy hosting server, I uploaded the files to a free webhosting and solution 3 is working over there. Sorry to waste everyone's time, I do appreciate the quick responses.
You can check the following condition instead of yours...
There strtotime() return false if that not contains a specific date string or for proper check of empty string you can use empty() function and for check that string contains '0000-00-00' like data then you can use strpos() as like the below code:
if(empty(trim($row['date'])) || (strpos($row['date'], '0000-00-00') !== false) || (!strtotime($row['date'])))
{
// empty date
}
If we aren't sure about how the date is being returned, try using date and strtotime together to ensure correct format:
if (date('Y-m-d', strtotime($row['date'])) > '0000-00-00'){
//Valid
}
Simply use empty() with strtotime will check all the empty cases
<?php
$row['date'] = '0000-00-00';
if(empty(strtotime($row['date']))){
// empty date
}
else{
//not empty date
}
If about your 3 condition it should be like below instead of using if ladder use else if and In 2nd condition your are comparing timestamp integer(strtotime will return int seconds) to the string date('0000-00-00') that is in correct
<?php
$row['date'] = '0000-00-00';
if (trim($row['date']) == '' || substr($row['date'],0,10) == '0000-00-00') {
// empty date
}
else if(strtotime($row['date']) == strtotime('0000-00-00')){
// empty date
}
else if ($row['date'] == '0000-00-00'){
// empty date
}
This question already has answers here:
My pattern isn't matching a ISO style date, why? [duplicate]
(3 answers)
Closed 7 years ago.
apologies for probably a simple question, but i am new to PHP and Javascript.
I am creating a login validation in PHP that requires a registering user to input their date of birth in a DD/MM/YYYY Format, that returns an error message if the date is entered in any other format. I am unsure how to do this, other than using preg_match, however this doesnt seem to work...
variables:
$DOB = $_POST['DOB'];
$error_message = '';
The Date Validation Segment
elseif (!preg_match("/^(0?[1-9]|[12][0-9]|3[01])\/\.- \/\.- \d{2}$/", $DOB))
{
$error_message = 'Invalid Date';
}
Error Display
if ($error_message != '')
{
echo 'Error: '.$error_message.' Go Back.';
echo '</body> </html>';
exit;
}
else
{
echo'<p><strong>Form Submitted Successfully!</strong></p>';
}
This is not a duplicate, i tried other threads and none of their solutions worked.
You should use more than a regular expression. For example, you should not allow something like 31/02/2015, because there's no 31th in February!
I have a function that works well:
function isDate($string) {
$matches = array();
$pattern = '/^([0-9]{1,2})\\/([0-9]{1,2})\\/([0-9]{4})$/';
if (!preg_match($pattern, $string, $matches)) return false;
if (!checkdate($matches[2], $matches[1], $matches[3])) return false;
return true;
}
It first uses preg_match to check for the formal validity of DD/MM/YYYY, grabbing DD, MM and YYYY portions into the $matches array. Then it check the validity of the date itself using the built-in PHP function checkdate.
You can use that in your code like:
if (!isDate($DOB)) {
$error_message = 'Invalid Date';
}
string_explode given string and then pass parts of it to
bool checkdate ( int $month , int $day , int $year )
unfortunately you cannot know if user posted month and day in your format if day is not greater than 12
You can do it like this in PHP:
$date=explode("/",$_POST['DOB']);
if(checkdate ($date[1] ,$date[0] ,$date[2]))
{
echo "valid";
}
else
{
echo "invalid";
}
checkdate will only return true if the three value behind "/" is valid, so if there's no "/" its invalid, same as they put numbers in wrong order.
check manual http://php.net/manual/en/function.checkdate.php
I have an online form that has a few fields with time data. I store this data into the MySQL data base into a time field, which needs a format hh:mm:ss. If the user inputs the time in this format correctly, then i want to accept the data. I also want to allow users to input the time in standard US time, like 9:30 am or 11:25 pm or 10:27 am etc.
Basically I want to test if the time is in the proper database format first (hh:mm:ss), then if it is not, test if it is in the second accepted format (hh:mm am/pm), and if it is, then I will use the PHP function strtotime() to convert it into the database time format. If it is in neither of these formats, then we display an error message and die.
Does anyone know how to test if the value of a variable matches one of these time formats?
Pseudo PHP code of what I want to do:
<?php
$value = //some time;
if (is_database_time($value)){
// good no problem
}else if (is_usa_time($value)){
$value = strtotime($value);
}else{
die("error incorrect time format, try again.");
}
?>
** EDIT **
Thanks everyone for the help. I used some of the info here to make a function that works perfectly:
<?php
function filter_time($key,$value){
// this section handles the storage of time data
if (preg_match('/^(0?\d|1\d|2[0-3]):[0-5]\d:[0-5]\d$/', $value)){
//do nothing
}else if (preg_match('/^(0?\d|1[0-2]):[0-5]\d\s(am|pm)$/i', $value)){
$value = date( 'H:i:s', strtotime($value));
}else{
display_error('incorrect time format in '.$key.' field.');
}
return $value;
}
?>
function verify_time_format()
function verify_time_format ($value) {
$pattern1 = '/^(0?\d|1\d|2[0-3]):[0-5]\d:[0-5]\d$/';
$pattern2 = '/^(0?\d|1[0-2]):[0-5]\d\s(am|pm)$/i';
return preg_match ($pattern1, $value) || preg_match ($pattern2, $value);
}
Returns TRUE for following values:
2:03:32
02:03:32
23:59:59
15:23 AM
15:23 am
09:41 pm
9:41 PM
etc...
Update:
function filter_time ($key, $value) {
$p1 = '/^(0?\d|1\d|2[0-3]):[0-5]\d:[0-5]\d$/';
$p2 = '/^(0?\d|1[0-2]):[0-5]\d\s(am|pm)$/i';
if (preg_match ($p1, $value) || preg_match ($p2, $value))
$res = date ('H:i:s', strtotime ($value));
else
display_error ("incorrect time format in {$key} field.");
return $res;
}
You're already using the strtotime from PHP, and for the values you specified there really is no need to force a specific format.
What you would likely want to test for and ensure, is that the field validates with only digits, the colon, and am or pm as in Wh1T3h4Ck5 answer.
With that in place, your code would likely be similar to the following
<?php
function valid_time($value) {//Wh1T3h4Ck5's function
return preg_match('/^(0?\d|1[0-2]):[0-5]\d\s(am|pm)$/i', $value);
}
$value = //some time;
if (vald_time($value)){
$time_value = strtotime($value);
echo $time_value;
}else{
die("Error incorrect time format, try again.");
}
?>
Though a more elegant solution would to look into using Jquery/Javascript PRIOR to the form being submitted. You can test and warn the user of improper format before submitting to the PHP script. Leave the validation in the PHP script though as well, with other safeguards if needed.
You can use a regular expression to solve the problem pretty easily. For example:
<?php
$databaseTimePattern = '/^(0[0-9])|(1[0-2]):[0-5][0-9]:[0-5][0-9]$/'; //Matches times in the form hh:mm:ss
$usaTimePattern = '/^([1-9]|(1[0-2])):[0-5][0-9] [a|p]m$/'; //Matches times in the form hh:mm am/pm
$value = //some time;
if (preg_match($databaseTimePattern, $value)){
// good no problem
}else if (preg_match($usaTimePattern, $value)){
$value = strtotime($value);
}else{
die("error incorrect time format, try again.");
}
?>