Search code examples
c++cron

C++: Get the last week day of any month


i am working on a code to parse cron format

After going through the different syntax i got stuck on the 'L' operator, specifically on the '3L' which will give me the last Wednesday of the month (e.g the last Wednesday of September 2021 is going to be 29th ) the number 3 is the number of day :

0 = Sunday
1 = Monday
.
.
6 = Saturday

i looked through the internet and i cant find anything that can help me (i dont want use any libraries)

i found this code which calculates the last Friday of every month, i want to change it so i can get the last week day of my choice of any month i want.

EDITED

#include <iostream>
using namespace std;

class lastFriday
{
    int lastDay[12];  //to store last day of all month//хранить последний день всего месяца
    int year; //for given year//за данный год
    string m[12];  // to store names of all 12 months//хранить имя всех 12 месяцев
    bool isleap;  // to check given year is leap year or not//проверить, является ли год високосным или нет
 private:
    //function to find leap year//функция поиска високосного года
    void isleapyear()
    {
        if ((year % 4))
        {
            if (year % 100)
                isleap = true;
            else if ((year % 400))
                isleap = true;
        }
    }

    // to display last  friday of each month
    void display()
    {
        for (int x = 0; x < 12; x++)
            cout << m[x] << lastDay[x] << endl;
    }

    //function to find last friday for a given month 
    int getWeekDay(int m, int d)
    {
        int y = year;

        int f = y + d + 3 * m - 1;
        m++;
        if (m < 3)
            y--;
        else
            f -= int(.4 * m + 2.3);

        f += int(y / 4) - int((y / 100 + 7) * 0.75);
        f %= 7;

        return f;
    }
 public:
    //set name of 12 months
    lastFriday()
    {
        m[0] = "JANUARY:   "; m[1] = "FEBRUARY:  "; m[2] = "MARCH:     "; m[3] = "APRIL:     ";
        m[4] = "MAY:       "; m[5] = "JUNE:      "; m[6] = "JULY:      "; m[7] = "AUGUST:    ";
        m[8] = "SEPTEMBER: "; m[9] = "OCTOBER:   "; m[10] = "NOVEMBER:  "; m[11] = "DECEMBER:  ";
    }

    //function to find last fridays
    void findLastFriday(int y)
    {
        year = y;

        //to check given year is leap year or not
        isleapyear();

        //if given year is leap year then feb has 28 else 29 
        int days[] = { 31, isleap ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };  // to set number of days for each month
        int d;

        //for all 12 months we have to find last friday
        for (int i = 0; i < 12; i++)
        {
            d = days[i];
            while (true)
            {
                if (!getWeekDay(i, d))
                    break;
                d--;
            }
            lastDay[i] = d;
        }

        //function call to print display dates of last friday for each month
        display();
    }
};

int main()
{
    int year;  //to store year given by user
    lastFriday LF;

    cout << "Enter the year in the range 1970 to 2037 : ";
    cin >> year;

    //validation for year between 1970 to 2037 
    if (year>2037|year<1970)
    {
        cout << "Not available for this year";
    }
    else
    {
        LF.findLastFriday(year);
    }

    return 0;
}

can anyone help me understand interpreting this code. thanks!


Solution

  • I found a solution for my problem and I want to share it with you, maybe someone can find it helpful.

    I mentioned in my question that i want to get the day of month of the last weekday of any month. First, in the cron format, if you want to specify that you could write it like this: "0 14 10 ? SEP 3L ?" this means, execute every last Wednesday of September on 10:14:00. For that to work in my code, I need to get which day of month is on Wednesday,

    This code is a portion of my project, but I will try explaining everything,

    else if (contains(str[5],'L'))
    {
        if (str[5] == "L") bdaysOfWeekDesc[6]=6;
        else
        {
            int diff;
            auto parts = split(str[5],'L');
            auto LDoM = LastDay(stoi(monthReplaced),currentYear);
            tm time_in = { 0, 0, 0, LDoM, stoi(monthReplaced)-1, currentYear - 1900};
                  time_t time_temp = mktime(&time_in);
                  const tm * time_out = localtime(&time_temp);
                  if (stoi(parts[0].data()) == time_out->tm_wday)
                  {
                      bdaysOfMonthsDesc[time_out->tm_mday] = time_out->tm_mday;
                  }
                  else if ((stoi(parts[0].data()) > time_out->tm_wday) || time_out->tm_wday ==0 )
                  {
                      diff = time_out->tm_wday - stoi(parts[0].data());
                      for(size_t j=0;j<=sizeof(bdaysOfMonthsDesc) / sizeof(bdaysOfMonthsDesc[0]);j++)
                        {
                          bdaysOfMonthsDesc[j]=0;
                          bdaysOfMonthsDesc[time_out->tm_mday + abs(diff) - 7] = time_out->tm_mday + abs(diff) - 7;
                        }
                  }
                  else if (stoi(parts[0].data()) < time_out->tm_wday)
                  {
                      diff = time_out->tm_wday - stoi(parts[0].data());
                      for(size_t j=0; j <= sizeof(bdaysOfMonthsDesc) / sizeof(bdaysOfMonthsDesc[0]); j++)
                        {
                          bdaysOfMonthsDesc[j] = 0;
                          bdaysOfMonthsDesc[time_out->tm_mday - abs(diff)] = time_out->tm_mday - abs(diff);
                        }
                  }
        }
    }
    
    • the split function is for splitting the field according to the separator given e.g: auto parts = split("3L", 'L'); parts[0] equals to "3"

    • the contains function checks if a character exists in a string or not e.g: contains("3L", 'L');

    the split and contains functions are from the croncpp

    • The LastDay function returns the last day (30 or 31 or 28 or 29) of the month given. This function is from @saqlain response on an other thread

    At first, I need to get the date for last day of the month so:

    tm time_in = {seconds, minutes, hours, dayOfMonth, Month, year-1900}
    

    seconds: 0-based,
    minutes: 0-based,
    hours: 0-based,
    DOM: 1-based day,
    Month: 0-based month ( the -1 in the code is because my month's field is 1-based)
    year: year since 1900

    with the mktime() and localtime() functions I can get which weekday is on the 30th or 31st of the month

    After that, I tested if the week day I am requesting in the cron format is the same as the weekday of the last day of month,
    or if it's superior or inferior.

    With this code, my problem was solved, and maybe it can help someone else.