views:

381

answers:

5

Hi,

I have maths problem ... (at the moment i solved it using manual iteration which is pretty slow) ...

For example if an employee got paid weekly (it can be fortnightly / every 2 weeks and monthly) with certain date (let's call the employee got paid every tuesday and for monthly the employee paid on certain date).

I have date range between 10th August 2009- 31 December 2009, now how to get frequency the employee got paid ?

is it possible to calculate this using jodatime ?

Example to make this question clear:

I have date range between Friday 14 August - Monday 14 Sept 2009 (31 days) the employee got paid on every Tuesday so he got paid on 18 & 25 August, 1 & 8 August we got 4 times payment (frequency)

another example:

with the same date range Friday 14 August - Monday 14 Sept 2009 (31 days) but different pay date .. for example on Sunday
so he got paid on : 15, 22 & 29 August , 5 & 12 September ... we got 5 times payment.

same date range but different pay day .. will result different.

So my question is, are there any formula to solve this case ? at the moment I calculate using manual iterator .. which is very slow (because the range could be some years or months)

thank you

ps: I am using groovy .. any solutions using java or groovy or just algorithm are welcome :)

+2  A: 

Oftentimes pay periods are on the 15th and the end of every month, so in that case you'd count the number of months and multiply by 2, checking the end conditions (if start is before the 15th, subtract one pay period; if end is after end of the month subtract one pay period).

It's possible to get counts of days, weeks, and months, but you'll have to add in the logic to handle the dodgy end conditions. It's probably not a simple formula, as the case I described demonstrates.

duffymo
good idea, how to write a good testcase?
dfa
Start with the easy one: I should see 12 paychecks between 1-Jan and 30-Jun. Now start adding in edge cases. Do I get 11 between 2-Jan and 30-Jun? 10 between 2-Jan and 29-Jun? You see the idea.
duffymo
with jodatime these tests should be very easy, definitevely +1
dfa
can you explain more ? I have just add the examples on the question.
nightingale2k1
Your examples say it all. I think you need to start with the largest unit possible - weekly, monthly, etc. - and work your way in from there. It's always about counting that largest unit in the interval and then dealing with the fencepost problem, right?
duffymo
+1  A: 

abosolutely, using the Weeks class is very simple:

DateTime start = new LocalDate(2009, 8, 10).toDateTimeAtStartOfDay();
DateTime end = new LocalDate(2009, 12, 31).toDateTimeAtStartOfDay();
int numberOfWeeks = Weeks.weeksBetween(start, end).getWeeks();

this code give 20 as result. It is right?

EDIT

maybe this is better:

DateMidnight start = new DateMidnight(2009, 8, 10);
DateMidnight end = new DateMidnight(2009, 12, 31);
int numberOfWeeks = Weeks.weeksBetween(start, end).getWeeks();
System.out.println(numberOfWeeks);
dfa
You could also use DateMidnight directly if only date is relevant. joda++;
Esko
@Esko, nice suggestion see my edit, thanks
dfa
you can calculate the weeks but not how much occurrences happened during certain period. btw I just add the examples for my case ... :)
nightingale2k1
A: 

Subtracting one date from the other to get the "number of days" (or weeks) is generally the wrong way to go for these kinds of calculations. For example, if someone is 365 days old, they are exactly one year old, unless there was a February 29 during that time. In any (modern) 7-day period, there is always exactly one Tuesday; but for 8 days, it's either one or two. The calendar often figures into the calculations.

If they're paid once or twice a month, you do the easy calculation on the whole months -- starting on the first and ending on the last day of the month, which varies -- and then you have to consider partial months at the beginning and/or end. (Don't forget what happens if the 15th or last day of the month falls on a weekend.) If they're paid every one or two weeks, you can sync on a known payday, and then do the simpler math to figure the whole weeks before and/or since. (Don't forget holidays that fall on the payday.)

Ken
A: 

There are two tricks here: One is that the rules are different depending on the time frame. I mean, if a person is paid once a week, then in 7 days he gets paid once, in 14 days he gets paid twice, etc. But if a person is paid on the 1st and 16th of every month, I can't tell you how many times he was paid in 60 days without knowing what months were included: where they short months or long months?

The second is that you have to worry about the start and end of the time period. If a person is paid every Monday, then the number of times he gets paid in 8 days depends on whether the first day of the 8 is Monday.

Thus, I think you need to have different logic for schedules that are a fixed number of days and those that are tied to months or something else where the intervals can vary.

For the fixed number of days, the problem is fairly simple. The only complexity is if the time frame is not an exact multiple of the interval. So I'd say, find the first date in the interval on which a payday occurs. Then find the number of days between there and the end of the time period, divide by the interval and drop any fractions.

For example: A person is paid every Monday. How many pay days between March 1 and April 12? Find the first Monday in that range. Say it falls on March 4. Then calculate the number of days from March 4 to April 12. That would be 39. 39/7=5 and a fraction. Therefore he gets paid 5 more paychecks, for a total of 6.

For monthly pay, I think you'd have to separate out the first and last month. You could then count the number of months in the middle and multiply by the number of pays per month. Then for the first and last count how many are in them the hard way.

Jay
A: 

Just got solutions please check if I did something wrong

import org.joda.time.* ; 

def start = new Date().parse("dd/MM/yy","14/08/2009");
def end = new Date().parse("dd/MM/yy","14/09/2009");

println("date range ${start} - ${end}");

def diff = end - start ; 
println("diff : ${diff} days ");
println("how many weeks : ${diff/7}");

def payDay = 2 ; // Monday = 1 Sunday = 0  

def startDay = new DateTime(start).dayOfWeek ; // 5 = Thursday 

def startDayDiff = payDay - startDay ; 
if(startDay > payDay){
   startDayDiff = 7 + payDay - startDay ;
}

// for example if end on Friday (5) while Pay day is day 1 (Monday) then 
// make sure end date is on Monday (same week )
// end date = end - ( endDay - payDay)


def endDay = new DateTime(end).dayOfWeek;
println("original end day: ${endDay}");
def endDayDiff = endDay - payDay ; 

// otherwise ... if endDay < payDay (for example PayDay = Friday but End day is on Monday)
// end date = end - 7 + payDay 
if(endDay < payDay){
   endDayDiff =  7 - endDay - payDay ;
}
println("endDayDiff : ${endDayDiff}");
println("startDayDiff:  ${startDayDiff}");

def startedOn = new DateTime(start).plusDays(startDayDiff);
println("started on : ${startedOn.toDate()}");

def endOn = new DateTime(end).minusDays(endDayDiff);
println("End on : ${endOn.toDate()}");

println("occurences :  ${Weeks.weeksBetween(startedOn,endOn).getWeeks()+1}");

Tested using groovyConsole with Joda Time help .. :)

nightingale2k1