This question is pretty similar to this and this (and other) questions, but what I want to do is the opposite, I am expecting a PHP answer to show the same result than MySQL YEARWEEK().
Today is 2019-09-16 and MySQL YEARWEEK says:
SELECT YEARWEEK(NOW()) -- returns 201937
And PHP says:
echo date('oW') // returns 201938
What do I have to do in PHP to show "201937" just like MySQL YEARWEEK does?
There are two issues:
The weeks number changes on different days (Monday for PHP, Sunday for MySQL)
The first week of the year is determined differently (week containing the 4th of january for PHP, week starting with the first Sunday of the year for MySQL)
Which then causes these differences:
First day of year: | Mo | Tu | We | Th | Fr | Sa | Su |
PHP week | ------- 01 ------ | --- 52/53 -- |
MySQL week | ----------- 52/53 ----------| 01 |
We have 2 different cases, based on when the year starts:
If it starts a Friday, Saturday or Sunday, PHP start week 1 "late" by 1 day (it can be solved by taking tomorrow's week number in PHP)
It it starts a Monday, Tuesday, Wednesday or Thursday, you'll end up with an offset of 3-6 days, PHP being ahead this time, and it becomes a mess to solve.
So all in all, it seems you're better off just counting how many Sundays already passed this year, which apparently can be done with the following (adapted from this):
ceil((date("z") + 1 - date("w")) / 7); //added +1 in case the year starts a Sunday
And if it's 0 you count how many Sundays there were last year:
$ldly = strtotime(date("Y")-1)."-12-31"); //last day last year
ceil((date("z", $ldly ) + 1 - date("w", $ldly )) / 7);
By combining the two (and adding a parameter if you want to check dates other than today) you'd get:
function weekNum($date = false) {
$day = $date ? strtotime($date) : time();
if($res = ceil((date("z", $day) + 1 - date("w", $day)) / 7)){
return $res;
}
$ldly = strtotime((date("Y", $day)-1)."-12-31"); //last day last year
return ceil((date("z", $ldly ) + 1 - date("w", $ldly )) / 7);
}
I think this should always match with the MySQL date, but do your own tests to make sure! :)
Like this?
echo date('oW', time() - 86400); // basically use yesterday's week number
Related
I'm working on a project and I need to format date in the following : YYYYWW where WW is the week number in the year, for example : today is 202131.
There are several ways to do this, I can use isoFormat('YYYYWW') directly, or I can get weekOfYear attribute and append it to current year.
Both methods however, break for the following date : 01-01-2021, indeed, the 1st january is set in the last week of 2020, but the year is 2021. Both methods give : 202153 while the correct result should be 202053 .
I currently have a workaround by checking if the month is less than 3 and the week is bigger than 50 then there is a problem and I decrement the year by 1.
public static function formatTestWeek($d)
{
$current = Carbon::parse($d);
$currentWeek = $current->weekOfYear;
$currentYear = $current->year;
if($currentWeek > 50 && $current->month < 3){
$currentYear -= 1;
}
$formattedDate = strval($currentYear) . $current->isoFormat("WW");
return $formattedDate;
}
Is there a more elegant approach in Carbon to get YYYYWW format that works in all cases ?
YYYY is the year
GGGG is the ISO week-year
gggg is the week-year following current locale settings (first_day_of_week + day_of_first_week_of_year)
So you need ->isoFormat('GGGGWW')
Complete list of codes available in isoFormat() are in the documentation:
https://carbon.nesbot.com/docs/#iso-format-available-replacements
I need to calculate number of days between two dates.
Required date entered by me,fetch the record from the database by the given dates.
If the database have 'startdate' as 1Jan2015 'enddate' as 5Feb2015.
For January month it should return 30 and for February 5 days.
My table:
id Name Type Project Place Start Date End Date Details
1 Sai Local Site Bangalore 2015-09-03 11:32:47 2015-09-05 11:32:47 test
2 Ram Local IGCAR Chennai 2015-04-01 15:15:36 2015-04-09 15:15:36 Installation
3 Mani Local IGCAR Chennai 2015-04-16 15:16:18 2015-05-21 15:16:18 Training
My coding
///////////Employee Outstation(Travel) details/////////////
$employeeTravel = new EmployeeTravelRecord();
//date_start = '2015-04-01' ;
//date_end = '2015-04-30';
$TravelEntryList = $employeeTravel->Find("(travel_date between ? and ? or return_date between ? and ? )",array($req['date_start'], $req['date_end'],$req['date_start'], $req['date_end']));
foreach($TravelEntryList as $Travelentry){
$amount = (strtotime($Travelentry->return_date) - strtotime($Travelentry->travel_date));
}
For second record, it returns correct value, but for third record it calculates including May month. But i want only 30 days of april.
DATEDIFF() returns value in days from one date to the other.
select *,datediff( end Date, Start Date) as days from My table;
Please have a look at this post, you should find what you're looking for :
How to get the number of days of difference between two dates on mysql?
There is a function in PHP called as date_diff for difference between two dates.
<?php
$date1 = date_create("2013-03-15");
$date2 = date_create("2013-12-12");
$diff = date_diff($date1,$date2);
echo $diff->format("%R%a days");
?>
Im currently trying to calculate the amount of periods (each period is 1 week, after a certain date or day). Lets say first period start on 01-01-2013 (tuesday) until 29-01-2013 (tuesday)(4 periods in total).
I have a table that looks like:
id | startDate (datetime) | endDate (datetime)
I have two input fields where a user can fill in a start date and end date. I would like to fill any date between 01-01-2013 and 29-01-2013 and decide how many times it passes a tuesday (the date the period starts) again.
So if I would select 01-01-2013 until 07-01-2013 would result in: 1, but if i would select 06-01-2013 till 09-01-2013 this would result in 2 and 06-01-2013 till 16-01-2013 would result in 3 etc.
To be clear, I dont want to know the amount of weeks between the two dates, only the amount of times it 'crosses' the same day (tuesday) that was given in the database. Every period is 1 week. Is there anyone that could help me out?
Use PHP's date() function.
$startday = strtotime($start_date_from_db);//date from db;
$endday = strtotime($end_date_from_db);//date from db;
$counter = 0;
for($i=$startday; $i<=$endday; $i+=86400) {
$current_day = date('w', $i);
if($current_day == 2) { //0 for sunday, 1 for monday, 2 for tuesday
$counter++;
}
}
When comparing dates a good method is:
1- transform the dates to timestamps:
$timestamp1 = strtotime($date1);
$timestamp2 = strtotime($date2);
2- do the desired operation, in this case:
$timebetween = $timestamp2 - $timestamp1;
3- Transform result (number of seconds) to desired value, in this case:
$weeks= $timebetween / 604800;
I'm kind of at a loss here. It seems as though somehow my code is missing a whole week at the end of 2009 and I've tried a couple different things.
My base function to get the start and end date for a week is below. Given a Year, Week and Day of the Week it gives you a date.
function datefromweeknr($aYear, $aWeek, $aDay)
{
$Days=array('xx','ma','di','wo','do','vr','za','zo');
//xx = Current Sun, ma = Mon ..... zo = Sun of the next Week
$DayOfWeek=array_search($aDay,$Days); //get day of week (1=Monday)
$DayOfWeekRef = date("w", mktime (0,0,0,1,4,$aYear)); //get day of week of January 4 (always week 1)
if ($DayOfWeekRef==0){
$DayOfWeekRef=7;
}
$ResultDate=mktime(0,0,0,1,4,$aYear)+((($aWeek-1)*7+($DayOfWeek-$DayOfWeekRef))*86400);
return $ResultDate;
}
Seemed to work completely fine until I realized that I was missing the week of December 27th 2009 to January 2nd 2010.
echo '<table border="1">';
for($i = 1; $i < 53; $i++){
if($i < 10){
$w = '0'.$i.'1';
}
else{
$w = $i.'1';
}
echo '<tr><td>Week#'.$i.' </td><td> '.date("Y-m-d",datefromweeknr(2009,$i,"xx")).' </td><td> '.date("Y-m-d",datefromweeknr(2009, $i,"za")).'</td><td> Week = '.date("W: Y-m-d",strtotime("2009W$w")).' </td></tr>';
}
echo '</table>';
It seems the 52nd week of the year ends on 2009-12-26 and the 1st week of the new year starts on 2010-01-03. I'm losing a whole week, No Bueno!
Anyone know what I'm doing wrong or can point me to a fool proof way of supplying a week number and a year to get me the start and end date of that week without losing any days in the process?
Check here:
http://www.onlineconversion.com/day_week_number.htm
If you enter 29 december 2009, so see that US and ISO/Europe give different week numbers (resp. 52 and 53).
Could this be related to your problem? Which standard do you dates conform too?
Edit:
From http://www.epochconverter.com/epoch/weeknumbers.php :
Week number according to the ISO-8601 standard, weeks starting on Monday. The first week of the year is the week that contains that year's first Thursday. The highest week number in a year is either 52 or 53.
Your question remainded me of a bug comment I read today on php.net:
In PHP 5 prior to 5.2.7, requesting a
given occurrence of a given weekday in
a month where that weekday was the
first day of the month would
incorrectly add one week to the
returned timestamp. This has been
corrected in 5.2.7 and later versions.
Which is irrevelent for now but I would suggest you to replace your calculations in datefromweeknr with strtotime calls. I'm pretty sure strtotime will fix your calculation bug.
So you could use something like:
strtotime('last Monday', $timestamp);
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