计算某个范围内的频率

时间:2009-08-10 09:38:32

标签: java datetime time groovy

我有数学问题......(目前我使用手动迭代解决了这个问题很慢)...

例如,如果一名员工每周获得一次付款(可以每两周一次,每两周一次),并且在某个日期付款(让我们在每个星期二打电话给员工付款,并且每个员工在特定日期付款)。

我的日期范围是2009年8月10日至2009年12月31日,现在如何获得员工获得报酬的频率?

是否可以使用jodatime来计算?

明确这个问题的例子:

  

我的日期范围介于 8月14日星期五 - 2009年9月14日星期一(31天)之间   员工在每个周二获得报酬   所以他得到了 18& 8月25日,1& 8月8日我们付了 4次付款   (频率)

另一个例子:

  

具有相同的日期范围 8月14日星期五 - 2009年9月14日星期一(31天)   但不同的支付日期...例如星期日
  所以他得到了报酬: 15,22& 8月29日,5& 9月12日 ...我们 5次付款。

相同的日期范围但不同的支付日...会产生不同的结果。

所以我的问题是,有没有解决这个案子的公式? 目前我使用手动迭代器计算..这非常慢(因为范围可能是几年或几个月)

谢谢

ps:我正在使用groovy ..欢迎任何使用java或groovy或只是算法的解决方案:)

5 个答案:

答案 0 :(得分:3)

支付期通常是在每个月的15日和月末,所以在这种情况下,您将计算月数并乘以2,检查结束条件(如果开始时间是在15日之前,则减去一个支付期;如果结束是在月末之后减去一个支付期间。)

可以获得天,周和月的计数,但您必须添加逻辑来处理恶劣的最终条件。它可能不是一个简单的公式,正如我所描述的情况所示。

答案 1 :(得分:1)

绝对地,使用Weeks类非常简单:

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

此代码给出20作为结果。是的吗?

修改

也许这样更好:

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);

答案 2 :(得分:0)

从另一个中减去一个日期以获得“天数”(或几周)通常是进行这些计算的错误方法。例如,如果有人是365天,他们正好一岁,除非在那段时间有2月29日。在任何(现代的)7天期间,总会有一个星期二;但是连续8天,它只有一两个。日历通常会计入计算中。

如果他们每月支付一次或两次,您可以在整个月内轻松计算 - 从第一个月开始到月末最后一天结束,这会有所不同 - 然后你必须考虑部分开始和/或结束的几个月。 (不要忘记如果一个月的第15天或最后一天是周末会发生什么。)如果他们每一周或两周付钱,你可以在一个已知的发薪日同步,然后做更简单的数学计算整个星期之前和/或之后。 (不要忘记发薪日的假期。)

答案 3 :(得分:0)

这里有两个技巧:一个是规则根据时间范围而有所不同。我的意思是,如果一个人每周支付一次,那么在7天内他得到一次报酬,在14天内他得到两次报酬等等。但是如果一个人在每个月的1日和16日得到报酬,我就不能告诉你他在60天内被支付了多少次而不知道包括哪些月份:他们在哪里短期或长月?

第二个是您必须担心时间段的开始和结束。如果每个星期一有人获得报酬,那么他在8天内获得报酬的次数取决于8日的第一天是否是星期一。

因此,我认为您需要对固定天数的计划以及与月份或其他间隔可能不同的其他计划相关的计划具有不同的逻辑。

对于固定的天数,问题非常简单。唯一的复杂性是时间范围不是间隔的精确倍数。所以我要说,找到发薪日的第一个日期。然后找出它与时间段结束之间的天数,除以间隔并删除任何分数。

例如:每周一支付一个人。 3月1日到4月12日之间的工资天数是多少?找到该范围内的第一个星期一。假设它落在3月4日。然后计算从3月4日到4月12日的天数。这将是39. 39/7 = 5和一小部分。因此,他获得了5个薪水,总共6个。

对于月薪,我认为你必须将第一个月和上个月分开。然后,您可以计算中间的月数,并乘以每月的工资数。然后,对于第一个和最后一个计数,其中有多少是困难的。

答案 4 :(得分:0)

刚拿到解决方案,请检查我是否做错了

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}");

使用带有Joda Time帮助的groovyConsole测试.. :))