【问题标题】:calculate frequency on certain range计算一定范围内的频率
【发布时间】:2009-08-10 09:38:31
【问题描述】:

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

例如,如果员工在特定日期每周(可以是每两周/每 2 周和每月)获得报酬(假设该员工在每个星期二获得报酬,而每月员工在特定日期获得报酬)。

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

是否可以使用 jodatime 进行计算?

举例说明这个问题:

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

另一个例子:

日期范围相同2009 年 8 月 14 日星期五至 9 月 14 日星期一(31 天) 但不同的付款日期.. 例如 星期日
所以他在 8 月 15 日、22 日和 29 日、9 月 5 日和 12 日...我们收到了 5 次付款。

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

所以我的问题是,有什么公式可以解决这种情况吗? 目前我使用手动迭代器进行计算.. 这非常慢(因为范围可能是几年或几个月)

谢谢

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

【问题讨论】:

  • 我不明白你想做什么。告诉我们您将采取的手动步骤。您必须使用比这两个日期(8 月 10 日和 12 月 31 日)更多的信息 它是什么?正确的答案是什么。
  • 好的 .. 我将编辑我的问题并提供清晰的示例
  • 频率是什么意思?
  • @max:特定日期范围内的付款频率。我提供了新的例子。请检查一下。

标签: java datetime time groovy


【解决方案1】:

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

可以计算天数、周数和月数,但您必须添加逻辑来处理不可靠的结束条件。正如我所描述的那样,这可能不是一个简单的公式。

【讨论】:

  • 从简单的开始:我应该会在 1 月 1 日到 6 月 30 日之间看到 12 份薪水。现在开始添加边缘情况。我会在 1 月 2 日到 6 月 30 日之间获得 11 个吗? 1 月 2 日和 6 月 29 日之间的 10 点?你明白了。
  • 用jodatime这些测试应该很容易,绝对+1
  • 你能解释更多吗?我刚刚添加了有关问题的示例。
  • 你的例子说明了一切。我认为你需要从尽可能大的单位开始——每周、每月等——然后从那里开始。总是要计算区间中最大的单位,然后处理栅栏问题,对吧?
【解决方案2】:

绝对,使用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);

【讨论】:

  • 如果只有日期相关,您也可以直接使用 DateMidnight。乔达++;
  • 您可以计算周数,但不能计算特定时期内发生的次数。顺便说一句,我只是为我的案例添加示例...... :)
【解决方案3】:

从另一个日期中减去一个日期以获得“天数”(或周数)通常是此类计算的错误方法。例如,如果某人是 365 天,那么他们正好是一岁,除非在那段时间有 2 月 29 日。在任何(现代)7 天期间,总是有一个星期二;但是8天,不是一两天。日历通常会影响计算。

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

【讨论】:

    【解决方案4】:

    这里有两个技巧:一个是规则因时间范围而异。我的意思是,如果一个人每周领一次工资,那么他在 7 天内领到一次工资,在 14 天内领到两次工资,依此类推。但是如果一个人在每个月的 1 号和 16 号领到工资,我就不能告诉您他在 60 天内获得了多少次报酬,但不知道包括哪些月份:它们是短月还是长月?

    第二个是您必须担心时间段的开始和结束。如果一个人每周一发工资,那么他在 8 天内发工资的次数取决于这 8 天的第一天是否是周一。

    因此,我认为对于固定天数的日程安排和与月份相关的日程安排或其他时间间隔可以变化的日程安排,我认为您需要有不同的逻辑。

    对于固定的天数,问题相当简单。唯一的复杂性是时间范围是否不是间隔的精确倍数。所以我想说,在发薪日发生的时间间隔中找到第一个日期。然后找出从那里到时间段结束之间的天数,除以间隔并删除任何分数。

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

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

    【讨论】:

      【解决方案5】:

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

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

      使用 groovyConsole 和 Joda Time 帮助进行测试 .. :)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-04-29
        • 2023-02-22
        • 1970-01-01
        • 1970-01-01
        • 2021-10-27
        相关资源
        最近更新 更多