Get duration between 2 dates with momentjs and angular-bootstrap Datepicker

Problem

I've put together 2 Datepickers from angular-bootstrap. I'm using moment.js to calculate the difference between the 2 Dates. The default difference is 20 hours between the Dates when you start the App. This gets calculated fine.

When I'm changing the End Date with the Popup Datepicker I'm getting a TypeError: undefined is not a function error.

The error is at the end in the duration function

return moment.duration(end.diff(start)).humanize();

where the diff(... starts.

This is the code:

angular.module('ui.bootstrap.demo', ['ui.bootstrap','angularMoment']);
angular.module('ui.bootstrap.demo').controller('DatepickerDemoCtrl', function($scope) {
  $scope.maxDate = new moment().add(100, 'y');

  // start date
  $scope.startDateToday = function() {
    $scope.startDate = new moment();
  };
  $scope.startDateToday();

  $scope.startDateClear = function() {
    $scope.startDate = null;
  };

  $scope.startDateOpen = function($event) {
    $event.preventDefault();
    $event.stopPropagation();

    $scope.startDateOpened = true;
  };

  // end date
  $scope.endDateToday = function() {
    $scope.endDate = new moment().add(20, 'h');
  };
  $scope.endDateToday();

  $scope.endDateClear = function() {
    $scope.endDate = null;
  };

  $scope.endDateOpen = function($event) {
    $event.preventDefault();
    $event.stopPropagation();

    $scope.endDateOpened = true;
  };

  // generic functions
  $scope.toggleMin = function() {
    $scope.minDate = new moment();
  };
  $scope.toggleMin();

  $scope.dateOptions = {
    formatYear: 'yy',
    startingDay: 1
  };

  $scope.formats = ['dd-MMMM-yyyy', 'yyyy/MM/dd', 'dd.MM.yyyy', 'shortDate'];
  $scope.format = $scope.formats[2];

  // duration
  $scope.getDuration = function(start, end) {
    return moment.duration(end.diff(start)).humanize();
  };

});
<!doctype html>
<html ng-app="ui.bootstrap.demo">
  <head>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.js"></script>
    <script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.12.0.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.8.4/moment.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-moment/0.8.3/angular-moment.js"></script>
    <script src="example.js"></script>
    <link href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet">
  </head>
  <body>

<div ng-controller="DatepickerDemoCtrl">
    <h4>Start Date</h4>
    <div class="row">
        <div class="col-md-6">
            <p class="input-group">
              <input type="text" class="form-control" datepicker-popup="{{format}}" ng-model="startDate" is-open="startDateOpened" min-date="minDate" max-date="{{maxDate}}" datepicker-options="dateOptions" ng-required="true" close-text="Close" />
              <span class="input-group-btn">
                <button type="button" class="btn btn-default" ng-click="startDateOpen($event)"><i class="glyphicon glyphicon-calendar"></i></button>
              </span>
            </p>
        </div>
    </div>
    <button type="button" class="btn btn-sm btn-info" ng-click="startDateToday()">Today</button>
    <button type="button" class="btn btn-sm btn-danger" ng-click="startDateClear()">Clear</button>

    <h4>End Date</h4>
    <div class="row">
        <div class="col-md-6">
            <p class="input-group">
              <input type="text" class="form-control" datepicker-popup="{{format}}" ng-model="endDate" is-open="endDateOpened" min-date="minDate" max-date="{{maxDate}}" datepicker-options="dateOptions" ng-required="true" close-text="Close" />
              <span class="input-group-btn">
                <button type="button" class="btn btn-default" ng-click="endDateOpen($event)"><i class="glyphicon glyphicon-calendar"></i></button>
              </span>
            </p>
        </div>
    </div>
    <button type="button" class="btn btn-sm btn-info" ng-click="endDateToday()">Today</button>
    <button type="button" class="btn btn-sm btn-danger" ng-click="endDateClear()">Clear</button>

    <hr />

    <div class="row">
        <div class="col-md-6">
		    <pre>Start Date: <em>{{startDate | date:'fullDate' }}</em></pre>
		</div>
    </div>
    <div class="row">
        <div class="col-md-6">
		    <pre>End Date: <em>{{endDate | date:'fullDate' }}</em></pre>
		</div>
    </div>
    <div class="row">
        <div class="col-md-6">
		    <pre>Duration: <em>{{getDuration(startDate, endDate)}}</em></pre>
		</div>
    </div>

</div>
</body>
</html>

If the Datepicker is not popping up, try the Plnkr. There's no error, but the duration gets set to undefined. Why is the getDuration function behaving this way?

Problem courtesy of: mles

Solution

Chabge getDuration to :

  $scope.getDuration = function(start, end) {
    try {
      return ((moment.duration(end - start)).humanize());
    } catch (e) {
      return "Cant evaluate"
    }
  };

Please see demo here http://plnkr.co/edit/G5eMB65rrcU3sN7rAR7N?p=preview

Solution courtesy of: sylwester

Discussion

There is currently no discussion for this recipe.

This recipe can be found in it's original form on Stack Over Flow.