I'm in need of help with the PHP date/time function.
Using de date/time function, I need to print the following:
Today is 'current day', the 'number of day of month', in the year 'year'. Today is 'number of day of the year'. We still have 'number of days till end of year'.
Just can't get this working.. any ideas?
Thanks!
Alright so there may be a better way to do this, but this is one way of getting all the different elements you asked for:
$d = new DateTime();
$currentDay = $d->format('l'); // Will give you the current day in full (i.e. Monday)
$dayOfMonth = $d->format('j'); // Will give you the current day of the Month
$year = $d->format('Y'); // Will give you the current Year.
$dayOfYear = ($d->format('z') + 1); // Starts at 0, so we add one to get the actual days past.
As for the days left, I reckon there is potentially a better way to do this, but here's a quick solution:
$daysInYear = 365;
if ($d->format('L') === 1) { // Returns 1 if leap year.
$daysInYear = 366;
}
$daysLeft = $daysInYear - $dayOfYear;
That should give you all the variables you need to print out the statement you asked for.
Related
I need to determine what day of the week a given date is, and what occurrence of that day of week it is in the given date's month.
The 3rd Sunday in January, 2017 is the 15th. I know this by looking at a calendar. But given I only know the exact date, how can I figure out it's the 3rd Sunday programmatically?
Determining the actually day of week is pretty easy by loading the date into PHP and formatting it to output the day:
$day_of_week = date('l', $timestamp);
It's the other part I can't quite figure out.
Try this which works out the current day or you could set any other valid timestamp to $timestamp:
<?php
date_default_timezone_set('UTC');
$timestamp = time();
$day_of_week = date('l', $timestamp);
$day_of_the_month = date('j', $timestamp);
$occurence = ceil($day_of_the_month / 7);
$suffix = 'th';
if($occurence == 3){
$suffix = 'rd';
} else if($occurence == 2){
$suffix = 'nd';
} else if($occurence == 1){
$suffix = 'st';
}
print 'It is the '.$occurence.$suffix.' '.$day_of_week.' of this month';
?>
I see no better way than just looping throught the full month and counting which on them is sunday. I would also recommend you to use a library like Carbon (Carbon oficial docs)
So, your code should be doing:
You collect you date
$dt = Carbon::createFromDate(2012, 10, 6);
A Carbon date object has a property called "dayOfWeek", so no more hassle here
if ($dt->dayOfWeek === Carbon::SATURDAY) {
}
#CBroe is actually better. You can just just divide by 7 your week number (no decimals) and add 1 to the result, that's the ocurrence.
PD: Sorry, I got no PHP editor nor access to my development PC
I have a database with different workdates, and I have to make a calculation that generates more dates based on a weekinterval (stored in the database) and the (in the database stored) days on which the workdays occur.
What my code does now is the following:
Read the first two workdates -> Calculate the weeks inbetween and save the week interval
Read all the workdates -> fill in the days on which a workdate occurs and save it in a contract.
Generate workdates for the next year, based on the week interval.
The point is: for each week with a week interval of 1, more days of the week should be saved as a workdate. I've used this code to do this, but it doesn't work.
// Get the last workdate's actdate.
$workdate_date = $linked_workdate['Workdate']['workdate_actdate'];
// Calculate the new workdate's date
$date = date("Y-m-d", strtotime($workdate_date . "+" . $interval . " week"));
// If 'Monday' is filled in for this contract, calculate on which day the
// Monday after the last interval is. Same for each day, obviously.
// The days are boolean.
if ($contract['Contract']['contract_maandag'] = 1){
$date = date("Y-m-d", strtotime($date, "next Monday"));
}
if ($contract['Contract']['contract_dinsdag'] = 1){
$date = date("Y-m-d", strtotime($date, "next Tuesday"));
}
// After this, save $date in the database, but that works.
Here is the error that i get:
strtotime() expects parameter 2 to be long, string given
I'm quite stuck right now, so help is appreciated!
if ($contract['Contract']['contract_maandag'] = 1){
if ($contract['Contract']['contract_dinsdag'] = 1){
This won't work. You're doing an assignment (=), so it's always true. But you want a comparison (===). It is recommended to do always (except required otherwise) to use strict (===) comparison.
Well, the = doesn't seem to be the problem, since the error is about the part that's after the comparison. Try
strtotime("$date next Monday");
I'm trying to use DateTime to check if a credit card expiry date has expired but I'm a bit lost.
I only want to compare the mm/yy date.
Here is my code so far
$expmonth = $_POST['expMonth']; //e.g 08
$expyear = $_POST['expYear']; //e.g 15
$rawExpiry = $expmonth . $expyear;
$expiryDateTime = \DateTime::createFromFormat('my', $rawExpiry);
$expiryDate = $expiryDateTime->format('m y');
$currentDateTime = new \DateTime();
$currentDate = $currentDateTime->format('m y');
if ($expiryDate < $currentDate) {
echo 'Expired';
} else {
echo 'Valid';
}
I feel i'm almost there but the if statement is producing incorrect results. Any help would be appreciated.
It's simpler than you think. The format of the datess you are working with is not important as PHP does the comparison internally.
$expires = \DateTime::createFromFormat('my', $_POST['expMonth'].$_POST['expYear']);
$now = new \DateTime();
if ($expires < $now) {
// expired
}
You can use the DateTime class to generate a DateTime object matching the format of your given date string using the DateTime::createFromFormat() constructor.
The format ('my') would match any date string with the string pattern 'mmyy', e.g. '0620'. Or for dates with 4 digit years use the format 'mY' which will match dates with the following string pattern 'mmyyyy', e.g. '062020'. It's also sensible to specify the timezone using the DateTimeZone class.
$expiryMonth = 06;
$expiryYear = 20;
$timezone = new DateTimeZone('Europe/London');
$expiryTime = \DateTime::createFromFormat('my', $expiryMonth.$expiryYear, $timezone);
See the DateTime::createFromFormat page for more formats.
However - for credit/debit card expiry dates you will also need to take into account the full expiry DATE and TIME - not just the month and year.
DateTime::createFromFormat will by default use todays day of the month (e.g. 17) if it is not specified. This means that a credit card could appear expired when it still has several days to go. If a card expires 06/20 (i.e. June 2020) then it actually stops working at 00:00:00 on 1st July 2020. The modify method fixes this. E.g.
$expiryTime = \DateTime::createFromFormat('my', $expiryMonth.$expiryYear, $timezone)->modify('+1 month first day of midnight');
The string '+1 month first day of midnight' does three things.
'+1 month' - add one month.
'first day of' - switch to the first day of the month
'midnight' - change the time to 00:00:00
The modify method is really useful for many date manipulations!
So to answer the op, this is what you need — with a slight adjustment to format to cater for single digit months:
$expiryMonth = 6;
$expiryYear = 20;
$timezone = new DateTimeZone('Europe/London');
$expiryTime = \DateTime::createFromFormat(
'm-y',
$expiryMonth.'-'.$expiryYear,
$timezone
)->modify('+1 month first day of midnight');
$currentTime = new \DateTime('now', $timezone);
if ($expiryTime < $currentTime) {
// Card has expired.
}
An addition to the above answers.
Be aware that by default the days will also be in the calculation.
For example today is 2019-10-31 and if you run this:
\DateTime::createFromFormat('Ym', '202111');
It will output 2021-12-01, because day 31 does not exist in November and it will add 1 extra day to your DateTime object with a side effect that you will be in the month December instead of the expected November.
My suggestion is always use the day in your code.
For op's question:
$y=15;
$m=05;
if(strtotime( substr(date('Y'), 0, 2)."{$y}-{$m}" ) < strtotime( date("Y-m") ))
{
echo 'card is expired';
}
For others with full year:
$y=2015;
$m=5;
if(strtotime("{$y}-{$m}") < strtotime( date("Y-m") ))
{
echo 'card is expired';
}
Would it not be simpler to just compare the string "201709" to the current year-month? Creating datetime objects will cost php some effort, I suppose.
if($_POST['expYear']. str_pad($_POST['expMonth'],2,'0', STR_PAD_LEFT ) < date('Ym')) {
echo 'expired';
}
edited as Adam states
The best answer is provided by John Conde above. It it does the minimum amount of processing: creates two correct DateTime objects, compares them and that's all it needs.
It could work also as you started but you must format the dates in a way that puts the year first.
Think a bit about it: as dates, 08/15 (August 2015) is after 12/14 (December 2014) but as strings, '08 15' is before '12 14'.
When the year is in front, even as strings the years are compared first and then, only when the years are equal the months are compared:
$expiryDate = $expiryDateTime->format('y m');
$currentDate = $currentDateTime->format('y m');
if ($expiryDate < $currentDate) {
echo 'Expired';
} else {
echo 'Valid';
}
Keep it simple, as the answer above me says except you need to string pad to the left:
isCardExpired($month, $year)
{
$expires = $year.str_pad($month, 2, '0', STR_PAD_LEFT);
$now = date('Ym');
return $expires < $now;
}
No need to add extra PHP load using DateTime
If you are using Carbon, which is a very popular Datetime extension library. Then this should be:
$expMonth = $_POST['month'];
$expYear = $_POST['year'];
$format_m_y = str_pad($expMonth,2,'0', STR_PAD_LEFT).'-'.substr($expYear, 2);
$date = \Carbon\Carbon::createFromFormat('m-y', $format_m_y)
->endOfMonth()
->startOfDay();
if ($date->isPast()) {
// this card is expired
}
Also take into consideration the exact date and time expiration:
Credit cards expire at the end of the month printed as its expiration date, not at the beginning. Many cards actually technically expire one day after the end of that month. In any case, unless they list a specific day of expiration along with month and year, they should work all the way through the end of their expiration month. Cardholders should not wait until the last moment to secure a replacement card. Source
I need to look at the contents of a string and determine what the day most closely following today would be.
For example. lets say I have a string called $available_day_list with the value "monday, thursday, friday, saturday,."
According to the list above, If today was tuesday, I would like to display "thursday."
If today was saturday, I would like to display "tuesday."
I am getting the value of today with:
$current_day = date("l");
$current_day = strtolower($current_day);
Anyone know how I might be able to do this without an array? Thanks all!!
Try this:
$days = explode(',',$available_day_list);
$closestDay = '';
$minTime = 620000;// more than a week
foreach($days as $day){
$diff = strtotime('next '.$day) - time();
if($diff < $minTime){
$closestDay = $day;
$minTime = $diff;
}
}
echo $closestDay;
(i know, should've been written as a comment, but can't yet) Yotam's code turns the string into an array. And it works great, I'm not sure why you don't want to use arrays.
If you really don't though, you'll basically have to determine the current day, and then search through the string for the next day, and if not the next, and so on, until you find one.
The DateTime class in PHP (5.3+) works just great as long as the first day of the week in your country is Sunday. In the Netherlands the first day of the week is Monday and that just makes the class useless for building a calendar with week view and calculations.
I can't seem to find an answer on Stackoverflow or the rest of the Internet on how to have DateTime act as if the first day of the week is Monday.
I found this piece on Stackoverflow, but it doesn't fix all the ways you can get into trouble and it's not an elegant solution.
$dateTime = new DateTime('2012-05-14');
$monday = clone $dateTime->modify(('Sunday' == $dateTime->format('l')) ? 'Monday last week' : 'Monday this week');
Is there a way to change this or extent DateTime? Can't imagine it's not a setting as most of Europe starts their weeks on monday.
Added:
Posting the full calendar and functions code will not make things clearer. But here is one one line for example.
I often have to check what the first day of the week is or calculate from the first day of the week to a different date and time in that week. My code is getting full of these:
$startOfWeek = $date->modify(('Sunday' == $date->format('l')) ? 'Monday last week' : 'Monday this week')->modify('+3 hours')->format(DATETIME);
I also get an unwanted result trying to get the first full week of the month or year. As my $date object doesn't always contain the same date I have to keep checking it this way, making the code difficult to read. Having a lot more programming to do on this calendar I can't forsee where it's going to bug again.
EDIT There are some inconsistencies though. For some strange reason DateTime does get this next one right:
$test = new DateTime('2012-10-29'); // Monday
echo $test->modify('Sunday this week')->format('Y-m-d'); // 2012-11-04
// But...
$test = new DateTime('2012-11-04'); // Sunday
echo $test->modify('Monday this week')->format('Y-m-d'); // 2012-11-05 instead of 2012-10-29
But I think I can make the question clearer:
Can the DateTime() class be used with monday as the first day of the week. If not, can the class be extended to use monday as the first day of the week.
UPDATE:
Ok, I think I'm getting somewhere... I'm not a pro at coding classes..but this seems to work for the weeks. But it still needs rules for first day, second day... and also for the day name Sunday itself. I don't think this is foolproof. I would appreciate any help to fix it.
class EuroDateTime extends DateTime {
// Fields
private $weekModifiers = array (
'this week',
'next week',
'previous week',
'last week'
);
// Override "modify()"
public function modify($string) {
// Search pattern
$pattern = '/'.implode('|', $this->weekModifiers).'/';
// Change the modifier string if needed
if ( $this->format('N') == 7 ) { // It's Sunday
$matches = array();
if ( preg_match( $pattern, $string, $matches )) {
$string = str_replace($matches[0], '-7 days '.$matches[0], $string);
}
}
return parent::modify($string);
}
}
// This works
$test = new EuroDateTime('2012-11-04');
echo $test->modify('Monday this week')->format('Y-m-d');
// And I can still concatenate calls like the DateTime class was intended
echo $test->modify('Monday this week')->modify('+3 days')->format('Y-m-d');
I found this to work, yet there are some inconsistencies in PHP's DateTime class.
If the departing date is a sunday the previous monday is not considered the same week (fixed by this class). But departing from a monday, the next sunday is considered as the same week. If they fix that in the future this class will need some additions.
class EuroDateTime extends DateTime {
// Override "modify()"
public function modify($string) {
// Change the modifier string if needed
if ( $this->format('N') == 7 ) { // It's Sunday and we're calculating a day using relative weeks
$matches = array();
$pattern = '/this week|next week|previous week|last week/i';
if ( preg_match( $pattern, $string, $matches )) {
$string = str_replace($matches[0], '-7 days '.$matches[0], $string);
}
}
return parent::modify($string);
}
}
There's nothing to stop you manually modifying a date to get the "first" day of the week, depending on your definition of "first". For instance:
$firstDayOfWeek = 1; // Monday
$dateTime = new DateTime('2012-05-16'); // Wednesday
// calculate how many days to remove to get back to the "first" day
$difference = ($firstDayOfWeek - $dateTime->format('N'));
if ($difference > 0) { $difference -= 7; }
$dateTime->modify("$difference days");
var_dump($dateTime->format('r')); // "Mon, 14 May 2012 00:00:00 +0000"
Notice how the output changes as you vary $firstDayOfWeek; if it was changed to 4 above (Thursday), it would then consider Thu, 10 May 2012 as the "first" day.
Edit: this is a rather basic example. The correct way to do this is by using the user/system's locale to give you the "first" day, and compute from there. See this question for more information.
You can also get the start and the end of the week with setISODate, the last parameter is the ISO-daynumber in the week, monday is 1 and sunday 7
$firstday = new \DateTime();
$lastday = clone($firstday);
$firstday->setISODate($firstday->format("Y"),$firstday->format("W"),1);
$lastday->setISODate($firstday->format("Y"),$firstday->format("W"),7);
I too am confused about what the problem is, because DateTime does have a notion of the week starting from Monday: The N format gives you the days of the week counting from Monday to Sunday, with Monday being 1 and Sunday being 7. Moreover, the W format, the only way to get a week number, also starts the week on Monday. (I seem to remember that Dutch week numbers aren't exactly like ISO week numbers, but that's a different story). So what feature are you missing exactly?
Edit So the problem is (only?) that the relative datetime formats, such as "Monday this week" give the wrong result when the reference date is a Sunday. From the docs it sounds like DateTime just defers to strtotime, which is supposed to be locale-dependent. So if you have your locale set properly and this is not working, it sounds like a bug (for what that's worth).
The proper answer:
$week_start_day; // 0 - Sunday, 1 - Monday
$date_time_from = new DateTime('now');
$date_time_to = clone $date_time_from;
$this_week_first_day = $date_time_from->setISODate($date_time_from->format("Y"), $date_time_from->format("W"), $week_start_day);
$this_week_last_day = $date_time_to->setISODate($date_time_to->format("Y"), $date_time_to->format("W"), (6 + $week_start_day));