0

I have been working with OrangeHRM for a project. It uses the Yui Calendar. I have been working on the leave module. The Leave module lets the user choose a From and To Date - A time frame for which he wants to apply leave !

I want to show the number of Working Days once the user has chosen the dates . A Simple Subtract statement would not work because I want to exclude the Saturdays and Sundays from the equations since they don't count as working days !

function fillToDate(frmLeaveApp) {

    var fromdate = frmLeaveApp.elements['txtLeaveFromDate'];
        var todate = frmLeaveApp.elements['txtLeaveToDate'];
            var result = frmLeaveApp.elements['txtLeaveTotalDay'];

     if(!fromdate || !todate || !result) {
        return;
    }

        var a = fromdate.value;
        var b = todate.value;

        var c = a.split('-');
        var d = b.split('-');

        var ac = new Date();
        ac.setFullYear(c[2], c[1], c[0]);
        var bd = new Date();
        bd.setFullYear(d[2], d[1], d[0]);

        result.value = (bd.getTime() - ac.getTime()) / (60*60*24*1000);
}

How do I do it ? Thanks in advance !

  • @RobG - Yes - The Public Holidays too . –  Jul 21 '11 at 07:18
  • Here: http://stackoverflow.com/questions/59934/national-holiday-web-service – mplungjan Jul 21 '11 at 07:46
  • @mplungjan Thanks for both the links! That helped a bit but right now what I need to do is I have two dates Date 1 = 27-08-2011 Date 2 = 29-08-2011 How do I subtract them ? Does YUI have any function for the same ? or do I need to write my own code ! –  Jul 21 '11 at 07:52
  • You mean DateMath http://mattsnider.com/javascript/yui-datemath-on-javascript-date-object/ - hmm does not cover working days – mplungjan Jul 21 '11 at 07:57
  • @mplungjan Exactly ! I want to remove the weekends from the equation ( and at a later stage - remove Public holidays too ) . –  Jul 21 '11 at 08:10
  • Here is something more likely to do what you want http://objectmix.com/javascript/801796-javascript-business-days-calendar-calculation.html http://lawrence.ecorp.net/inet/samples/js-date-fx.shtml – mplungjan Jul 21 '11 at 08:11
  • @mplungjan - the "national holiday web service" covers about 2% of countries and less than 10% of the world's population - perhaps there is a better resource? And how do you tell which holidays are observed by which user? – RobG Jul 22 '11 at 05:11
  • @RobG In this Case - Orange HRMS lets you define the company Holidays - which I guess will have to take and then exclude it from the calendar ! –  Jul 22 '11 at 05:35

3 Answers3

0

Not super proud of this solution - must be more elegant ways, but it should work - does not handle national holidays yet

Demo here

function fillToDate(frmLeaveApp) {

    var fromdate = frmLeaveApp.elements['txtLeaveFromDate'];
    var todate = frmLeaveApp.elements['txtLeaveToDate'];
    var result = frmLeaveApp.elements['txtLeaveTotalDay'];

    if(!fromdate || !todate || !result) {
        return;
    }

    var from = new Date(fromdate.value.replace(/\-/g,"/"));
    var to = new Date(todate.value.replace(/\-/g,"/"));

    // brute force seems the quickest to find
    var res = 0;
    var aDay = 24*60*60*1000;
    for (var i = from.getTime(), n=to.getTime();i < n; i+=aDay) {
      var d = new Date(i).getDay();
      if (d!=0 && d !=6) res++;
    }
    result.value = res;
}
mplungjan
  • 169,008
  • 28
  • 173
  • 236
  • This worked just perfectly with a bit of changes . For some weird reasons - I had to use the values 2 and 3 for Saturday and Sunday Any idea why ? –  Jul 21 '11 at 12:52
  • No. If you did, then there is a problem with the code or with the dates. I assumed yyyy/mm/dd. 0 is Sunday and 6 is Saturday – mplungjan Jul 21 '11 at 13:19
  • Works fine ! Just that I added i<=n so that even the to and from dates are counted. Thanks ! –  Jul 21 '11 at 14:59
0

A simple solution not that great :)

In YUI calendar, selected date cell has 'selected' class.

Saturday cell has 'wd6' and Sunday has 'wd0' classes.

Get all the cells which has 'selected' class and filter and remove cells which have 'wd6' and 'w0' classes.

var cells = Y.one("#calContainer").all('.selected');
var res = 0;

for (var i = 0, i < cells.length; i++) {
      if (!cells[i].hasClass('.wd6') || !cells[i].hasClass('.wd0')) res++;
    }

return res;

I haven't tested this code.

Aneesh
  • 1,193
  • 3
  • 16
  • 26
0

There are a few things here. Firstly, to get the number of days between two dates far more efficiently than already offered:

/*
   Get the number of days between two dates - not inclusive.

   "between" does not include the start date, so days
   between Thursday and Friday is one, Thursday to Saturday
   is two, and so on. Between Friday and the following Friday is 7.

   e.g. getDaysBetweenDates( 22-Jul-2011, 29-jul-2011) => 7.

   If want inclusive dates (e.g. leave from 1/1/2011 to 30/1/2011),
   use date prior to start date (i.e. 31/12/2010 to 30/1/2011).

   Only calculates whole days.
*/
function getDaysBetweenDates(d0, d1) {

  var msPerDay = 8.64e7;

  // Copy dates so don't mess them up
  var x0 = new Date(d0);
  var x1 = new Date(d1);

  // Set to noon - avoid DST errors
  x0.setHours(12,0,0);
  x1.setHours(12,0,0);


  // Round to remove daylight saving errors
  return Math.round( (x1 - x0) / msPerDay );
}

To get the number of "business" days, work out the number of whole weeks, multiply by 5, then adjust for remainder days and weekends at the start and finish. If you want to include the start date (typical for leave), use a start date one day before the nominated date. e.g. a leave application from Mon 4-Jul-2011 to Fri 8-Jul-2011 is 5 days of leave.

On the other hand, 5 business days from Mon 4-Jul-2011 is usually the following Monday, 11-Jul-2011 but might be COB on Fri 8-Jul-2011. The rules for such things can be different depending on local custom, legal precedent, contract agreement, and so on.

Also, such simple algorithms are rarely sufficient anyway. Public holidays mess things up, as does different working weeks in different places. Some are Saturday to Wednesday - Thursday and Friday are "weekend" days. In other places, Saturday is a work day (6 day week). Also, public holidays may fall on weekends.

/* 
   Simple algorithm: each week has 5 business days: Monday
   to Friday inclusive. Saturday and Sunday are non-working
   days.
*/

function getBusinessDaysBetweenDates(d0, d1) {
  var days = getDaysBetweenDates(d0, d1);
  var bWeeks = (days/7)|0;
  var rDays = days%7;
  var startDay = d0.getDay();
  var endDay   = d1.getDay();

  // If not whole weeks, adjust for weekends
  if (rDays) {

    // Adjust for start on weekend, end any day
    if (startDay == 6) {
      rDays -= 1;
    } else if(startDay == 5) {
      rDays -= (rDays == 1)? 1 : 2;

    // Adjust for start on business day
    // and end on weekend
    } else if (endDay == 6) {
      rDays -= 1;

    // Adjust for going over whole weekend
    } else if (endDay < startDay) {
      rDays -= (rDays == 1)? 1 : 2;
    }
  }
  return bWeeks * 5 + rDays;
}

If you want to include public holidays that fall on days from Monday to Friday, you'll need another function that uses a calendar of public holidays and returns how many fall on business days between the subject dates. There might also be holidays for specific industries, professions, religions and so on.

RobG
  • 142,382
  • 31
  • 172
  • 209
  • Since I suck at math and do not trust algorithms just found on the net, I posted a brute force one which will work just fine for small periods. But great if your code works. I just cannot determine that by eyeballing it. – mplungjan Jul 23 '11 at 08:12
  • "Brute force" is probably ok in many cases for calculations like pay or leave, it's only really a problem when doing lots of them. Doing calendaring for any kind of HR system (leave, pay, scheduling, etc.) is really quite complex when all the business rules and cultural differences are added in. Adding and subtracting days is just the tip of the iceberg. :-) – RobG Jul 23 '11 at 13:27