This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How would I get the birthdays of friends who are celebrating their birthday this week, this month and next month using MYSQL and PHP?
I have a mysql table of users with fields UserId, Username, Birthdate (format YYYY-MM-DD). I want to display something on my homepage like this:
Upcoming birthdays:
Fred Smith 24 Aug
Bill Jones 27 Aug
Sarah Connor 1 Sep
David Cassidy 5 Sep
You get the idea - it generates a short list of which birthdays are coming up next, ignoring the year, just based on the day and month. I just have no idea how to do the query - any help would be appreciated!
You can use the mysql DATE_FORMAT() function. This should give you all the birthdays between the current day, and 7 days from now:
SELECT username, DATE_FORMAT(Birthdate,'%M %d') as 'birthday' FROM table WHERE DATE_FORMAT(Birthdate,'%m-%d') BETWEEN DATE_FORMAT(CURDATE(),'%m-%d') AND DATE_FORMAT(ADDDATE(NOW(), INTERVAL 7 DAY), '%m-%d') ORDER BY DATE_FORMAT(Birthdate,'%m-%d');
Another option is to create a function that will sit in a helper class, or go into your user class perhaps:-
/**
* Fetches a list of birthdays coming up in the following week
* #return array an array user's birthdays
*/
public function getBirthdays()
{
$date = new DateTime();
$date->setTime(0, 0, 1);
$today = $date->getTimestamp();
$week = new DateInterval('P7D');
$date->add($week);
$date->setTime(23, 59, 59);
$nextWeek = $date->getTimestamp();
$select = new Zend_Db_Select(Zend_Db_Table::getDefaultAdapter());
$select ->from('users', array('user_name', 'user_dob'))
->where('user_dob > ?', $today)
->where('user_dob < ?', $nextWeek);
return $select->query()->fetchAll();
}
Then you just do:-
$birthdays = $classYouMade->getBirthdays();
$html = '';
foreach($birthdays as $bday){
$html .= "Happy Birthday to {$bday['user_name']} on ";
$html .= date('jS F', $bday['user_dob']) . '<br/>';
}
echo $html;
It's quite long, but is self documenting (I think) and you can come back to it in a year's time and see exactly what is happening at a glance.
I have ofcourse made some assumptions about how you are storing date etc (I always use unix timestamps), but I'm sure you can adapt it to your use case if you wish to use it.
First, you need to retrieve a list of your users as follow:
$adapter = Zend_Db_Table::getDefaultAdapter()
$table = $adapter->getDbTable()
$select = $table->select();
$select->where('active = ?', true); // if needed
$user = $table->fetchAll($select);
Your getDbTable would be something very similar to the one in Zend Quickstart :
public function setDbTable($dbTable)
{
if (is_string($dbTable)) {
$dbTable = new $dbTable();
}
if (! $dbTable instanceof Zend_Db_Table_Abstract) {
throw new Exception('Invalid table provided');
}
$this->_dbTable = $dbTable;
return $this;
}
public function getDbTable()
{
if (null === $this->_dbTable) {
$this->setDbTable('My_Users_DbTable_User');
}
return $this->_dbTable;
}
And in My/Users/DbTable/User a simpla class that contains:
class My_Users_DbTable_User extends Zend_Db_Table_Abstract
{
protected $_name = 'users';
}
Finally, when you retrieved your data from the database, you can iterate through each row you fetched using current() and toArray()methods. See Zend_Db_Table_Row documentation for more details.
In order to display only the day and month of a birthdate, you can use Zend_Date which is pretty useful.
$date = "1970-12-10";
$d = new Zend_Date($date);
echo $d->toString(Zend_Date::DAY) . " " . $d->toString(Zend_Date::MONTH_NAME_SHORT);
// output: 10 Dec
You can query this with something like:
SELECT username, birthdate FROM table WHERE birthdate >= beginning_of_week AND birthdate <= end_of_week
You'd probably have to calculate the week range you want in whatever script you're querying from.
You should be able to get the list with a simple SQL query:
select UserId, Username, Birthdate from Users where Birthdate >= CURDATE() and Birthdate <= DATE_ADD(CURDATE(), INTERVAL + 2 WEEK) order by Birthdate ASC
Then you can format the text using DateTime::format() in PHP.
while ($row = mysql_fetch_assoc($res))
{
$birthday = new DateTime($row['Birthdate']);
print $row['Username']." ".$birthday->format('d M')."\n";
}
Related
I currently get the last 30 days results like this.
public function commission_month(){
$status = 'A';
$this->db->select_sum('LenderCommission');
$this->db->where(['Status' => $status ]) ;
$this->db->where('CompletedDate >= DATE_SUB(CURDATE(), INTERVAL 30 DAY) ');
$query = $this->db->get('toutcome');
$result = $query->result();
return $result[0]->LenderCommission;
}
What i am really trying to do is get results for this current month.
And then when its the next month , its should do the same.
You can use a "like" query to get the information you need, assuming the dates are stored in a manner you can easily apply a like to.
Basically, the query will be something along the lines of ... AND CompletedDate LIKE 'YYYY-MM-%'... where YYYY and MM are valid year and months. This can be done in CodeIgniter by using the $this->db->like() builder:
$this->db->like('CompletedDate', date('Y-m'));
Your code then being:
public function commission_month(){
$status = 'A';
$this->db->select_sum('LenderCommission');
$this->db->where(['Status' => $status ]) ;
$this->db->like('CompletedDate', date('Y-m'));
$query = $this->db->get('toutcome');
$result = $query->result();
return $result[0]->LenderCommission;
}
I want to select names which expires in this month and two months ahead.
$t=date('Y');
$q = date('m');
for($e=$q;$e<=($q+2);$e++){
$ren = $t.'-'.$e;
$sql = "select name,renewal_date from hosting_details where renewal_date LIKE '$ren%' ";
}
In this first month display correctly but then onward doesn't give any result. when i echo $ren,for the first month it gives 2016-01 and second month 2016-2.
how can i resolve this
You could simply use sprintf() to format the numbers. For example:
$t=date('Y');
$q = date('m');
for($e=$q;$e<=($q+2);$e++){
$ren = $t.'-'. sprintf("%'.02d", $e);
var_dump($ren);
}
More info on sprintf() can be found in the docs.
However since you're working with dates, why not use a \DateTime object and have it do the work for you? This means you don't have to do any date overflow logic etc - PHP does all the complex work for you! :) e.g.
$begin = new DateTime( '2016-01-11' );
$numMonths = 2;
for($i=0; $i<$numMonths; $i++)
{
// e.g. increment the month and format the date.
var_dump($begin->modify( '+1 month' )->format("Y-m-d"));
// of course modify the format to "Y-m" for your code:
// $ren = $begin->modify( '+1 month')->format("Y-m");
}
For more reading you can checkout \DateTime and \DatePeriod in the PHP docs.
Here's a working example comparing the two approaches.
Using sprintf() can solve your problem:
$t=date('Y');
$q = date('m');
for($e=$q;$e<=($q+2);$e++){
$ren = sprintf('%d-%02d', $t,$e);
$sql = "select name,renewal_date from hosting_details where renewal_date LIKE '$ren%' ";
echo $sql . "\n";
}
Output:
select name,renewal_date from hosting_details where renewal_date LIKE '2016-01%'
select name,renewal_date from hosting_details where renewal_date LIKE '2016-02%'
select name,renewal_date from hosting_details where renewal_date LIKE '2016-03%'
Edit :
Maturity date, what is it ?
I'm not native english speaker. Sorry about that. I think the best we can do, is to define Maturity Date.
A maturity date is a date that indicates the deadline for the payment
of an invoice. In BtoB, the maturity date indicates when the customer
wants to pay us, defined during the contract it is usually a later date between 1 and 3 months
after the publishing of the bill. It's a calculated data, and
implemented in my application with the following code.
I have this code in my Invoice module I extracted it for you can tests :
<?php
class Config
{
protected $amountDelayedDays;
protected $paymentDay;
protected $paymentCondition;
public function getAmountDelayedDays()
{
return $this->amountDelayedDays;
}
public function getPaymentCondition()
{
return $this->paymentCondition;
}
public function getPaymentDay()
{
return $this->paymentDay;
}
public function setAmountDelayedDays($days)
{
$this->amountDelayedDays = $days;
return $this;
}
public function setPaymentDay($days)
{
$this->paymentDay = $days;
return $this;
}
public function setPaymentCondition($condition)
{
$this->paymentCondition = $days;
return $this;
}
}
class Test {
/**
* #param DateTime $dateInvoice
* #param Config $config
* #return DateTime
*/
public function calcMaturityDate(\DateTime $dateInvoice, $config)
{
if ($config->getPaymentCondition() == 'delayed') {
$dateMaturity = clone $dateInvoice;
$startDay = $dateMaturity->format('j');
$dateMaturity->modify("+{$config->getAmountDelayedDays()} days");
$endDay = $dateMaturity->format('j');
if ($startDay != $endDay && $endDay < 30) {
$dateMaturity->modify('last day of last month');
} else {
$dateMaturity->modify('last day of this month');
}
if ($config->getPaymentDay() != 0) {
$dateMaturity->modify('+' . $config->getPaymentDay() . 'days');
}
return $dateMaturity;
} else {
return $dateInvoice;
}
}
}
$config = new Config;
$config->setPaymentDay(15);
$config->setAmountDelayedDays(60);
$config->setPaymentCondition('delayed');
$test = new Test;
$date = $test->calcMaturityDate(new DateTime('2015-01-31'), $config);
var_dump($date);
?>
I have to calculate a maturity date from the date of invoice.
If my invoice is dated at 2014-11-30 and my client is configured to be charged 2 month later & on the 15'(=60days + 15 ), I have to produce a maturity date like this :
'2015-02-15'
For doing this I have to variables in my Config class :
$config->getAmountDelayedDays() and $config->getPaymentDay()
My code is not perfect to handle all problems. February changing years, custom value of days... Jumped month...
I think the problem is in
if ($startDay != $endDay && $endDay < 30) {
$dateMaturity->modify('last day of last month');
} else {
$dateMaturity->modify('last day of this month');
}
It's too simple to handle all cases, maybe it's wrong. I can't make my mind clear about this...
Tests case
I have units test testing this function I'm not passing
/**
* Tests MaturityDate
*
*/
public function testCanGiveCorrectMaturityDate()
{
$config = $this->parser->setConfig();
$config->setAmountDelayedDays(60);
$config->setPaymentDay(15);
$config->setPaymentCondition('delayed');
// From February Ok ?
$dateInvoice = new \Datetime('2015-02-28');
$maturityDate = $this->mock->calcMaturityDate($dateInvoice , $config);
$this->assertEquals('15-05-2015', $maturityDate->format('d-m-Y'));
// From February ok ?
$dateInvoice = new \Datetime('2015-02-28');
$config->setAmountDelayedDays(30);
$config->setPaymentDay(0);
$maturityDate = $this->mock->calcMaturityDate($dateInvoice , $config);
$this->assertEquals('31-03-2015', $maturityDate->format('d-m-Y'));
// New years and pass february
$config->setAmountDelayedDays(90);
$config->setPaymentDay(15);
$dateInvoice = new \Datetime('2014-11-30');
$maturityDate = $this->mock->calcMaturityDate($dateInvoice , $config);
$this->assertEquals('15-03-2015', $maturityDate->format('d-m-Y'));
// No delayed
$config->setPaymentCondition('standard');
$dateInvoice = new \Datetime('2014-11-30');
$maturityDate = $this->mock->calcMaturityDate($dateInvoice , $config);
$this->assertEquals('30-11-2014', $maturityDate->format('d-m-Y'));
}
If I get it right, you expect the paymentDay to be always 15th day of month of maturity, or next month, when date of maturity is later than 15th.
With this assumption your class would be:
public function calcMaturityDate(\DateTime $dateInvoice, $config)
{
$dateMaturity = clone $dateInvoice;
$dateMaturity->add(new \DateInterval("P{$config->getAmountDelayedDays()}D"));
$payDay = $config->getPaymentDay();
// patch 0 payDay to last day of month
if (0 == $payDay) {
$payDay = $dateMaturity->format('t');
}
if ($dateMaturity->format('j') > $payDay) {
$dateMaturity->modify('next month');
}
$dateMaturity->setDate(
$dateMaturity->format('Y'),
$dateMaturity->format('m'),
$payDay
);
return $dateMaturity;
}
Few notes:
the class name is a bit misleading, as it returns payment date, not maturity date;
maturity interval is 60 days, not 2 months;
For the last point I would recommend to refactor your config class to return \DateInterval for maturity interval instead of integer, so you will have flexibility to define 2 month interval as "P2M" or 60 days as "P60D" depending on business requirements:
If instead of
public function getAmountDelayedDays()
{
return $this->amountDelayedDays;
}
you have
/**
* #return \DateInterval
*/
public function getDelayInterval()
{
return $this->delayInterval;
}
the ugly line from above
$dateMaturity->add(new \DateInterval("P{$config->getAmountDelayedDays()}D"));
turns to elegant
$dateMaturity->add($config->getDelayInterval());
In these cases a always convert the "friendly date" to a timestamp; do the math; then convert back to a friendly date.
Something like this:
$invoice_date = "2014-11-30";
$ts_invoice_date = time($invoice_date);
$ts_maturity_month = $ts_invoice_date + (60*24*60*60); //60 days*24hrs*60mins*60secs
$maturity_date = date("Y-m-15 00:00:00", $ts_maturity_month);
From documentation: Date and Time
date('Y-m-d', strtotime('+1 week'))
strtotime documentation
Your question:
I have to calculate a maturity date from the date of invoice.
You can use date('Y-m-d', strtotime('+60 days')) and that will handle odd/even number of days in month, as well as fix to hours (if you need that precision)..
A date 2014-11-30 with date('Y-m-d', strtotime('+ $amountDelayedDays days')) yelds the correct date.
I think i get what your trying to do and I have had to do something similar. You basically want something to determine if the current day of the month is less than 15 and if it is it remains the 15th of this month else if its say the 20th of the same month then date is 15th of next month?. I think this is how I am reading this. If this is the case then you need to compare the day of the invoice to the 15th and if less than its the same month or if its greater than then its the next month. It then gets interesting as are you allowing a leverage period of say 5 days before the due date. A factor on what I was working on I used. This could be the case if the date of the invoice was the 14th and you set payment date on the 15th. With the logic the client would only have a day to pay the invoice. I think we went with the 15th minus 5 days.
This question already has answers here:
How to calculate days between two dates in PHP?
(6 answers)
Closed 8 years ago.
I want to keep track the status if there is no shipment of product within 2 days then there is must have a notification to alert them by email to do a shipment. The shipment date can be fetch from email date but it is possible if I compare :
//MAX(date_shipment = latest date record of shipment in database
if (MAX(date_shipment) - dateNow() >= 2 days )
{
$update ="update table1 set remarks = 'No shipment received since 2 days ago', status = 'warning'";
$result = mysql_query($update);
}
else
{ }
But there is problem I thinks because this code is compare with dateNow(). How come if there is new shipment received, still the date comparison code running but not compare with this new shipment date received. I have no idea how to explain and how to start to do this function.
Can someone advise what is the right way to solve this prob? Thanks in advance
Let's try this code:
$currentDate = getdate();
$anotherDate = MAX(date_shipment); //whatever this is
//this will give sql format to the current date
$year = $currentDate['year'];
$month = $currentDate['mon'];
$day = $currentDate['mday'];
$currentDate = $year.'-'.$month.'-'.$day;
$date1 = date_create($anotherDate); //assuming your date has sql format
$date2 = date_create($currentDate);
$difference = date_diff($date1, $date2);
$difference = str_replace(" days","",$difference->format('%R%a days'));
if ($difference >= 2){
$update ="update table1 set remarks = 'No shipment received since 2 days ago', status = 'warning'";
$result = mysql_query($update);
}
else
{ } //I don't get what you want here
This seems like what you are trying to do. Do not use mysql anymore, use mysqli.
$dbDate = mysql_query("SELECT `date_shipment` FROM table1");
$addedDate = new DateTime();
$addedDate->modify('+2 day');
if ($dbDate['date_shipment'] >= $addedDate)
{
$update ="UPDATE table1 SET remarks = 'No shipment received since 2 days ago',
status = 'warning'";
$result = mysql_query($update);
}
else
{ }
I'm creating a TV Guide which lists programmes coming up (and on some listings, previous airings from the past), with all data stored in a database. It runs in PHP, my version being 5.28 (upgrading to 5.30 or 6 soon).
Below is a script which works (note the field airdate is stored as DATETIME in the database):
[Disclaimer: The script isn't mine, but a generic one I downloaded, and modified to suit my own needs.]
<? //connect to mysql //change user and password to your mySQL name and password
mysql_connect("localhost","root","PASSWORD");
//select which database you want to edit
mysql_select_db("tvguide1");
//select the table
$result = mysql_query("select * from epdata3 order by airdate LIMIT 20;");
//grab all the content
while($r=mysql_fetch_array($result))
{
//the format is $variable = $r["nameofmysqlcolumn"];
//modify these to match your mysql table columns
$programme=$r["programme"];
$channel=$r["channel"];
#$airdate = strtotime($r['airdate']);
$airdate = strtotime($r['airdate']);
$now = strtotime("NOW");
$currentYear = date("Y", $now);
$yearOfDateFromDatabase = date("Y", $airdate);
if($yearOfDateFromDatabase == $currentYear)
$dateFormat = "F jS - g:ia"; // dateFormat = 24 December
else
$dateFormat = "F jS, Y - g:ia"; // dateFormat = 01 January 2010
$currentTime = date("g:ia", $airdate); // format of "Y" gives four digit year ie
2009 not 09
$airdateFormatted = date($dateFormat, $airdate);
$sDate = date("F dS, Y - g:ia",$airdate);
$episode=$r["episode"];
$setreminder=$r["setreminder"];
echo "<tr><td><b>$programme</b></td><td>showing on $channel</td>";
echo "<td>$airdateFormatted</td><td>$episode</td><td>$setreminder</td></tr>";
}
?>
That displays all the episodes coming up, and if there's any coming up the next year, it displays them with the year, like this:
TV Programme showing next on Channel1 December 30th, 2009 - 6:00pm "Episode 1 - Photosynthesis" Set Reminder
TV Programme showing next on Channel1 January 6th - 2:45pm "Episode 2 - Behind the Music" Set Reminder
TV Programme showing next on Channel1 January 7th - 8:00pm "Ultimate Car Crimes" Set Reminder
However, what I would like it to do is remove certain records after a period of time has expired (but that would have to be set somewhere in the script, since programme lengths vary) rather than me manually deleting them from the database. Some programmes are 30 minutes long, others 60 minutes... lengths vary, basically.
What I would like it to do is this (notice that the first listing does not show the date as it is the current date.):
TV Programme showing next on Channel1 6:00pm "CCTV Cities - Wigan" Set Reminder
TV Programme showing next on Channel1 January 9th - 2:45pm "Roman Empire - A History of its People" Set Reminder
TV Programme showing next on Channel1 January 10th - 8:00pm "Celebrity 100 Worst Moments" Set Reminder
but I don't know how to configure it to do this with PHP or the date() function. It works fine with the dates, and showing them.
I don't have access to cron jobs since this is on a localhost Apache installation on Windows Vista Home Edition.
If anyone could help me figure this out it would be much appreciated - all help is much appreciated.
I haven't put this as a live site, since it's "in development hell" right now, and I want to get things right as much as possible.
Your question is a bit unclear, but I assume you are asking how you can select only episodes from today or future, and how to format the date so that when the episode is airing today, show only the date.
Here's a revised version of your code that can handle both of those:
<?php
//connect to mysql
mysql_connect("localhost","root","PASSWORD");
mysql_select_db("tvguide1");
// Select only results for today and future
$result = mysql_query("SELECT * FROM epdata3 WHERE airdate >= CURDATE() ORDER BY airdate ASC LIMIT 20;");
while($r = mysql_fetch_array($result)) {
$programme = $r["programme"];
$channel = $r["channel"];
$airdate = strtotime($r['airdate']);
$episode = $r["episode"];
$setreminder = $r["setreminder"];
$now = time();
if(date('Y-m-d') == date('Y-m-d', $airdate)) {
// Same date, show only time
$dateFormat = 'g:ia';
} elseif(date('Y') == date('Y', $airdate)) {
// Same year, show date without year
$dateFormat = 'F jS - g:ia';
} else {
// Other cases, show full date
$dateFormat = 'F jS, Y - g:ia';
}
$airdateFormatted = date($dateFormat, $airdate);
echo "<tr><td><b>$programme</b></td><td>showing on $channel</td>";
echo "<td>$airdateFormatted</td><td>$episode</td><td>$setreminder</td></tr>";
}
?>
MySQL can literally handle millions of records - why bother deleting when you can archive..? Just don't show the archived records.
for listing future records instead of this:
$result = mysql_query("select * from epdata3 order by airdate LIMIT 20;");
I would suggest something like this:
$result = mysql_query("select * from epdata3 WHERE airdate > '$today' ORDER BY airdate LIMIT 20;");
For a gig listing page I years ago also added a delete algorythm fearing the db could get 'full' - but regretted it later...
function reldate ($time) {
$now = time();
$cmp_fmt = '%Y%m%d';
if (strftime($cmp_fmt, $time) == strftime($cmp_fmt, $now)) {
$out_fmt = '%I:%M %P';
} else {
$day = strftime('%e', $time);
if (preg_match('/([^1]1|^1)$/', $day)) {
$day_suffix = 'st';
} elseif (preg_match('/([^1]2|^2)$/', $day)) {
$day_suffix = 'nd';
} elseif (preg_match('/([^1]3|^3)$/', $day)) {
$day_suffix = 'rd';
} else {
$day_suffix = 'th';
}
$out_fmt = '%B %e' . $day_suffix . ' - %I:%M %P';
}
return strftime($out_fmt, $time);
}