vertigoelectric
vertigoelectric

Reputation: 1327

How can I get the date of the Nth weekday of a given month in a MySQL query?

I've searched for answers and while I've found similar questions answered online I've been unable to use them for my purpose. I need help.

I'm building a calendar which supports recurring events. I'm almost done, but the final piece is the toughest. I need to be able to support events that occur on the Nth X of every Y months, where X is a given weekday and Y is a number of months.

I've already figured out the "every Y months" part (which is the 2nd to the last line in the query segment below). I just need to get the "Nth weekday".

I found a PHP script someone created that claims to solve this wonderfully, and I planned on using it, but then I realized that this must be done entirely within the MySQL query because the values specifying which weekday to get the date for are part of the db record and I cannot get them to use outside of the main query.

Here's a portion of the query so you can get an idea of where I'm headed with this:

WHEN event_recurring_pattern_type = 'monthly' AND event_recurring_monthly_type = 'dayxofeveryxmonths' THEN
    MOD(PERIOD_DIFF(CONCAT(event_date_year,event_date_month), CONCAT('$date_year','$date_month')), event_recurring_monthly_dayofeveryxmonths) = 0
    AND event_recurring_monthly_dayx = '$date_day'

WHEN event_recurring_pattern_type = 'monthly' AND event_recurring_monthly_type = 'thexweekdayofeveryxmonths' THEN
    MOD(PERIOD_DIFF(CONCAT(event_date_year,event_date_month), CONCAT('$date_year','$date_month')), event_recurring_monthly_dayofeveryxmonths) = 0
    AND '$date_timestamp' = {the date of the Nth weekday of $date_month}

The last line there should compare the calendar's current output date (as it builds the calendar one day at a time) with the date of the Nth weekday of whatever month we're on during the output process. When they match up, that event will be output onto the calendar.

$date_timestamp is the current output date in 'YYYY-MM-DD' format in this case, so the Nth weekday I get the date for should also be in that format.

If I haven't given enough information, or if this has been adequately answered elsewhere, please let me know. One of my previous questions was "closed" because some people thought it was too vague or didn't give enough info, even though I gave plenty of information relevant to my question and still received a perfectly acceptable answer that solved my problem. Give me a chance to improve a question if necessary before performing negative actions.

Thanks in advance.

Oh yeah, and if this can be further created to optionally get the LAST specified weekday of the given month, that would be even better. The PHP script did that, but like I said, I can't do this with PHP this time.

Upvotes: 1

Views: 919

Answers (3)

R. Flowers
R. Flowers

Reputation: 1

I am going to try this (not been proven in the field yet) :

 SET @target = DATE('2013-06-15');
SELECT  1 + ( 
 IF( MONTH(DATE_SUB( @target, INTERVAL  7 DAY)) = MONTH(@target), 1, 0) +
 IF( MONTH(DATE_SUB( @target, INTERVAL 14 DAY)) = MONTH(@target), 1, 0) +
 IF( MONTH(DATE_SUB( @target, INTERVAL 21 DAY)) = MONTH(@target), 1, 0) +
 IF( MONTH(DATE_SUB( @target, INTERVAL 28 DAY)) = MONTH(@target), 1, 0) ) AS nth_weekday_of_month;

It seems relatively quick, but you could always create a pre-populated table (a few years out, or created by crons, etc.) with this function.

Upvotes: 0

Justin ᚅᚔᚈᚄᚒᚔ
Justin ᚅᚔᚈᚄᚒᚔ

Reputation: 15369

Use DAYOFWEEK():

WHEN event_recurring_pattern_type = 'monthly'
 AND event_recurring_monthly_type = 'thexweekdayofeveryxmonths'
THEN MOD(
       PERIOD_DIFF(
         CONCAT(event_date_year,event_date_month),
         CONCAT('$date_year','$date_month')
       ), event_recurring_monthly_dayofeveryxmonths
     ) = 0
 AND DAYOFWEEK('$date_timestamp') = event_recurring_monthly_dayofweek

The above assumes the addition of the event_recurring_monthly_dayofweek column, but you could just as easily re-use the event_recurring_monthly_dayx column to store the day-of-week integer.

Upvotes: 1

Mark Ransom
Mark Ransom

Reputation: 308121

The easiest way is to write a program to populate a new table with the information you need. It wouldn't require a very large table to go a long way into the future. Then just join to the table in your query.

Upvotes: 0

Related Questions