-1

I have 2 date values and a set of rows which have a range defined as discount_start_month and discount_end_month. The current situation is that I only have month information as below, there is no year data to compare the input 2 dates values with these months.

The goal is to take the date and see in between which range of months they fall into. At any given point of time they may fall into any of discount_code

For Eg: A date 01 January 2022 would come under DEC_JAN row. A date 01 December 2021 would still come uder DEC_JAN row

Problem:

  1. The problem statement is without year information how would you check in which range do the input dates lie ?
  2. Once I figure out (1), I need to generate 2 dates with the values advance_start_month and advance_end_month, so for the above it would be ,

2 dates would be named as startDateGeneration and endDateGeneration

startDateGeneration would be generated from the discount_code's advance_start_month,

considering example 01 January 2022, the startDateGeneration would be generated from DEC_JAN's advance_start_month and advance_end_month

day -> first day of the month of October (from advance_start_month)

Month -> October

Year -> Previous year

startDateGeneration would be 01 October 2021

Same for endDateGeneration, we would use the advance_end_month so it would be 01 January 2022

enter image description here

Inputs are start date and end date.

Code to find the dates in range by iterating over the above dataset.

private static boolean isInRange(
      LocalDate discountDate, Integer fromMonth, Integer toMonth) {
    YearMonth fromMonthDiscount = YearMonth.of(discountDate.getYear(), fromMonth);
    YearMonth toMonthDiscount = YearMonth.of(discountDate.getYear(), toMonth);
    YearMonth yearMonthDiscountDate =
        YearMonth.of(discountDate.getYear(), discountDate.getMonthValue());

    if (fromMonth > toMonth) {
      if (discountDate.getMonthValue() == Constants.DEC_MONTH) {
        toMonthDiscount = YearMonth.of(discountDate.getYear() + 1, toMonth);
      } else if (discountDate.getMonthValue() == Constants.JAN_MONTH) {
        fromMonthDiscount = YearMonth.of(discountDate.getYear() - 1, fromMonth);
      }
    }

    return (yearMonthDiscountDate.isAfter(fromMonthDiscount)
            || yearMonthDiscountDate.equals(fromMonthDiscount))
        && (yearMonthDiscountDate.isBefore(toMonthDiscount)
            || yearMonthDiscountDate.equals(toMonthDiscount));
  }

Logic to find the problem statement (2) part,

 int startYear = fromDate.getYear();
    int endYear = toDate.getYear();
    
    // Get the advance_start_month from the DB iterating object of the start date
    int advanceStartMonth = ....
    
    if(advanceStartMonth >= Constants.OCT_MONTH &&
        advanceStartMonth <= Constants.DEC_MONTH &&
        startYear == endYear) {
        startYear = startYear - 1;
    }
    
    // Get the advance_start_month and advance_end_month from the DB iterating object of the end date  
    int discountResultStartMonth = //.......
        int discountResultEndMonth = //........
    
        if (discountResultStartMonth > discountResultEndMonth) {
            if (toDate.getMonthValue() == Constants.DEC_MONTH) {
                endYear = endYear + 1;
            }
        }

Logic for forming the dates to generate a range out of these,

fromDateSeasonMap -> Dataset for 1 row from the above dataset(for start date) toDateSeasonMap -> Dataset for 1 row from the above dataset(for end date)

LocalDate startDateGeneration =
          fromDate
              .withMonth((Integer) fromDateSeasonMap.get(Constants.ADVANCE_START_MONTH))
              .withYear(startYear);
      LocalDate endDateGeneration =
          toDate
              .withMonth((Integer) toDateSeasonMap.get(Constants.ADVANCE_END_MONTH))
              .withYear(endYear)
              .withDayOfMonth(
                  YearMonth.of(endYear, (Integer) toDateSeasonMap.get(Constants.ADVANCE_END_MONTH))
                      .atEndOfMonth()
                      .getDayOfMonth());

Notes:

  1. At any given point of time there would be no overlapping months in the dataset.
  2. Only Months numerical data is present.
  3. There would be no values greater than 12 as there are only 12 months in a year.

Expected Input and output

Begin Input
Start Date: 2023-08-01
End Date: 2023-10-01
startDateGeneration: 2023-06-01
endDateGeneration: 2023-11-30
===================================
Begin Input
Start Date: 2023-09-01
End Date: 2023-12-01
startDateGeneration: 2023-07-01
endDateGeneration: 2024-01-31
===================================
Begin Input
Start Date: 2023-01-30
End Date: 2023-02-01
startDateGeneration: 2022-11-30
endDateGeneration: 2023-03-31
===================================
Begin Input
Start Date: 2023-01-30
End Date: 2023-02-01
startDateGeneration: 2022-11-30
endDateGeneration: 2023-03-31
===================================
Begin Input
Start Date: 2022-10-30
End Date: 2023-02-01
startDateGeneration: 2022-08-30
endDateGeneration: 2023-03-31
===================================
Begin Input
Start Date: 2022-08-30
End Date: 2022-10-01
startDateGeneration: 2022-06-30
endDateGeneration: 2022-12-31
===================================
Begin Input
Start Date: 2022-08-30
End Date: 2023-02-01
startDateGeneration: 2022-06-30
endDateGeneration: 2023-03-31
===================================
Begin Input
Start Date: 2023-04-30
End Date: 2023-07-01
startDateGeneration: 2023-02-28
endDateGeneration: 2023-07-31
===================================
Begin Input
Start Date: 2023-06-30
End Date: 2023-07-01
startDateGeneration: 2023-04-30
endDateGeneration: 2023-07-31
===================================
Begin Input
Start Date: 2023-08-30
End Date: 2023-10-01
startDateGeneration: 2023-06-30
endDateGeneration: 2023-12-31
===================================
Begin Input
Start Date: 2023-10-30
End Date: 2024-01-01
startDateGeneration: 2023-08-30
endDateGeneration: 2024-03-31
===================================
Begin Input
Start Date: 2022-12-30
End Date: 2023-02-01
startDateGeneration: 2022-10-30
endDateGeneration: 2023-03-31
===================================
Begin Input
Start Date: 2023-01-30
End Date: 2023-02-01
startDateGeneration: 2022-10-30
endDateGeneration: 2023-03-31
===================================
Begin Input
Start Date: 2022-10-01
End Date: 2023-02-01
startDateGeneration: 2022-07-01
endDateGeneration: 2023-03-31
===================================
Begin Input
Start Date: 2022-12-01
End Date: 2023-02-01
startDateGeneration: 2022-10-01
endDateGeneration: 2023-03-31
===================================
Begin Input
Start Date: 2023-02-01
End Date: 2023-04-01
startDateGeneration: 2022-12-01
endDateGeneration: 2023-05-31
===================================
Begin Input
Start Date: 2023-02-01
End Date: 2023-03-01
startDateGeneration: 2022-12-01
endDateGeneration: 2023-03-31
===================================
Begin Input
Start Date: 2023-04-30
End Date: 2023-06-01
startDateGeneration: 2023-02-28
endDateGeneration: 2023-07-31
===================================
Begin Input
Start Date: 2023-06-30
End Date: 2023-08-01
startDateGeneration: 2023-04-30
endDateGeneration: 2023-08-31
===================================
oldcode
  • 1,669
  • 3
  • 22
  • 41
  • 1
    I am sorry, I can’t follow. I think I need a representative assortment of example inputs with desired outputs. – Ole V.V. May 15 '23 at 04:43
  • @OleV.V. The start date and end date are inputs the expected outputs are `startDateGeneration` and `endDateGeneration` – oldcode May 15 '23 at 06:37
  • @OleV.V. Let me know if this helps or would you need more details – oldcode May 15 '23 at 06:48
  • I am still far from understanding it all. So these are guesses, and you must deem whether they are right or not: 1. If start_month > end_month, the row spans New Year. In this case a date is in the range if monthOfDate <= end_month || monthOfDate >= start_month. In the opposite case, not crossing New Year, the condition is monthOfDate >= start_month && monthOfDate <= end_month. 2. Similarly if advance_start_month > discount_start_month, then the “advance” period (whatever that is) starts the year before, so subtract 1 from the year. – Ole V.V. May 15 '23 at 18:25
  • @OleV.V. 1. Your first condition should be `&&` 2. the advance_start_month will always be less than the discount_start_month – oldcode May 16 '23 at 04:06
  • @OleV.V. I have edited the question and added more details with date examples, describing how the flow is . This should help you else let me know how I can help in further understanding. – oldcode May 16 '23 at 04:31
  • 1. I put `||` (or) there on purpose. If the date is 2023-12-19, discount_start_month is 12 and end month 1, then if I do 12 <= 1 && 12 >= 12, then it will never be true even thought the date is within the interval from December through January. With `||` it will be true for dates in December and January and no other dates. 2. In the FEB_MAR row discount_start_month is 2 and advance_start_month is 12. And 12 is not less than 2. I think this was why you asked that question to begin with? I am sorry, I am about to give up on helping you. – Ole V.V. May 16 '23 at 06:05
  • @OleV.V. ` I think this was why you asked that question to begin with?` the current logic is handled for Dececmber month what if the month was 10 or 11 in the `discount_start_month`. `I am sorry, I am about to give up on helping you.` Oops ! Is this a complex question or you are having trouble to understand it ? – oldcode May 16 '23 at 06:58
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/253674/discussion-between-ole-v-v-and-oldcode). – Ole V.V. May 16 '23 at 09:41
  • @oldcode, I'll give this a try. I was planning on just creating my own objects and using `Calendar` for comparison, if needed. Any objections? – Reilas May 24 '23 at 22:53
  • @oldcode, for `isInRange`, there is a `discountDate` parameter. What is this value? I thought the input was a start and end date. – Reilas May 25 '23 at 00:22
  • @oldcode, and finally, your "expected output" data has, for example, and start and end date of 2023-08-01 and 2023-10-01. The discount start and end dates appear to only extend for 1 month, how would this match any of the data-sets? – Reilas May 25 '23 at 00:26
  • @Reilas For SeasonId `101` , the `advance_start_month` for `2023-08-01` is `06` from above table as shown in screenshot and the advance_end_month for `2023-10-01` is `11` – oldcode May 25 '23 at 11:45
  • 1
    It is probably pretty easy to implement the logic you need. However, I cannot help but wonder why anyone would shoot themselves in their own feet like this, making a simple matter complicated. Why don't you use actual dates instead of strange combinations of months and "seasons" for designating the beginnings and ends of discount periods? Did somebody decide that this would not be complicated enough and then make it harder on purpose? – kriegaex May 29 '23 at 10:27
  • 1
    Besides, you never explained how seasons translate to years and what the advance dates actually mean. It seems like the advance start month is always two months prior to the discount start and the advance end always identical to the discount end. Therefore, you can automatically calculate them. Who designs such a system? A masochist maybe - no offence meant. – kriegaex May 29 '23 at 10:29
  • @kriegaex - You cannot use the actual dates an actual date might lie anywhere between the range, the problem is to detect the `advance_start_month` and the valid year for it. Lets say if the season id is `101` and the actual date could lie anywhere between April and May you would have to pick up this info from database and then simply subtract the month from `advance_start_month`. – oldcode Jun 01 '23 at 12:16
  • @kriegaex -`Therefore, you can automatically calculate them` , not always I have given here some limited examples here. `Besides, you never explained how seasons translate to years` you cannot store year info as storing year info would make it invalid for next year. That is why you have to explicitly derive the year from the months ? Wouldn't it be dumb to store the year info when the table could have the same data for years and years ? – oldcode Jun 01 '23 at 12:18
  • No, it would not be dumb. Storing exact dates for each period would unburden you from calculating dates with a complex algorithm. This premature optimisation to try and store as little info as possible in the DBMS probably neither saves any significant amount of storage space nor does it yield any performance gain. Furthermore, you would be more flexible in the future. What if for some reason business comes up with the idea to have a special Xmas discount from 05-Dec to 10-Jan? If you simply store dates, you can do that. If you assume that forever it will be full months, you cannot. – kriegaex Jun 01 '23 at 13:10
  • What actually is "dumb" (I mean suboptimal) - pardon my French, I am just using your own words - is the current design. You are trying to solve a home-grown problem you would not even have if you would simply store dates. This is not unlike masturbation - being busy, playing with yourself. No disrespect, I am just trying to make a point and be very clear. Ever heard about the KISS principle? – kriegaex Jun 01 '23 at 13:12
  • @kriegaex you are not trying to understand the point my friend, we cannot store the dates only months can be stored, how can you even think of storing the full date with the years, the logic should work for any year not only the ones that is stored. This month info is like a configuration and it set for years and years. Why would anyone store the dates and then modify the year logic in Database every year to make the logic working ? – oldcode Jun 02 '23 at 14:19
  • If you only explain a small part of the story, how am I supposed to know more than you tell? Your statement that I am not _trying_ to understand is false, otherwise why would I bother commenting? I cannot read your mind, and your specification is incomplete. SO is not a discussion forum, but a Q/A platform. Just look at the sheer number of comments your question has provoked. Ideally it should just be a question and an answer. Anyway, this is a waste of time. I am out of here, good luck. – kriegaex Jun 02 '23 at 15:58
  • @kriegaex `If you only explain a small part of the story, how am I supposed to know more than you tell? ` I posted a question with all details, deleted it as I got comments feedback was to shorten the question, I argued and explained making it short will not do any good, so had to delete the question and posted a new one with only core logic you can take a look here as you have enough rep to view deleted question[actual question](https://stackoverflow.com/questions/76248877/comparing-months-without-years-data-for-all-date-usecases) – oldcode Jun 03 '23 at 15:19
  • Maybe next time, just ask a clear, concise question with some code and link the question to a GitHub repository with a full, minimal sample project reproducing your situation. Next to nobody feels inclined to copy many code snippets into their IDEs, then noticing that some small part or a build configuration is missing. Like others said here and over in the other question before, it is kind of difficult to find out what the actual question is. Again, good luck to you. – kriegaex Jun 11 '23 at 08:34
  • @kriegaex I have removed lot of verbose information. Please let me know if you can read through it and understand ? – oldcode Jun 16 '23 at 19:24

2 Answers2

0
private static boolean isInRange(
    LocalDate discountDate, Integer fromMonth, Integer toMonth) {
  int discountYear = discountDate.getYear();

  if (fromMonth > toMonth) {
    if (discountDate.getMonthValue() == Constants.DEC_MONTH) {
      toMonth += 12;
    } else if (discountDate.getMonthValue() == Constants.JAN_MONTH) {
      fromMonth -= 12;
    }
  }

  return discountDate.getMonthValue() >= fromMonth && discountDate.getMonthValue() <= toMonth;
}

and

int startYear = fromDate.getYear();
int endYear = toDate.getYear();
int advanceStartMonth = fromDateSeasonMap.get(Constants.ADVANCE_START_MONTH);
int advanceEndMonth = toDateSeasonMap.get(Constants.ADVANCE_END_MONTH);

if (advanceStartMonth >= Constants.OCT_MONTH && advanceStartMonth <= Constants.DEC_MONTH && startYear == endYear) {
  startYear -= 1;
}

if (advanceEndMonth >= Constants.OCT_MONTH && advanceEndMonth <= Constants.DEC_MONTH && startYear == endYear) {
  endYear -= 1;
}

if (advanceEndMonth < advanceStartMonth) {
  if (toDate.getMonthValue() == Constants.DEC_MONTH) {
    endYear += 1;
  }
}

LocalDate startDateGeneration = fromDate.withMonth(advanceStartMonth).withYear(startYear);
LocalDate endDateGeneration = toDate.withMonth(advanceEndMonth).withYear(endYear);

// Adjust the end day of the month for endDateGeneration
int lastDayOfMonth = YearMonth.of(endYear, advanceEndMonth).lengthOfMonth();
endDateGeneration = endDateGeneration.withDayOfMonth(lastDayOfMonth);

Hope that helps, the question isn't very clear, but this could help you.

1 1
  • 3
  • 2
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community May 30 '23 at 05:15
0

To handle the logic for isInRange when the start month is greater than the end month, you can modify the logic as follows:

private static boolean isInRange(LocalDate discountDate, Integer fromMonth, Integer toMonth) {
    int discountYear = discountDate.getYear();
    int discountMonth = discountDate.getMonthValue();

    if (fromMonth <= toMonth) {
        return discountMonth >= fromMonth && discountMonth <= toMonth;
    } else {
        if (discountMonth >= fromMonth || discountMonth <= toMonth) {
            return true;
        } else {
            if (discountMonth == Constants.JAN_MONTH && toMonth == Constants.DEC_MONTH) {
                return true;
            }
            if (discountMonth == Constants.DEC_MONTH && fromMonth == Constants.JAN_MONTH) {
                return true;
            }
        }
    }

    return false;
}

This logic handles the case when the start month is greater than the end month by considering the special cases of December (12) and January (1).

To handle the year generation logic based on the dataset, you can use the following approach:

  1. Get the start year from the fromDate object.
  2. Get the end year from the toDate object.
  3. Retrieve the advance_start_month and advance_end_month from the dataset.
  4. Check if the advance_start_month falls between October (10) and December (12) inclusive, and the start year is the same as the end year. If true, decrement the start year by 1.
  5. Check if the advance_end_month is less than the advance_start_month. If true, check if the toDate month is December (12) and increment the end year by 1.

Here's an example implementation of the year generation logic:

int startYear = fromDate.getYear();
int endYear = toDate.getYear();

// Get the advance_start_month from the DB iterating object of the start date
int advanceStartMonth = ...; // Retrieve the value from the dataset

if (advanceStartMonth >= Constants.OCT_MONTH && advanceStartMonth <= Constants.DEC_MONTH && startYear == endYear) {
    startYear = startYear - 1;
}

// Get the advance_start_month and advance_end_month from the DB iterating object of the end date
int advanceEndMonth = ...; // Retrieve the value from the dataset

if (advanceEndMonth < advanceStartMonth) {
    if (toDate.getMonthValue() == Constants.DEC_MONTH) {
        endYear = endYear + 1;
    }
}

By following this approach, you can generate the correct start and end years for the startDateGeneration and endDateGeneration objects.

Please note that you need to retrieve the corresponding values from the dataset for advance_start_month and advance_end_month as mentioned in the code comments.

I hope I've understand the question correctly, it was hard to follow.

I.sh.
  • 252
  • 3
  • 13