I am trying to calculate last years starting day of the "current week NOW()" and the ending day of that week. Along with this I am needing an offset as sometimes the Starting day of the week may not be Sunday or Monday, but even possibly a Thursday.
If a week starts on a Tuesday for instance it will end on a Monday. Given this if the current day is Thursday I need to be able to calculate the Tuesday and Monday.
I understand how to get last years current day.
SELECT DATE_SUB(NOW(), INTERVAL 1 YEAR);
But with the offset requirement here I am having issues calculating the starting day of that week and ending day of that week. Which needs to be in a "date format."
* Working to clarify this more... My example was off...
***Edit
For the sake of argument (and example), let's say that today is Jan 23, 2012. My task is to accept that date and return the start and end dates for that week of the previous year.
My assumptions are:
1) a week is defined as having a thursday (ie 2011 week 1 is 1/2 - 1/8)
2) start of week is Sunday
According to the week numbering scheme as I understand it with the above assumptions, week 1 is the first week with a Thursday. That means, Jan 23 falls within week 4 in 2012. This is confirmed with WEEK('2012-01-04') = 4. My target thus is to select the start and end dates of week 4 of the previous year. In 2011, the results would be Jan 23 - Jan 29.
Complicating this further is then to adjust the start of the week (modify assumption 2). Continue to use WK4... 2011, Jan 23 - Jan 29, Sun - Sat, If I say the start of the week is Monday, then I would adjusting the dates by one... giving Jan 24 - Jan 30. Tues adjusts by 2... Jan 25 - Jan 31, etc.
The approach is two steps:
1) calculate the start and end of the true year week
2) slide it into the "future" by whatever the start day would be
While the sliding into the future may or may not be correct, it would at least yield consistent results based on the conventional understanding of what "week 4" means.
Unfortunately PHP is not necessarily an option here. We need this to be ran inside of a SELECT START_WEEK, END_WEEK;
Any advice or help towards solving this query would be much helpful.
Thanks
Well, ISO 8601 assumes:
a week is defined as having a Thu
the start of a week is Mon
Jan 23 falls within week 4 of 2012 which you can confirm with
SELECT WEEK('2012-01-23', 3) = 4;
Week 4 of 2012 is Jan 23 to Jan 29 which you can confirm with the calendar at whatweekisit.com. As a query, you can calculate with:
SELECT
WEEK('2012-01-23', 3) AS weekNumber,
DATE_SUB('2012-01-23', INTERVAL DAYOFWEEK('2012-01-23') - 2 DAY) AS startOfWeek,
DATE_ADD('2012-01-23', INTERVAL 8 - DAYOFWEEK('2012-01-23') DAY) as endOfWeek;
Week 4 of 2011 is Jan 24 to Jan 30 (also confirmable by calendar). It is true that same date may not fall within the current week number and last year's week, but I don't suspect they would be wildly different.
SELECT
IF (WEEK('2012-01-23', 3) = WEEK(DATE_SUB('2012-01-23', INTERVAL 1 YEAR), 3),
DATE_SUB(DATE_SUB('2012-01-23', INTERVAL 1 YEAR), INTERVAL DAYOFWEEK(DATE_SUB('2012-01-23', INTERVAL 1 YEAR)) - 2 DAY),
DATE_SUB(DATE_SUB(DATE_ADD('2012-01-23', INTERVAL 6 DAY), INTERVAL 1 YEAR), INTERVAL DAYOFWEEK(DATE_SUB(DATE_ADD('2012-01-23', INTERVAL 6 DAY), INTERVAL 1 YEAR)) - 2 DAY)) AS datetimeStart;
Notice that I'm always representing the calculations verbatim in several places (e.g. DATE_SUB('2012-01-23', INTERVAL 1 YEAR) of Jan 32 2011); if you're doing this within a stored procedure or UDF you can probably use variables to make it more concise/readable/maintainable.
Now that the start and end of the target year week has been identified, you can simply apply your offset. Given $weekDayStart is 0 - 6 (Sun - Sat):
SELECT
DATE_ADD(
IF (WEEK('2012-01-23', 3) = WEEK(DATE_SUB('2012-01-23', INTERVAL 1 YEAR), 3),
DATE_SUB(DATE_SUB('2012-01-23', INTERVAL 1 YEAR), INTERVAL DAYOFWEEK(DATE_SUB('2012-01-23', INTERVAL 1 YEAR)) - 2 DAY),
DATE_SUB(DATE_SUB(DATE_ADD('2012-01-23', INTERVAL 6 DAY), INTERVAL 1 YEAR), INTERVAL DAYOFWEEK(DATE_SUB(DATE_ADD('2012-01-23', INTERVAL 6 DAY), INTERVAL 1 YEAR)) - 2 DAY)),
INTERVAL $weekDayStart - 1 DAY) AS datetimeStart,
DATE_ADD(
IF (WEEK('2012-01-23', 3) = WEEK(DATE_SUB('2012-01-23', INTERVAL 1 YEAR), 3),
DATE_SUB(DATE_SUB('2012-01-23', INTERVAL 1 YEAR), INTERVAL DAYOFWEEK(DATE_SUB('2012-01-23', INTERVAL 1 YEAR)) - 2 DAY),
DATE_SUB(DATE_SUB(DATE_ADD('2012-01-23', INTERVAL 6 DAY), INTERVAL 1 YEAR), INTERVAL DAYOFWEEK(DATE_SUB(DATE_ADD('2012-01-23', INTERVAL 6 DAY), INTERVAL 1 YEAR)) - 2 DAY)),
INTERVAL $weekDayStart + 5 DAY) AS datetimeEnd;
So, working it through with the input of 2012-01-23 and start day of Thurs would yield:
Jan 23 2012 = week 4
week 4 of 2011 = 1/24-1/30
Offset Thu - Mon (4 - 1) is +3 which moves window to Jan 27 - Feb 2 2011
Found it... Had to read up on the issue a little more.
This ended up being 7 different queries.
My Base Query:
Sunday Start Day of Week
SELECT
DATE_SUB(
DATE_ADD(
STR_TO_DATE( CONCAT( YEAR('2012-01-04')-1, '-01-01' ), '%Y-%m-%d'), #Get last year starting date.
INTERVAL WEEK('2012-01-04') WEEK),
INTERVAL 6 DAY) START_DAY_OF_WEEK,
DATE_ADD(
STR_TO_DATE( CONCAT( YEAR('2012-01-04')-1, '-01-01' ), '%Y-%m-%d'),
INTERVAL WEEK('2012-01-04') WEEK) END_DAY_OF_WEEK;
This gets me Week 1 of 2011. Starting of that week is 1/2 and ending on 1/8.
Now if my week starts on a different day I add in an offset...
Tuesday Start Day of Week
SELECT
DATE_SUB(
DATE_ADD(
STR_TO_DATE( CONCAT( YEAR('2012-01-04')-1, '-01-01' ), '%Y-%m-%d'), #Get last year starting date.
INTERVAL WEEK('2012-01-04') WEEK),
INTERVAL 4 DAY) START_DAY_OF_WEEK,
DATE_ADD(
DATE_ADD(
STR_TO_DATE( CONCAT( YEAR('2012-01-04')-1, '-01-01' ), '%Y-%m-%d'), #Get last year starting date.
INTERVAL WEEK('2012-01-04') WEEK),
INTERVAL 2 DAY) END_DAY_OF_WEEK;
This will give me 1/4 start day of week and ending on 1/10.
To get the other days of the week is relatively simple:
Sunday (First Query...)
Monday -5 start day +1 end day.
Tuesday -4 start day +2 end day.
Wednesday -3 start day +3 end day.
Thursday -2 start day -4 end day.
Friday -1 start day -5 end day.
Saturday -0 start day -6 end day.
It is 7 separate queries but does enable me to do what I was intending to do.
Related
How to get mysql record older than 30 days? my code will get all the records even which are inserted two months ago .
WHERE date < DATE_SUB(NOW(), INTERVAL 1 MONTH)
I want only one month ago not bigger than one month
Put both start and end date in the filter.
WHERE date >= CURDATE() - INVERVAL 2 MONTH
AND date < CURDATE() - INTERVAL 1 MONTH
It's verbose and repetitive, but that's an affliction of all SQL code.
Calendar months? If you, on May 7th or anytime in May, want to ask for the calendar month of April, it would be this
WHERE date >= LAST_DAY(CURDATE()) + INTERVAL 1 DAY - INTERVAL 2 MONTH
AND date < LAST_DAY(CURDATE()) + INTERVAL 1 DAY - INTERVAL 1 MONTH
LAST_DAY('2021-05-07') gets you '2021-05-31',
+ INTERVAL 1 DAY then gets you '2021-06-01', then
- INTERVAL 2 MONTH finally gets you '2021-04-01'
It's easy to read and reason about.
CURDATE() gives today's date in place of the current date and time given by NOW(). Lots of historical reporting doesn't care about time of day, just calendar day. So it might be smart to use CURDATE(), depending on your application.
Previously I had the query set to grab the last 4 weeks but it didn't count full weeks which threw off Excel pivot tables dependent on the queried data.
I changed it to this and now it's curtailing my data to the last 2 weeks only.
I suspect the AND statement is faulty. Can someone confirm?
WHERE
BalanceDay >= DATE(CONVERT_TZ(CURRENT_TIMESTAMP, 'UTC', Mapping.DEFAULT_TIMEZONE) - INTERVAL DAYOFWEEK(CURRENT_TIMESTAMP) - 1 DAY - INTERVAL 4 WEEK)
AND BalanceDay <= DATE(CONVERT_TZ(CURRENT_TIMESTAMP, 'UTC', Mapping.DEFAULT_TIMEZONE) - INTERVAL DAYOFWEEK(CURRENT_TIMESTAMP) - 1 DAY - INTERVAL 3 WEEK) + INTERVAL 6 DAY
This is what I had previously which did pull 4 weeks but didn't pull in full weeks (i.e. if it ran on a Friday, I would get something other than 28 days' worth of data):
WHERE
BalanceDay >= CONVERT_TZ(CURRENT_DATE, 'UTC', Mapping.DEFAULT_TIMEZONE) - INTERVAL 4 WEEK
Well, I don't understand the real business of your query. but after running it, this query got the last four weeks:
WHERE
BalanceDay >= DATE(CONVERT_TZ(CURRENT_TIMESTAMP, 'UTC', Mapping.DEFAULT_TIMEZONE) - INTERVAL DAYOFWEEK(CURRENT_TIMESTAMP) - 1 DAY - INTERVAL 4 WEEK)
AND DATE(CONVERT_TZ(CURRENT_TIMESTAMP, '+00:00', '+03:00') - INTERVAL DAYOFWEEK(CURRENT_TIMESTAMP) - 1 DAY - INTERVAL 1 WEEK) + INTERVAL 6 DAY
consider using DATE_ADD & DATE_SUB though.
good luck :)
How to select data from last monday to sunday. Like this
`WHERE
`order`.order_createdAt >= date_sub(date_sub(curdate(), interval day(curdate()) - 1 day), interval 1 month)
and `order`.order_createdAt < date_sub(curdate(), interval day(curdate()) - 1 day)`
this show data from last month
Upd. find this
`WHERE WEEK (order_createdAt) = WEEK( current_date)-1
AND YEAR( order_createdAt) = YEAR( current_date );`
But it takes from past sunday to saturday
If you want to check for Last week Monday to This Sunday, which is say Today's date is '2017-01-27' and Last week Monday date will be 2017-01-16 and This Sunday will be 2017-01-22, then you can follow below query,
WHERE
`order`.order_createdAt BETWEEN subdate(curdate(),dayofweek(curdate())+5)
and subdate(curdate(),dayofweek(curdate())-1)`
Hope this would help you out.
Following SQL code might be useful to Presto users who might be searching for same information in reference to same question asked, for data between Last Monday to Next Sunday (an ISO week): -
WHERE date_column_ref BETWEEN date_add('day', dow(localtimestamp) * -1 + 1, localtimestamp) and date_add('day', 7 - dow(localtimestamp), localtimestamp)
select subdate(curdate(), WEEKDAY(curdate()) + 7); # Monday
select subdate(curdate(), WEEKDAY(curdate()) + 1); # Sunday
I been trying to search for the same issue on getting MONDAY to SUNDAY, from a specific day.
I have come-up with the following and hope this helps anyone who is looking for the same solution as I am.
The only issue I have is, I think this can be improved and open for suggestions as it's long.
SELECT
DATE_ADD(DATE('2021-05-30 02:12:43'),
INTERVAL - WEEKDAY(DATE('2021-05-30 02:12:43')) DAY) AS MONDAY,
DATE_ADD(DATE_ADD(DATE('2021-05-30 02:12:43'),
INTERVAL - WEEKDAY(DATE('2021-05-30 02:12:43')) DAY),
INTERVAL 6 DAY) AS SUNDAY
;
How do I get the nth previous working date in MySQL?
Suppose the function signature is
nth_previous_working_date (d DATE, n INT)
For 10th September, 2015, the function should return 3rd September, 2015
You can use the date_sub function.
SELECT DATE_SUB('2015-09-10', INTERVAL 7 DAY);
or simply use the minus operator
SELECT '2015-09-10' - INTERVAL 7 DAY
See the working example.
Getting the previous non-weekend working day can be done with a case.
select case dayofweek(curdate() - interval 1 day) -- yesterday
when 1 then curdate() - interval 3 day -- when sunday, go 2 more days before
when 7 then curdate() - interval 2 day -- when saturday, go 1 more days before
else curdate() - interval 1 day -- yesterday
end
Does anyone have a snippet of MYSQL code that will give me the new datetime of a day one year in the future that is the same day of the week?
SELECT new_day = ADDDATE(new_day,INTERVAL 364 DAY) FROM my_table
Works on non-leap years. Any ideas how to deal best with leap years?
Given that a normal year is 52 weeks and 1 day long and a leap year is 52 weeks and 2 days long, your new date will be one or two days earlier in the year than it was in the old year. For any date after New Year's Day in a regular year, or any date after the 2nd of January in a leap year, adding 52 week or 364 days gives you a date in the next year that is on the same day of the week and occurs 1 or 2 days earlier in the month (or at the end of the prior month).
That leaves you with the problem of what to do with the first two days of the year. Presumably 'next year' is crucial, so the simple answer that 2013-12-31 is 52 weeks later than 2013-01-01 is not OK. In this case, you have to write a conditional expression, spelled CASE in SQL.
SELECT CASE WHEN YEAR(DATEADD(ref_date, INTERVAL 364 DAY)) = YEAR(ref_date)
THEN DATEADD(ref_date, INTERVAL 371 DAY)
ELSE DATEADD(ref_date, INTERVAL 364 DAY)
END
FROM ...wherever...
how do you wish it to deal with leap years? either save month and date and compare if 364 or 371 are closest to first day, and pick regardingly, or do nothing and face inaccuracy after a couple of years.
*saved_date* is the very first date before created new dates based on it
*passed_years* is increasing for every new since the first
date_add(last_date, INTERVAL (case when datediff(date_add(saved_date, INTERVAL passed_years YEAR), date_add(last_date, INTERVAL 371 DAY)) <= 3 then 371 else 364 end)) DAY)
The idea of this is to either fetch 52 or 53 weeks of the next year. leap years doesn't affect weekdays, but they "contribute" to an already existing problem; the date gets lower for each passing year if you only add 52 weeks each year without above solution.
Why not simply
CURDATE() + INTERVAL 52 WEEK`
Sure, it will be 1 or 2 days earlier in the 'calendar'.
mysql> SELECT NOW(), CURDATE() + INTERVAL 52 WEEK;
+---------------------+------------------------------+
| NOW() | CURDATE() + INTERVAL 52 WEEK |
+---------------------+------------------------------+
| 2017-09-05 15:50:46 | 2018-09-04 |
+---------------------+------------------------------+
If you need it to be 'later', then use 53.