PHP Bug day of year [duplicate] - php

This question already has answers here:
Convert day of the year to datetime in php
(2 answers)
Closed 2 years ago.
I'm trying to convert day of year into date.
So no problem i use DateTime::createFromFormat with z and Y.
DateTime::createFromFormat('z Y', '199 2020');
/*RESULT*/
object(DateTime)[3]
public 'date' => string '2020-07-19 12:45:24.000000' (length=26)
public 'timezone_type' => int 3
public 'timezone' => string 'Europe/Paris' (length=12)
But when i test the result i get the wrong day of year...
date('z Y', strtotime('2020-07-19'));
/*RESULT*/
'198 2020' (length=8)
So i trying this
DateTime::createFromFormat('z Y', date('z Y', strtotime('2020-07-19')));
/*RESULT*/
object(DateTime)[3]
public 'date' => string '2020-07-20 12:52:10.000000' (length=26)
public 'timezone_type' => int 3
public 'timezone' => string 'Europe/Paris' (length=12)
if i check day of year 199 of 2020 on this website: https://www.calendrier.best/numero-de-jour-2020.html
I get 2020-07-17
What i'm doing wrong ??

If you know the year, you can use something like this. Outputs:
string(10) "2020-07-17"
Code:
<?php
$dayOfYearNumber = 199;
$year = 2020;
// Add day of year number to the first day of the year, substracting 1 because Jan 1st will be the first day.
$date = (new DateTime("$year-1-1"))->add(new DateInterval('P' . $dayOfYearNumber - 1 . 'D'));
var_dump($date->format('Y-m-d')); // string(10) "2020-07-17"

PHP only detects some standards like you can see here https://www.php.net/manual/de/datetime.formats.date.php
In Your first example you defined your format but strtotime() has no such parameter
If you have these values as variable you could use mktime() instead https://www.php.net/manual/de/function.mktime
But I recommend to always give PHP a month e.x. January

Related

Get day from date Laravel

I got a date with format 'Y-m-d', and want to get the day from it. Like if I have 2021.01.01, I want for example Friday, or Thursday depending on what day it actually is. I already got the date stored as $date and I want the day stored as $day.
I've already tried this, without any error, and without anything happening:
$day = Carbon::createFromFormat('Y-m-d', $date)->format('1');
var_dump($day);
I've found another solution for you :
$timestamp = strtotime('2009-10-22');
$day = date('l', $timestamp);
echo $days;
output:
Thursday
You can try this ,
$d=unixtojd(mktime(0,0,0,6,20,2007));
var_dump(cal_from_jd($d,CAL_GREGORIAN));
output :
array (size=9)
'date' => string '6/20/2007' (length=9)
'month' => int 6
'day' => int 20
'year' => int 2007
'dow' => int 3
'abbrevdayname' => string 'Wed' (length=3)
'dayname' => string 'Wednesday' (length=9)
'abbrevmonth' => string 'Jun' (length=3)
'monthname' => string 'June' (length=4)
And for your code , you just need to add your date like this
$d=unixtojd(mktime(0,0,0,month,days,year));
$calendar = cal_from_jd($d,CAL_GREGORIAN);
var_dump($calendar['dayname']);
It seems like you used a 1 (one) instead of an l (lowercase L). If you change that, it works fine.
$day = Carbon::createFromFormat('Y-m-d', $date)->format('l');
var_dump($day);
This works, you seem to be using 1 instead of l
$today = Carbon::now();
$dayName = $today->format('l');
When using Carbon, ->dayName is the obvious and more explicit way:
Carbon::createFromFormat('Y-m-d', $date)->dayName
It also allow you to have it in any language:
Carbon::createFromFormat('Y-m-d', $date)->locale('fr_FR')->dayName

Carbon createFromFormat unexpected result

::createFromFormat() results in being one month ahead:
var_dump($_GET['archive']);
var_dump(Carbon::createFromFormat('m/Y', $_GET['archive']));
Result:
string '11/2015' (length=7)
object(Carbon\Carbon)[160]
public 'date' => string '2015-12-01 10:38:41.000000' (length=26)
public 'timezone_type' => int 3
public 'timezone' => string 'Europe/London' (length=13)
Seems that you just got unlucky because you were testing on the 31st of the month.
However, this is (apparently) a documented feature. See: http://php.net/manual/en/datetime.createfromformat.php
If you set your format mask "correctly", it works as you'd expect.
$x = Carbon::createFromFormat ('m/Y', '04/2009');
$y = DateTime::createFromFormat ('m/Y|', '04/2009');
dd ($x, $y);
To avoid ambiguity, the Carbon function is just a wrapper for the underlying DateTime function of PHP; I'm just aiming to prove that this is not a Carbon feature that's causing our headache.
If you test on the 31st of the month, $x above will be read as 31 April 2009 which will be displayed as 1st May.
With the pipe symbol in the mask though, all the non-declared time variables (H, i, s) are set to zero, and date variables (d, m) set to 1, so $y will always respond as you expect regardless of the day of the week.
For me testing at 17:46 in the evening of the 4th day of the month, the above code produces the following:
Carbon #1233769590 {#219 ▼
date: 2009-02-04 17:46:30.0 Europe/London (+00:00)
}
DateTime #1233446400 {#217 ▼
date: 2009-02-01 00:00:00.0 Europe/London (+00:00)
}
This is a really weird implementation of date/time function in my opinion. The only real-world situation that you'd want to use this function in, is if you're reading data from an external source (such as an XML "date" field).
Which programmer on earth would want their program to assume that the missing time (or in your case, day) component of the incoming data, should be taken from the runtime execution time? It's absolutely crazy bonkers.
It seems that Carbon uses the current day if not provided. Hence
var_dump(Carbon::createFromFormat('m/Y', '10/2015'));
var_dump(Carbon::createFromFormat('m/Y', '11/2015'));
results e.g. on July 31st in
object(Carbon\Carbon)[156]
public 'date' => string '2015-10-31 11:03:10.000000' (length=26)
public 'timezone_type' => int 3
public 'timezone' => string 'Europe/London' (length=13)
object(Carbon\Carbon)[138]
public 'date' => string '2015-12-01 11:03:10.000000' (length=26)
public 'timezone_type' => int 3
public 'timezone' => string 'Europe/London' (length=13)
as October has 31st but "November 31st is actually December 1st".

PHP | Get total Months of two Overlapping Date Ranges

i am trying to figure out how to get total Months in between two overlapping date Ranges.
e-g
Date Range from Date-A to Date-B overlapping the Date range of Date-X and Date-Y.
_ Start|Jan - Feb - March - April ------ Nov - Dec|End (DateRange A)
Start|Jan - Feb ---- Dec - Jan - Feb|End _
In two date ranges the Jan and Feb Months are colliding. Means Total of 2 Months are there.
So i want these two months in my array so i can apply different functions on it.
e-g i have these two dates
$dateRange1Start = "2015-07-01";
$dateRange1End = "2014-06-30";
=-=-=-=====-=-==
$dateRange2Start = "2012-02-01";
$dateRange2End = "2014-12-31";
There are total 6 Months in colliding between these two date ranges. i want to get these 6 Months.
I tried to search for help in google, but mostly i get less than or greater than signs. but specifically like this. I tried to implement my own logic but its not getting me anywhere, sadly to only more problems :(
i am trying to get results like this
$collidingDates = array("2014-07","2014-08","2014-09","2014-10","2014-11","2014-12");
Any help would be appreciated. :)
=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=--=-=
UPDATE:
Here is what i have done so far, yes getting some code from here and there. and tweaking it a bit up to fulfill my requirements.
//Getting all Months from First Date Range
$start = (new DateTime('2014-06-01'))->modify('first day of this month');
$end = (new DateTime('2015-05-06'))->modify('first day of next month');
$interval = DateInterval::createFromDateString('1 month');
$firstPeriod = new DatePeriod($start, $interval, $end);
//Getting all Months from Second Date Range.
$start = (new DateTime('2012-02-01'))->modify('first day of this month');
$end = (new DateTime('2014-12-31'))->modify('first day of next month');
$interval = DateInterval::createFromDateString('1 month');
$secondPeriod = new DatePeriod($start, $interval, $end);
$collidingDates = array();
foreach ($firstPeriod as $f_dt) {
foreach($secondPeriod as $s_dt){
if($f_dt->format("Y-m") === $s_dt->format("Y-m")){
array_push($collidingDates,$f_dt->format("Y-m"));
}
}
}
echo "<pre>";
print_r($collidingDates);
i got this output.
Array
(
[0] => 2014-06
[1] => 2014-07
[2] => 2014-08
[3] => 2014-09
[4] => 2014-10
[5] => 2014-11
[6] => 2014-12
)
But i think i am getting 1 extra month
2014-06, not sure how O_o??
This is a two step process. First you need to establish the narrowest date range from the start and end dates. Then list the months between those dates.
// An array of start and end dates. There are just 2 in this example but you
// could have as many as you like in the same "start, then end" format.
$ranges = [
[new DateTime('2014-07-01'), new DateTime('2015-06-30')],
[new DateTime('2012-02-01'), new DateTime('2014-12-31')]
];
// Reduce the ranges to one set of two dates, the latest of the start dates
// and the earliest of the end dates.
$range = array_reduce($ranges, function($carry, $item){
return $carry
? [max($carry[0], $item[0]), min($carry[1], $item[1])]
: $item;
});
var_dump($range);
/*
array (size=2)
0 =>
object(DateTime)[1]
public 'date' => string '2014-07-01 00:00:00.000000' (length=26)
public 'timezone_type' => int 3
public 'timezone' => string 'Europe/London' (length=13)
1 =>
object(DateTime)[4]
public 'date' => string '2014-12-31 00:00:00.000000' (length=26)
public 'timezone_type' => int 3
public 'timezone' => string 'Europe/London' (length=13)
*/
// Shift both dates to the first of the month. Strictly speaking, we only
// need to do this with the start date.
$range = array_map(function($date){
return $date->modify("first day of this month");
}, $range);
var_dump($range);
/*
array (size=2)
0 =>
object(DateTime)[1]
public 'date' => string '2014-07-01 00:00:00.000000' (length=26)
public 'timezone_type' => int 3
public 'timezone' => string 'Europe/London' (length=13)
1 =>
object(DateTime)[4]
public 'date' => string '2014-12-01 00:00:00.000000' (length=26)
public 'timezone_type' => int 3
public 'timezone' => string 'Europe/London' (length=13)
*/
$months = [];
$interval = new DateInterval("P1M");
for ($month = $range[0]; $month <= $range[1]; $month->add($interval)) {
$months[] = $month->format("Y-m");
}
var_dump($months);
/*
array (size=6)
0 => string '2014-07' (length=7)
1 => string '2014-08' (length=7)
2 => string '2014-09' (length=7)
3 => string '2014-10' (length=7)
4 => string '2014-11' (length=7)
5 => string '2014-12' (length=7)
*/
I think you are looking for this:
$start = (
new DateTime('2015-12-02'))
->modify('first day of this month');
$end = (new DateTime('2016-05-06'))->modify('first day of next month');
$interval = DateInterval::createFromDateString('1 month');
$period = new DatePeriod($start, $interval, $end);
foreach ($period as $dt) {
echo $dt->format("Y-m") . "<br>\n";
}

Display dates between two dates [duplicate]

This question already has answers here:
PHP: Return all dates between two dates in an array [duplicate]
(26 answers)
Closed 7 years ago.
I have a form that the user should fill two dates.I want to display dates between those selected dates like
June 11
June 12
June 13
June 14
June 15
Jun 16
Jun 17
in my action.php
$dateTo = $r->getParameter("date_to", date('Y-m-d'));
$dateFrom = $r->getParameter("date_from", date('Y-m-d', strtotime('7 days ago', strtotime($dateTo))));
$dateRange = new DatePeriod(DateTime::createFromFormat('Y-m-d',$dateTo), new DateInterval('P1D'), DateTime::createFromFormat('Y-m-d',$dateFrom));
then in my templates, I tried
foreach $dateRange as $date {echo $date}
Whats the correct way to display those date?
var_dump outputs like
object(DatePeriod)[62]
public 'start' =>
object(DateTime)[21645]
public 'date' => string '2015-05-20 16:56:21' (length=19)
public 'timezone_type' => int 3
public 'timezone' => string 'Asia/Manila' (length=11)
public 'current' => null
public 'end' =>
object(DateTime)[21656]
and I tried
<?php foreach($dateRange as $r):?>
<?php echo $r->format('Y-m-d') ?>
<?php endforeach ?>
But nothing displayed in my table
According to the PHP doc DatePeriod implements the Traversable interface. So you can use it like an array and loop with a foeeach over it:
/** #var DateTime[] $dateRange */
$dateRange = new DatePeriod(...);
foreach($dateRange as $date) {
$date->format(...);
}
What is not mentioned in the official PHP doc is that you get an "array" of DateTime objects.
You need to use format.
Like this:
echo $date->format("Ymd") . "<br>";

DateTime "first day of last month" not returning the first day

I looked at this answer already, and it's quite close to what I have.
Here is my PHP code:
$start = new DateTime('0:00 first day of previous month', new DateTimeZone('UTC'));
/*
if (isset($_GET['year']) && isset($_GET['month']) && checkdate($_GET['month'], 1, $_GET['year'])) {
$start = DateTime::createFromFormat('Y-m-d', $_GET['year'] . '-' . $_GET['month'] . '-1');
}*/
$middle = DateTime::createFromFormat('U', strtotime('first day of last month', $start->format('U')));
$middle->setTimezone(new DateTimeZone('UTC'));
$end = DateTime::createFromFormat('U', strtotime('first day of 2 months ago', $start->format('U')));
$end->setTimezone(new DateTimeZone('UTC'));
var_dump($start);
var_dump($middle);
var_dump($end);
Today is August 27th, so I would expect July 1, June 1, and May 1. Here's what the actual output is:
object(DateTime)[1]
public 'date' => string '2013-07-01 00:00:00' (length=19)
public 'timezone_type' => int 3
public 'timezone' => string 'UTC' (length=3)
object(DateTime)[2]
public 'date' => string '2013-05-02 00:00:00' (length=19)
public 'timezone_type' => int 3
public 'timezone' => string 'UTC' (length=3)
object(DateTime)[3]
public 'date' => string '2013-04-02 00:00:00' (length=19)
public 'timezone_type' => int 3
public 'timezone' => string 'UTC' (length=3)
Why is it returning the second day of the months for me?
I've also tried it without the new DateTimeZone('GMT') as the second parameter of the constructor for the initial DateTime but it still gives me the same result, just with different times.
this part irrelevant - question was edited
Because of the timezone difference. $start is calculated in the 'Rainy River timezone', while $middle and $end are in UTC time.
The 'Rainy River timezone has a -06:00 hour offset from UTC (exactly the difference in hours between the first with the second and third results).
update 1 - solution
It seems the problem lies somewhere around strtotime. For some reason it yields a result with an offset of one day (further explanation needed). A simple solution, is to subtract one second from that date and it will produce the correct result.
$timezone = new DateTimeZone('UTC');
$start = new DateTime('0:00 first day of previous month', $timezone );
$middle = DateTime::createFromFormat('U', strtotime('first day of last month',($start ->format('U'))-1),$timezone);
echo $middle->format('Y-m-d')."\n";
Result:
2013-05-01
update 2 - reason for problem
Eventually I find out that the problem originates from the instantiation of the fisrt date object. Here is an illustration.
This will give a correct result:
$original = new DateTime('2013-05-01');
echo $original->format('Y-m-d')."\n";
$previous= DateTime::createFromFormat('U', strtotime('first day of last month',($original->format('U'))),new DateTimeZone('UTC'));
echo $previous->format('Y-m-d')."\n";
Result (OK):
2013-05-01
2013-04-01 <--- OK
However, this will not (only first line different, as in the original code):
$original = new DateTime('0:00 first day of previous month', new DateTimeZone('UTC'));
echo $original->format('Y-m-d')."\n";
$previous= DateTime::createFromFormat('U', strtotime('first day of last month',($original->format('U'))),new DateTimeZone('UTC'));
echo $previous->format('Y-m-d')."\n";
Result:
2013-07-01
2013-05-02 <--- BAD
After reading the answer here, I had a better idea:
$start = new DateTime('0:00 first day of previous month');
/*
if (isset($_GET['year']) && isset($_GET['month']) && checkdate($_GET['month'], 1, $_GET['year'])) {
$start = DateTime::createFromFormat('Y-m-d', $_GET['year'] . '-' . $_GET['month'] . '-1');
}*/
$middle = clone $start;
$middle->modify('first day of last month');
$end = clone $start;
$end->modify('first day of 2 months ago');
var_dump($start);
var_dump($middle);
var_dump($end);
Output:
object(DateTime)[1]
public 'date' => string '2013-07-01 00:00:00' (length=19)
public 'timezone_type' => int 3
public 'timezone' => string 'America/Rainy_River' (length=19)
object(DateTime)[2]
public 'date' => string '2013-06-01 00:00:00' (length=19)
public 'timezone_type' => int 3
public 'timezone' => string 'America/Rainy_River' (length=19)
object(DateTime)[3]
public 'date' => string '2013-05-01 00:00:00' (length=19)
public 'timezone_type' => int 3
public 'timezone' => string 'America/Rainy_River' (length=19)
Also, I realize that a DateTimeImmutable would be a better choice for the $start instance (so that I don't have to clone the other two), but I don't have access to PHP 5.5 yet.

Categories