php not parsing date correctly - php

I need to convert 'Nov22' into a date object that is in the month of November. I am trying the following - but it only works with months with 31 days:
$novDateString = 'Nov22';
$decDateString = 'Dec22';
$novDate = DateTime::createFromFormat('My', $novDateString);
$decDate = DateTime::createFromFormat('My', $decDateString);
echo $novDate->format('m');
echo $decDate->format('m');
// output
12
12
As you can see, both Nov22 and Dec22 go to December. In fact, all months with less than 31 days go map to the month ahead of it. Is this a known issue or is there an easy way to solve?

Since you're not specifying a day, it's defaulting to today, which is the 31st:
$novDateString = 'Nov22';
$decDateString = 'Dec22';
$novDate = DateTime::createFromFormat('My', $novDateString);
// DateTime #1669926271 {#4573
// date: 2022-12-01 15:24:31.0 America/New_York (-05:00),
// }
$decDate = DateTime::createFromFormat('My', $decDateString);
//DateTime #1672518273 {#4578
// date: 2022-12-31 15:24:33.0 America/New_York (-05:00),
// }
November 31st doesn't exist, so the day becomes December 1st. You need to prepend a day before the string, and then pass in the correct format:
$novDate = DateTime::createFromFormat('jMy', '1'.$novDateString);
//DateTime #1667331673 {#4576
// date: 2022-11-01 15:41:13.0 America/New_York (-04:00),
// }

Related

How to get First and Last Day of Previous Month with Carbon - Laravel

I need First and Last Day of Previous Month using Carbon Library, what I have tried is as follows:
$firstDayofPreviousMonth = Carbon::now()->startOfMonth()->subMonth()->toDateString();
$lastDayofPreviousMonth = Carbon::now()->endOfMonth()->subMonth()->toDateString();
Result I'm getting is for$firstDayofPreviousMonth = '2016-04-01'(as current month is 5th(May)) and for $lastDayofPreviousMonth = '2016-05-01'.
I'm getting correct result for $firstDayofPreviousMonth, but it's giving me 30 days previous result, and giving me wrong result for $lastDayofPreviousMonth.
Can anyone help me out with this?
Try this:
$start = new Carbon('first day of last month');
$end = new Carbon('last day of last month');
Just try this
$firstDayofPreviousMonth = Carbon::now()->startOfMonth()->subMonth()->toDateString();
$lastDayofPreviousMonth = Carbon::now()->subMonth()->endOfMonth()->toDateString();
Updated code, which is more accurate
$firstDayofPreviousMonth = Carbon::now()->startOfMonth()->subMonthsNoOverflow()->toDateString();
$lastDayofPreviousMonth = Carbon::now()->subMonthsNoOverflow()->endOfMonth()->toDateString();
#kenfai Thanks
With this ... the date start init on 00:00 and date end finish in 23:59
$start = new Carbon('first day of last month');
$start->startOfMonth();
$end = new Carbon('last day of last month');
$end->endOfMonth();
To specifically answer your question as to why you're getting the wrong result for $lastDayofPreviousMonth.
Lets break down this statement in your example:
Carbon::now()->endOfMonth()->subMonth()->toDateString();
// Carbon::now() > 2016-05-05
// ->endOfMonth() > 2016-05-31
// ->subMonth() > 2016-04-31 // Simply takes 1 away from 5.
This leaves us with an invalid date — there is no 31st of April. The extra day is simply added on to the last valid date (2016-04-30 + 1) which rolls the date into May (2016-05-01).
As previously mentioned to be sure this never happens always reset the date to the 1st of the month before doing anything else (as every month has a 1st day).
$lastDayofPreviousMonth = Carbon::now()->startofMonth()->subMonth()->endOfMonth()->toDateString();
// Carbon::now() > 2016-05-05
// ->startofMonth() > 2016-05-01 00:00:00
// ->subMonth() > 2016-04-01 00:00:00
// ->endOfMonth() > 2016-04-30 23:59:59
There is currently a bug within Carbon when using the method
Carbon::now()->startOfMonth()->subMonth()->endOfMonth()->toDateTimeString();
The bug results in returning the last day as 30 for those months that have 31 days.
IE - if you are in March and you run the above call it will return 2017-03-30 and not 2017-03-31 as you would expect.
As I was doing a between dates operation I ended up using..
Carbon::now()->startOfMonth()->subSeconds(1)->toDateTimeString();
This ended up with the correct date dateTimeString for those days that end on the 31st.
Another solution is using Carbon method subMonthNoOverflow():
$lastDayofPreviousMonth = Carbon::now()->subMonthNoOverflow()->endOfMonth()->toDateString();
Found it here when run into 31 day of month issue: https://github.com/briannesbitt/Carbon/issues/627
This works for me.
$firstDayofPreviousMonth = Carbon::now()->startOfMonth()->subMonth()->toDateTimeString(); // 2021-08-01 00:00:00
$lastDayofPreviousMonth = Carbon::now()->endOfMonth()->subMonth()->toDateTimeString(); // 2021-08-31 23:59:59
Use of single $date variable
$date = Carbon::now();
$firstDayofPreviousMonth = $date->startOfMonth()->subMonth()->toDateTimeString(); // 2021-08-01 00:00:00
$lastDayofPreviousMonth = $date->endOfMonth()->toDateTimeString(); // 2021-08-31 23:59:59

Detect BST in php

I am building a booking system in php that offers session times for people to book outdoor activities.
In the summer months, there is an extra session available at the end of the day, because of Daylight Savings, there is an extra hour in the evenings.
Year Clocks go forward Clocks go back
2014 30 March 26 October
2015 29 March 25 October
2016 27 March 30 October
2017 27 March 30 October
2018 25 March 28 October
I am using this...
$todaysDate = strtotime(date("Y-m-d"));
$bstBegin = strtotime("2015-03-29");
$bstEnd = strtotime("2015-10-25");
if($todaysDate > $bstBegin && $todaysDate > $bstEnd)
{
echo "<option value="evening">Evening Session</option>";
}
I only need to show this extra option in the select list between these dates. Is this something I will need to set manually from year to year, or is there a PHP date variable that knows the days the clocks change?
$today = strtotime(date("Y-m-d"));
if (date('I', $today)) {
echo "We're in BST!";
} else {
echo "We're not in BST!";
}
or use the DateTime object equivalent, which maintains details of all the transition dates globally
I work normally with the DateTime functions and like it very much. You have a lot of possibilities to modify a date.
But in your case you can concat the actual year to your string.
$todaysDate = strtotime(date("Y-m-d"));
$bstBegin = strtotime(date('Y')."-03-29");
$bstEnd = strtotime(date('Y')."-10-25");
I hope i have understood your problem correctly.
I have found this online very good ref : https://gist.github.com/aromig/56376f76d4fb653ba83e
public function is_BST() {
$theTime = time();
$tz = new DateTimeZone('Europe/London');
$transition = $tz->getTransitions($theTime, $theTime);
$abbr = $transition[0]['abbr'];
return $abbr == 'BST' ? true : false; }

Wrong easter date in php

I try to calculate the easter date in php.
echo(date("2012: t.n.Y", easter_date(2012)).'<br>'); // 2012: 30.4.2012
This date is correct for the eastern orthodox churches. But I want the normal one!
My next try with the easter_days function:
function easter($year) {
$date = new DateTime($year.'-03-21');
$date->add(new DateInterval('P'.easter_days($year).'D'));
echo $year.": ".$date->format('t.m.Y') . "<br>\n";
}
easter(2012); // 2012: 30.4.2012
Tested oh PHP 5.2.6 and 5.3.6. I also tried to change the timezone with no success.
Your date format is wrong. t is the number of days in the given month (april = 30). Use d for day of the month:
echo(date("d.m.Y", easter_date(2012)).'<br>');
// will output: 08.04.2012
btw: orthodox easter date is April 15th this year.
If you want to use the DateTime class, the following will give you a DateTime object set to Easter. Use easter_date() instead of fiddling around with easter_days():
function easter($year, $format = 'd.m.Y') {
$easter = new DateTime('#' . easter_date($year));
// if your timezone is already correct, the following line can be removed
$easter->setTimezone(new DateTimeZone('Europe/Berlin'));
return $easter->format($format);
}
echo easter(2012); // 08.04.2012
echo easter(2012, 'd.m.Y H:i'); // 08.04.2012 00:00
Timezone
Setting the timezone is only necessary when the default timezone is wrong. Must be set afterwards as it is ignored in the constructor when a unix timestamp is provided.
If left out, the DateTime constructor may produce a wrong date (e.g. 07.04.2012 22:00 for 2012 instead of 08.04.2012 00:00)

Can't get previous month from DateTime in PHP- Is this a (pretty big) bug?

I need to create functions in PHP that let me step up/down given datetime units. Specifically, I need to be able to move to the next/previous month from the current one.
I thought I could do this using DateTime::add/sub(P1M). However, when trying to get the previous month, it messes up if the date value = 31- looks like it's actually trying to count back 30 days instead of decrementing the month value!:
$prevMonth = new DateTime('2010-12-31');
Try to decrement the month:
$prevMonth->sub(new DateInterval('P1M')); // = '2010-12-01'
$prevMonth->add(DateInterval::createFromDateString('-1 month')); // = '2010-12-01'
$prevMonth->sub(DateInterval::createFromDateString('+1 month')); // = '2010-12-01'
$prevMonth->add(DateInterval::createFromDateString('previous month')); // = '2010-12-01'
This certainly seems like the wrong behavior. Anyone have any insight?
Thanks-
NOTE: PHP version 5.3.3
(Credit actually belongs to Alex for pointing this out in the comments)
The problem is not a PHP one but a GNU one, as outlined here:
Relative items in date strings
The key here is differentiating between the concept of 'this date last month', which, because months are 'fuzzy units' with different numbers of dates, is impossible to define for a date like Dec 31 (because Nov 31 doesn't exist), and the concept of 'last month, irrespective of date'.
If all we're interested in is the previous month, the only way to gaurantee a proper DateInterval calculation is to reset the date value to the 1st, or some other number that every month will have.
What really strikes me is how undocumented this issue is, in PHP and elsewhere- considering how much date-dependent software it's probably affecting.
Here's a safe way to handle it:
/*
Handles month/year increment calculations in a safe way,
avoiding the pitfall of 'fuzzy' month units.
Returns a DateTime object with incremented month/year values, and a date value == 1.
*/
function incrementDate($startDate, $monthIncrement = 0, $yearIncrement = 0) {
$startingTimeStamp = $startDate->getTimestamp();
// Get the month value of the given date:
$monthString = date('Y-m', $startingTimeStamp);
// Create a date string corresponding to the 1st of the give month,
// making it safe for monthly/yearly calculations:
$safeDateString = "first day of $monthString";
// Increment date by given month/year increments:
$incrementedDateString = "$safeDateString $monthIncrement month $yearIncrement year";
$newTimeStamp = strtotime($incrementedDateString);
$newDate = DateTime::createFromFormat('U', $newTimeStamp);
return $newDate;
}
Easiest way to achieve this in my opinion is using mktime.
Like this:
$date = mktime(0,0,0,date('m')-1,date('d'),date('Y'));
echo date('d-m-Y', $date);
Greetz Michael
p.s mktime documentation can be found here: http://nl2.php.net/mktime
You could go old school on it and just use the date and strtotime functions.
$date = '2010-12-31';
$monthOnly = date('Y-m', strtotime($date));
$previousMonth = date('Y-m-d', strtotime($monthOnly . ' -1 month'));
(This maybe should be a comment but it's to long for one)
Here is how it works on windows 7 Apache 2.2.15 with PHP 5.3.3:
<?php $dt = new DateTime('2010-12-31');
$dt->sub(new DateInterval('P1M'));
print $dt->format('Y-m-d').'<br>';
$dt->add(DateInterval::createFromDateString('-1 month'));
print $dt->format('Y-m-d').'<br>';
$dt->sub(DateInterval::createFromDateString('+1 month'));
print $dt->format('Y-m-d').'<br>';
$dt->add(DateInterval::createFromDateString('previous month'));
print $dt->format('Y-m-d').'<br>'; ?>
2010-12-01
2010-11-01
2010-10-01
2010-09-01
So this does seem to confirm it's related to the GNU above.
Note: IMO the code below works as expected.
$dt->sub(new DateInterval('P1M'));
Current month: 12
Last month: 11
Number of Days in 12th month: 31
Number of Days in 11th month: 30
Dec 31st - 31 days = Nov 31st
Nov 31st = Nov 1 + 31 Days = 1st of Dec (30+1)

Find out date of nth week's monday in PHP?

I have a simple situation where I have a user supplied week number X, and I need to find out that week's monday's date (e.g. 12 December). How would I achieve this? I know year and week.
Some code based mainly on previous proposals:
$predefinedYear = 2009;
$predefinedWeeks = 47;
// find first mоnday of the year
$firstMon = strtotime("mon jan {$predefinedYear}");
// calculate how much weeks to add
$weeksOffset = $predefinedWeeks - date('W', $firstMon);
// calculate searched monday
$searchedMon = strtotime("+{$weeksOffset} week " . date('Y-m-d', $firstMon));
An idea to get you started:
take first day of year
add 7 * X days
use strtodate, passing in "last Monday" and the date calculated above.
May need to add one day to the above.
Depending on the way you are calculating week numbers and the start of the week this may sometimes be out. (i.e. if the monday in the first week of the year was actually in the previous year!)
TEST THIS THOROUGHLY - but I've used a similar approach for similar calcualtions in the past.
This will solve the problem for you. It mainly derives from Mihail Dimitrov's answer, but simplifies and condenses this somewhat. It can be a one-line solution if you really want it to be.
function getMondaysDate($year, $week) {
if (!is_numeric($year) || !is_numeric($week)) {
return null;
// or throw Exception, etc.
}
$timestamp = strtotime("+$week weeks Monday January $year");
$prettyDate = date('d M Y');
return $prettyDate;
}
A couple of notes:
As above, strtotime("Monday January $year") will give you the timestamp of the first Monday of the year.
As above +X weeks will increment a specified date by that many weeks.
You can validate this by trying:
date('c',strtotime('Sunday Jan 2018'));
// "2018-01-07T00:00:00+11:00" (or whatever your timezone is)
date('c',strtotime('+1 weeks Sunday Jan 2018'));
// "2018-01-14T00:00:00+11:00" (or whatever your timezone is)
date('c',strtotime('+52 weeks Sunday Jan 2018'));
// "2019-01-06T00:00:00+11:00"
Due to reputation restriction i can't post multiple links
for details check
http://php.net/manual/en/function.date.php and http://php.net/manual/en/function.mktime.php
you can use something like this :
use mktime to get a timestamp of the week : $stamp = mktime(0,0,0,0,<7*x>,) {used something similar a few years back, so i'm not sure it works like this}
and then use $wDay = date('N',$stamp). You now have the day of the week, the timestamp of the monday should be
mktime(0,0,0,0,<7*x>-$wDay+1,) {the 'N' parameter returns 1 for monday, 6 for sunday}
hope this helps
//To calculate 12 th Monday from this Monday(2014-04-07)
$n_monday=12;
$cur_mon=strtotime("next Monday");
for($i=1;$i<=$n_monday;$i++){
echo date('Y-m-d', $cur_mon);
$cur_mon=strtotime(date('Y-m-d', strtotime("next Monday",$cur_mon)));
}
Out Put
2014-04-07
2014-04-14
2014-04-21
2014-04-28
2014-05-05
2014-05-12
2014-05-19
2014-05-26
2014-06-02
2014-06-09
2014-06-16
2014-06-23

Categories