php week(curdate()) sum of other years - php

OK so i have this query:
SELECT obrero as MAESTRO, sum(costo_semanal) AS TOTAL_COST,
ROUND(SUM(week_cost)/MONTH(CURDATE()),2) AS MONTHLY_COST,
ROUND(SUM(week_cost)/WEEK(CURDATE()),2) AS WEEKLY_COST
from tbl_costos WHERE obrero ='$maestro'
I did this and it worked great in 2015, the problem is that now on 2016 we go back to week 1 and month 1 so im not having the proper division.
What I need to accomplish is to sum the 52 weeks of the past year and sum the current week of this year so i could have a % of the cost per week
"cost/number of weeks" = $cost per week.
for example of today 2016-01-18 being the 4th week of the year
total paid (of 2015 and 4 weeks of 2016) = $4000.00
weeks = 52 + 4 = 56
4000.00/56 = $71.4285714 average cost per week
The same thing applies to Months, it should be doing the division with 13, and cus January is month 1, its doing it over 1.
I could just do:
SUM(week_cost)/(12+ MONTH(CURDATE()));
and
SUM(week_cost)/(52 + WEEK(CURDATE()));
but that would solve the problem for this year only!!

You should use DATEDIFF() in order to calculate the number of days each maestro has worked from a given date, "start_date" to a given end date "end_date", and then convert those days to weeks, months and years if you need to.
Be flexible and anticipate that each maestro can work from any given date, or a report can be asked from any given date. Your's assume that each maestro started to work on 2015-01-01 and that all reports shall be done with this in mind. Reality is different.
Select obrero as MAESTRO, sum(costo_semanal) as TOTAL_COST, ROUND(SUM(costo_semanal/ROUND(DATEDIFF(start_date, end_date)/30,0)),0) AS MONTHLY_COST, ROUND(SUM(costo_semanal/ROUND(DATEDIFF(start_date, end_date)/7,0)),0) AS WEEKLY_COST FROM tbl_costos WHERE obrero=$maestro;
Do not place the variable $maestro on your query, better use PREPARED STATEMENTS.

Related

Split a Carbon period into full months and reminder in days for the start and end

What I have is:
$period = CarbonPeriod::create("03-09-2022", '1 month', "20-03-2023"); // 3rd of September and 20th of March
From this I can tell the number of months on which the period spans. But what I need is to have a way to calculate a salary based on that period knowing a monthly salary.
So what I'm actually trying to get is:
28 Days(for the first month) followed by 5 full months followed by 20 days (for the last month)
Is there any way I can get this from CarbonPeriod or CarbonInterval?
The following will give you a good approximation:
$salaryPerMonth = 1000;
$totalSalary = Carbon::create('03-09-2022')->floatDiffInRealMonths('20-03-2023') * $salaryPerMonth;
But unless you're working 7/7 days, the approach is not exact, you would need to take into account only business days (excluding, holidays, etc.)
If you want to go to this deeper precision level, take a look at https://github.com/kylekatarnls/business-day and https://github.com/kylekatarnls/business-time

PHP DateTime sub produces unexpected results

I have the following example of me subtracting the DateInterval from DateTimeImmutable
$dateA = new DateTimeImmutable('2016-06-30');
$dateB = new DateTimeImmutable('2016-05-31');
$dateInterval = new DateInterval('P3M');
// print 2016-03-30 as expected
echo $dateA->sub($dateInterval)->format('Y-m-d');
// print 2016-03-02 which i would expect 2016-02-29
echo $dateB->sub($dateInterval)->format('Y-m-d');
When I set the period to 'P8M' it works as expected. How it comes, it dosent works for february?
Ok, it's really simple (kind of). Each 'month' interval evaluates to the prior (or X number of prior) month's equivalent day. If there are more days in the current month, than the month being landed on, the excess overflows to the following month.
So if you have a date which is May 31, 2016 and want to subtract 3 month intervals, it will:
Go back 3 months (in the list of months, don't think days yet), resulting in 'February'
Then look for February 31st. This doesn't exist so bleed over to following month 2 days (2016 Febuary has 29 days, so 2 extra days)
Viola! March 2nd.
Go forward, lets say you're in May 31, 2016 and want to add one month
Go forward one month to June.
Look for June 31st, nope, 1 extra day, bleed over to July.
As expected, July 1st is the answer.
The lesson in this: Adding and Subtracting Month intervals sucks, is confusing, and can lead to non-intuitive results unless you've got your month calculation rosetta stone with you.
Explanation from the PHP Docs
Note:
Relative month values are calculated based on the length of months that they pass through. An example would be "+2 month 2011-11-30", which would produce "2012-01-30". This is due to November being 30 days in length, and December being 31 days in length, producing a total of 61 days.

How Do I Calculate the Number of the Following Week?

I need to calculate the number of the week following a given week. This is trivial for most weeks within the year, but not at the end / beginning of the year. For example if I need to know the week following week 52 of 2013.
I would like to use the defaul_week_format 3, i.e.
a) the weeks start with Monday (instead of Sunday)
b) the numbering within a year starts with 1 (instead of 0)
and c) week number 1 is the first week with more than 3 days this year.
My approach to e.g. calculate the week after week 36 2014 is the following:
SELECT WEEK(DATE_ADD(STR_TO_DATE('W36 2014 Tuesday', 'W%V %X %W'), INTERVAL 1 WEEK))
For this example I calculate the date of Tuesday in week 36, add one week, and calculate the week of this day. This would work, but even without adding one week, I have this strange behaviour:
It works for the default_week_format 0:
SET ##local.default_week_format=0;
SELECT STR_TO_DATE('W36 2014 Tuesday', 'W%V %X %W');
-> Tuesday of week 36 is 2014-09-09
SELECT week('2014-09-09');
-> 2014-09-09 is in week 36
So far, so good: Tuesday of week 36 is in week 36.
But this simple experiment does NOT work for default_week_format 3:
SET ##local.default_week_format=3;
SELECT STR_TO_DATE('W36 2014 Tuesday', 'W%V %X %W');
-> Tuesday of week 36 is 2014-09-09
-> This is wrong, because numbering should start with 1 (instead of 0 now)!
-> Tuesday of week 36 should be 2014-09-02
SELECT week('2014-09-09');
-> 2014-09-09 is in week 37
So MySQL tells me that Tuesday of week 36 is in week 37!
My only explanation for this:
week() takes default_week_format into account
str_to_date() ignores the default_week_format
How can I force MySQL function str_to_date to use the default_week_format?
Or: How else can I calculate the number of the following week?
I could also do it in PHP, but I get the weeks' numbers from a MySQL database.
Thanks for any help!
I was facing exactly the same problem. My solution - perhaps not the greatest one, but it works.
As you already mentionned: Most of the cases are trivial, you just need to know the year end / beginning. Therefore, I just store the relevant weeks for the needed number of years in the following table:
CREATE TABLE `NEXT_WEEK_TAB` (
`CUR_WEEK` varchar(8) NOT NULL,
`NEXT_WEEK` varchar(8) NOT NULL,
PRIMARY KEY (`CUR_WEEK`,`NEXT_WEEK`)
)
You get the following week now with the current algorithm:
following_week = (SELECT next_week
FROM next_week_tab
WHERE cur_week = <your_current_week>);
if !following_week then following_week++;
As I said: Probably not the nicest solution, but it's pretty simple - and it works.
I think you must use Week with a mode argument
mysql> SELECT WEEK('2008-02-20',0);
-> 7
mysql> SELECT WEEK('2008-02-20',1);
-> 8
take a look here :
http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_week

Calculating first day Date of a week from a given week number

I have a question and can't find that specific answer.
In my application, my work year start on july 1 every years. So 52 weeks later, I start again on july first. What I want is a field that I enter let say week 32. I want to have the answer of what is the first day of that specified week and show it as date format. So in other words, if I put week 1 in the field, it will give me the result = July 1 and if I put Week 2 in the field, it will gives me july 8, etc. But I think that every year could change. So I need a calculation that will do this. Is it possible in php?
Tks for help
Seby
strtotime("July 1 2013 +".$monthNum." months");
something like this?

ISO-8601 week numbering vs "Outlook" numbering in PHP

I recently came across a big problem, as I have a system that's paying the customers weekly.
As we all know, a year has 52 weeks, and there are standards for it. I'm using PHP aka date('W') to get the week number from a date, that calculates that according to the standard ISO-8601.
Here are some references:
http://www.iso.org/iso/date_and_time_format and
http://en.wikipedia.org/wiki/ISO_week_date
But here's the ISSUE: year 2009 has 53 weeks. It seems that through the Gregorian calendar within 400 years there are 71 years that have 53 weeks. That's one thing I didn't know, and probably many didn't as well.
According to Wikipedia:
2009-12-31 is 2009-W53-4 (ISO year 2009 has 53 weeks, extending the Gregorian year 2009, which starts and ends with Thursday, at both ends with three days).
and the date function in PHP totally respects it.
If you look into MS Outlook, and show day of the week in the calendar view, it will appear 52 weeks
considering 28 DEC 2009 to 03 JAN 2010 week 1. Is this another standard? The US standard or something?
If so, then why PHP can't support it? Did anyone make a function that supported this?
Is it correct to have 53 weeks? We have both European and US clients.
Outlook doesn't follow any sort of standard for week numbering. It has two settings that determine week numbering, called "First day of week" and "First week of year".
By setting "First day of week" to Monday and "First week of year" to "First 4-day week" the ISO standard can be simulated.
Each user will have to make this adjustment to follow the ISO standard.
I know of no separate US standard, and, apparently, neither does Outlook.
I don't think you will have an issue here. Fact is you are following an international standard for date and time formatting and counting (ISO8601). If you have any customers that complain, simply refer them to the standard.
Outlook's week numbering is somewhat equivalent to the following:
$dummyWeek = floor((date('z') + (date('N') - 1)) / 7) + 1;
For billing purposes, you are better off using ISO8601 as a standard. In fact, if you look at your taxes that you are going to fill this year, they will describe the last fiscal year as being 53 weeks long.
The problem with the Outlook way of counting is that a week is not guaranteed to be 7 days. For example, OW01-2010 is compromised of only 2 days: Fri Jan 1, Sat Jan 2. That's an awfully short billing period for a week.
ISO8601 weeks are guaranteed to be 7 days long which is why we need a leap-week every 4/5/6 years.
Which one of those options would you prefer:
ISO8601: Having 53 weeks once in a while, but every single one of them is 7 days long.
Outlook: Having 52/53 weeks in a year at random, but having to pay twice a year for an "half-week".
Here is the way I solved it.
Note: I code in PHP, but the algorithm implemented in SQL is the relevant part of my code below. Also note that I handled '2028-12-31' separately because it is a special date that gives 54 as it's week number.
// generate an sql that calculates the outlook week of $date (until 2033)
function sqlWeek ($date) {
$week = "if( ". $date . " = '2028-12-31', 54, (week( " . $date . ", 0) + if( (year( " . $date . ") - 1) in (2011, 2016, 2022, 2033), 0, 1)) MOD (if (year( ". $date .") = 2028, 54, if( (year( ".$date." ) - 1) in (2011, 2016, 2022, 2033), 53, 52))))";
return "concat( if( char_length( ".$week." ) < 2, concat( '0', ".$week." ), ".$week." ), '/', year($date) )";
}
There is more of the world outside of the USA than there is inside - and ISO 8601 is probably used more widely outside the USA than it is inside.
The initial statement 'a year has 52 weeks' is only partially true, as you have now found. In terms of ISO weeks, you can end up with week 53, as noted in Wikipedia. You can have up to three days of Year N+1 in week 52 of Year N, or week 53 of Year N. You can have up to three days of Year N-1 in Week 1 of Year N, too. And you need to determine both ISO 'week-year' as well as 'week' - because when the Gregorian calendar year is N, the ISO week-year can be year N-1 or N+1 (depending on which end of the year you are working with). That's why there are separate format specifiers ('%Y', '%y', '%g', '%G') in strftime(), for example (but note that the POSIX standard thinks that days before the first Monday in January are in week 0 of the current year, not in week 52 or 53 of the previous year).
There doesn't seem to be any reliable 'US standard' for 'week'. You get different results depending on the software you use. If you look at the Oracle definition of week, then the first seven days of the year are week 1; you have 1 or 2 days in week 53 at the end of the year.
See also SO 274861 for an implementation of ISO week numbers code. Even if you don't code in the language, the algorithm should be readily understandable.
Just a word of warning, if you're using PHP you might also be using MySQL. MySQL does NOT follow ISO-8601 week conventions but does it close enough that you may think it does. As other people are noting about Outlook, trying to mimic a wonky non-standard way of calculating week numbers isn't worth it!

Categories