I know an event happens on a Monday in any given year. I also know that the event falls between May 25-31 of any given year. If I calculate the type of day May 25th is, I find out that its a Wednesday. But how can I write a script to determine the event will be May 30th?
I'm assigning the days a number: Sunday = 1, Monday = 2, etc...
I have variable A equal to what day May 25th is: A = 4
I have variable B equal to what day the event occurs on: B = 2
I'm setting X equal to how many days I need to add to A to have the correct date.
I wrote this equation that seems to work:
(A + X) % 7 = B
(4 + X) % 7 = 2
I know if I set 5 as X the equation is true, and 5 is how many days I need to add to May 25th to make it May 30th, but how can I rewrite the equation so it is equal to X and not to B?
Related
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.
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.
Im currently programming a calendar with php and mysql and im stuck with some functionality while selecting all events i want to display. I implemented the possibilty to repeat an event. Therefore i set a timestamp from which the event starts and a timestamp to determine when the event ends. Furthermore i got some integer values which represent the rythm in which the event is repeated.
Then i fetch the events based on a timestamp which is send with a request.
I now want to enable the user to shift events from the weekend to the Friday before the weekend or the monday after the weekend. For example:
From: 1450306800 (today)
until: 0 (infinite)
rythm : 1 (-> every month)
jump:2 (-> on every 2nd day / month)
weekends : 3 (-> shift to next monday)
-> January 2nd 2016 is a saturday and i want to display that event on the next monday.
currently my select looks something like this: (:day -> timestamp from request, :d -> day of month from :day, :weekday -> day of the week from :day)
SELECT * FROM events
WHERE repeat_from <= :day
AND ((repeat_until >= :day) OR (repeat_until = 0))
AND CASE weekends
WHEN 0 THEN (:weekday BETWEEN 1 AND 7)
WHEN 1 THEN (:weekday < 6)
WHEN 2 THEN ??
WHEN 3 THEN ??
AND CASE rythm
WHEN 1 THEN (:d - DAY(FROM_UNIXTIME(repeat_from))) / (jump + 1) = CEIL ((:d - DAY(FROM_UNIXTIME(repeat_from))) / (jump + 1)) ... [all the other cases]
How do i check if the event would have been displayed on saturday or sunday before/after within the select? The only way i can think of is to more or less repeat the whole select from the "...AND CASE rythm..." part which is quite alot.
Or would the best way be, to fetch the event on every monday/friday anyway if it shifts and then check with a php function if the event would have been displayed on saturday or sunday ?
Why don't you do all the calculations and matching on the PHP back-end? With that much cases and clauses in your MySQL query you'll probably get yourself a really slow execution.
Select all Events by your major criteria. In your case that would probably be:
SELECT * FROM
events
WHERE
repeat_from <= :day AND
(
(repeat_until >= :day) OR
(repeat_until = 0)
)
Then just loop through all fetched rows and apply the built-in date() method - much faster and flexible:
# you can match the week number of different dates
$currentWeekNumber = date('W');
$specificDayWeekNumber = date('W', strtotime($specificDate));
# or match the day number
$currentDayNumber = date('N');
$specificDayNumber = date('N', strtotime($specificDate));
The date() method is super flexible and will allow you to check if certain Event date is within the weekend or not, so you can manipulate it further.
If you provide some further explanations and/or examples, I'll try to be more specific with the solution. Cheers.
I'm trying to figure out how to repeat certain tasks on specific days at certain intervals based on an existing date.
For example, I have this:
Date Task
2011-01-12 MJK-0083
I want to:
Determine the day of the week based on the date provided (in this case, Wednesday)
Determine which Wednesday of the month it is (in this case, the 2nd Wednesday)
Calculate the date of the 2nd Wednesday in June as the next date this task will occur
I've been looking at some examples, but while I can do bits of it, I can't seem to figure out how to do all of it. For example, I'm using this for step 1:
date('l', strtotime('2011-01-12'))
But I am lost when it comes to steps 2 and 3... Can someone help me out?
To find out which Wednesday of the month it is, you can do this using the day of the month
(int)(day_of_month / 7) + (day_of_month % 7 == 0 ? 0 : 1)
Thus, for 2012-01-12 you'll get:
(int)(12 / 7) + (12 % 7 == 0 ? 0 : 1) = 1 + 1 = 2 -> second Wednesday
This is a bit like the popular relative time (ago) except I'm not dealing with a timestamp but the number of months.
I'm not sure on how to go by this though?
Heres some examples to improve your understanding of my question:
If input was:
3
Output would be:
3 Months
If input was:
13
Output would be:
1 Year, 1 month
So for every 12 months its X Year(s) (if any) and then the remaining months are following it with X month(s).
You can use the mod operator to get remaining months:
$years = (int)($total_months / 12);
$months = $total_months % 12;