【问题标题】:Moment.js - Duration within business/open/shift hours?Moment.js - 营业/营业/轮班时间内的持续时间?
【发布时间】:2018-04-26 17:25:51
【问题描述】:

提前感谢您的帮助。我正在尝试使用 moment.js 计算两个日期之间的持续时间,但我无法弄清楚如何只计算在我们的营业/营业时间内的时间(在我们的例子中是分钟)。

鉴于这些营业时间:

  • 周一至周五上午 8:00 至下午 6:00
  • Sa-Su 上午 10:00 至下午 2:00

简单的持续时间示例

如果作业从周四下午 4:00 开始,周五上午 9:30 结束,则持续时间为 210 分钟(下午 4 点至 6 点 = 120 分钟,上午 8 点至 9:30 = 90 分钟)。

不那么简单的持续时间示例

如果作业从周四下午 4:00 开始,周六上午 9:30 结束,则持续时间为 720 分钟(下午 4 点至下午 6 点 = 120 分钟,下午 8 点至下午 6 点 = 600 分钟,周五下午 6 点至周六上午 10 点之间的时间为不增加持续时间)

【问题讨论】:

    标签: javascript momentjs duration


    【解决方案1】:

    有一个基于 moment 构建的库来解决这个确切的问题。 https://www.npmjs.com/package/moment-business-time.
    我相信类似下面的例子对你有用。

    moment('2015-02-27T16:30:00Z').workingDiff(moment('2015-02-26T12:00:00Z'), 'hours');
    // 12 
    moment('2015-02-27T16:30:00Z').workingDiff(moment('2015-02-26T12:00:00Z'), 'hours', true);
    // 12.5 
    

    【讨论】:

      【解决方案2】:

      作为一般规则 - 不要在未显示您当前拥有的内容的情况下发布问题。要求免费工作是不受欢迎的。话虽如此 - 我也不认为仅仅使用图书馆来做这件事一定是如果你相对绿色的话。只有通过编码才能变得更好。

      我写了一个快速未完成的证明来获得分钟使用时刻。如果这是用于生产代码 - 不要使用它,这是一个示例供您查看并了解如何处理解决方案。 (有很多)。

      尝试查看代码,然后编写自己的实现。

      function isOutOfTimeRange(time, start, end) {
        var date = time.format('YYYY-MM-DD');
        var startDate = date + ' ' + start;
        var endDate = date + ' ' + end;
        if (!time.isBetween(startDate, endDate, 'minute')) {
          var timeFormatted = time.format('YYYY-MM-DD HH:mm');
          // If the time is exactly start or end time it should be ok to use
          if ((timeFormatted === startDate) || (timeFormatted === endDate)) {
            return false;
          }
          return true;
        }
        return false;
      }
      
      function isOutOfHours(time, businessHrs) {
        var day = time.day();
        var dayStart = businessHrs[day].start;
        var dayEnd = businessHrs[day].end;
      
        return isOutOfTimeRange(time, dayStart, dayEnd);
      }
      
      function getMinsWorked(startTime, endTime) {
        return moment.duration(endTime.diff(startTime)).as('minutes');
      }
      
      function minutesWorked(startJob, endJob, bizHrs) {
      
        var start = moment(startJob);
        var end = moment(endJob);
      
        // return early if the start and end time range is invalid
        if (end.isBefore(start, 'second')) {
          return 'A job cannot start after it has ended!';
        }
        // return early if start or end is not within business hours
        if (isOutOfHours(start, bizHrs) || isOutOfHours(end, bizHrs)) {
          console.log('The start and end date must not be out of hours');
        }
      
        var timeDiff = moment.duration(end.diff(start));
        var firstDay = start.day();
        var lastDay = end.day();
      
        // return early if we can make a quick calculation on the same day
        if (firstDay === lastDay) {
          // create a duration object by diffing the end and start dates and return as minutes
          return timeDiff.as('minutes');
        }
      
        var totalMinsWorked = 0;
        var endTime;
        var startTime;
      
        for (var i = firstDay; i <= lastDay; ++i) {
          var currentDay = start.add(i - firstDay, 'days');
          var dateStr = currentDay.format('YYYY-MM-DD');
          var dayStart = moment(dateStr + ' ' + bizHrs[i].start);
          var dayEnd = moment(dateStr + ' ' + bizHrs[i].end);
      
          // it's the last day so diff the end time from the start
          if (i === lastDay) {
            totalMinsWorked += getMinsWorked(dayStart, end);
          }
      
          // it's the first day so go from the start time
          if (i === firstDay) {
            totalMinsWorked += getMinsWorked(start, dayEnd);
          }
      
          // its a centre day so just get the dif of the start to the end
          totalMinsWorked += getMinsWorked(dayStart, dayEnd);
        }
        return totalMinsWorked;
      }
      
      console.log(minutesWorked('2018-05-16 10:00', '2018-05-16 12:30', [{ // index 0 is Sunday
          start: '10:00',
          end: '14:00'
        },
        {
          start: '08:00',
          end: '18:00'
        },
        {
          start: '08:00',
          end: '18:00'
        },
        {
          start: '08:00',
          end: '18:00'
        },
        {
          start: '08:00',
          end: '18:00'
        },
        {
          start: '08:00',
          end: '18:00'
        },
        { // index 6 is Sat
          start: '10:00',
          end: '14:00'
        }
      ]));
      &lt;script src="https://momentjs.com/downloads/moment.js"&gt;&lt;/script&gt;

      【讨论】:

        【解决方案3】:

        这是工作代码

        var start = moment( "start date with time here" );
        var end = moment( "end date with time here" );
        
        var bizHours = {
            1: { start: "09:00", end: "18:00" },
            2: { start: "09:00", end: "18:00" },
            3: { start: "09:00", end: "18:00" },
            4: { start: "09:00", end: "18:00" },
            5: { start: "09:00", end: "17:00" },
            6: { },
            7: { }
        };
        
        var minutes = minutesWorked(start, end, bizHours);
        console.log( minutes );
        
        
        
        // calculation function
        function minutesWorked(startJob, endJob, bizHrs) {
          if (end.isBefore(start, 'second')) {
            return 0;
          }
        
          var timeDiff = moment.duration(end.diff(start));
          var startDay = start.format('YYYY-MM-DD');
          var endDay = end.format('YYYY-MM-DD');
          var current = start;
          var currentDay = current.format('YYYY-MM-DD');
        
          var totalMin = 0;
          var endTime, startTime;
          var weekday, bizStartTime, bizEndTime, duration;
        
          do {
            weekday = current.format('E');
            bizStartTime = bizHrs[weekday].start;
            bizEndTime = bizHrs[weekday].end;
        
            if ( bizStartTime && bizStartTime ) {
                if (currentDay == startDay) {
                    startTime = start.format("HH:mm");
                    startTime = startTime > bizStartTime ? startTime : bizStartTime;
                    startTime = startTime < bizEndTime ? startTime : bizEndTime;
                } else {
                    startTime = bizStartTime;
                }
        
                if (currentDay == endDay) {
                    endTime = end.format("HH:mm");
                    endTime = endTime < bizEndTime ? endTime : bizEndTime;
                    endTime = endTime > bizStartTime ? endTime : bizStartTime;
                } else {
                    endTime = bizEndTime;
                }
        
                startTime = moment(currentDay + ' ' + startTime);
                endTime = moment(currentDay + ' ' + endTime);
        
                duration = moment.duration(endTime.diff(startTime)).as('minutes');
                totalMin += duration;
            }
        
            // next day
            current.add(1, "days");
            currentDay = current.format('YYYY-MM-DD');
          }
          while (currentDay <= endDay);
        
          return totalMin;
        }
        

        【讨论】:

          【解决方案4】:

          正如 Cruril 指出的那样,有一个名为 moment-business-time 的库可以处理这个问题,它是 Moment.js 的插件。

          问题是你不能在浏览器中运行插件,因为它是一个 Node 包。我冒昧地提取了脚本以避免所有讨厌的逻辑。使用browserify 有一张building a client script 的开放票。

          我记录了构建客户端脚本here 的步骤,但编译后的脚本仍然找不到workingDiff 函数。所以我包括了一个简化的;在下面的脚本中的时刻业务时间的工作版本。

          moment.updateLocale('en', {
            workinghours: {
              0: null,                       // Sun : CLOSED
              1: [ '12:00:00', '20:00:00' ], // Mon : 8am - 4pm  (local EDT)
              2: [ '12:00:00', '18:00:00' ], // Tue : 8am - 2pm  (local EDT)
              3: [ '12:00:00', '20:00:00' ], // Wed : 8am - 4pm  (local EDT)
              4: [ '12:00:00', '18:00:00' ], // Thu : 8am - 2pm  (local EDT)
              5: [ '12:00:00', '16:00:00' ], // Fri : 8am - 12pm (local EDT)
              6: null                        // Sat : CLOSED
            },
            holidays : []
          });
          
          moment.locale('en');
          moment.tz.setDefault("America/New_York"); // Timezone plugin
          
          var dateFormat = 'MM/DD/YYYY hh:mm:ss a';
          
          // 0 + 8 + 6 + 8 + 6 + (4 - 1.5) + 0 = 30.5
          var fromDate = moment('04/01/2018 00:00:00 am', dateFormat); // 2018-04-01T04:00:00.000Z
          var toDate   = moment('04/06/2018 02:30:00 pm', dateFormat); // 2018-04-06T18:30:00.000Z
          
          console.log(fromDate.workingDiff(toDate, 'hours'));       // 30 hours
          console.log(fromDate.workingDiff(toDate, 'hours', true)); // 30.5 hours
          .as-console-wrapper { top: 0; max-height: 100% !important; }
          <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.1/moment.min.js"></script>
          <script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.16/moment-timezone.min.js"></script>
          <script src="https://rawgit.com/rmkane/32084550b349eaebe7e78e46903084ce/raw/434cf510165a65c234a8cb1cb99641bc7ab15c16/moment-business-time.js"></script>
          
          <!--
          
          https://github.com/lennym/moment-business-time
          https://www.npmjs.com/package/moment-business-days#how-to-use
          
          -->

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-07-15
            • 2018-01-21
            • 2015-04-11
            • 2011-02-12
            • 1970-01-01
            • 2014-05-31
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多