0
votes

I have found a little Javascript function that compares dates and returns true when a certain date is within the range of two other dates. It's working fine mostly, but for some reason it returns false when the compared date is equal to the end date. It works with the start date though, that's why it's confusing me. Anyone see what I'm missing?

var dates = {
   convert:function(d) {
      // Converts the date in d to a date-object.
      return (
        d.constructor === Date ? d :
        d.constructor === Array ? new Date(d[0],d[1],d[2]) :
        d.constructor === Number ? new Date(d) :
        d.constructor === String ? new Date(d) :
        typeof d === "object" ? new Date(d.year,d.month,d.date) :
        NaN
      );
    },
    inRange:function(d,start,end) {
       // Checks if date in d is between dates in start and end.
       return (
        isFinite(d=this.convert(d).valueOf()) &&
        isFinite(start=this.convert(start).valueOf()) &&
        isFinite(end=this.convert(end).valueOf()) ?
        start <= d && d <= end :
        NaN
       );
    }
}

edit: Here are my inputs: I get my test data from a database, this is the output http://zoiglapp.bplaced.net/data/selectAll.php (sorry it doesn't look very pretty, but the important fields are zoiglBegin and zoiglEnd). As you can see, I have one timerange that ends on 2015-11-09 and one that starts there. The latter one is showing fine, the former one isn't showing up. This is my AngularJS Controller with the database data, the today variable and the compare function I found:

app.controller('HomeController', ['$scope', '$http', function($scope, $http) {
    $scope.today = new Date();
    $http.get("data/selectAll.php")
    .success(function(data) {
        $scope.lokale = data;
    });
    $http.get("data/selectCities.php")
    .success(function(data) {
        $scope.cities = data;
    });
    $scope.dates = {
        convert:function(d) {
            // Converts the date in d to a date-object.
            return (
                d.constructor === Date ? d :
                d.constructor === Array ? new Date(d[0],d[1],d[2]) :
                d.constructor === Number ? new Date(d) :
                d.constructor === String ? new Date(d) :
                typeof d === "object" ? new Date(d.year,d.month,d.date) :
                NaN
            );
        },
        inRange:function(d,start,end) {
            // Checks if date in d is between dates in start and end.
           return (
                isFinite(d=this.convert(d).valueOf()) &&
                isFinite(start=this.convert(start).valueOf()) &&
                isFinite(end=this.convert(end).valueOf()) ?
                start <= d && d <= end :
                NaN
            );
        }
    };
}]);

and here is where I call the function in the ngIf directive:

<div ng-repeat="city in cities | orderBy:'city'">
<h2>{{city.city}}</h2>
<accordion close-others="true">
    <accordion-group heading="{{lokal.name}}" ng-repeat="lokal in lokale | filter:city.city | orderBy:'name'" ng-if="dates.inRange(today, lokal.zoiglBegin, lokal.zoiglEnd)">
        [...]
</div>
1
what is the input to this function? - Minato
sample input I mean.. - Minato
Works ok for me here jsfiddle.net/zrqgqfy6 . So check your input... - Stepashka
Just tried this: s = new Date(2015,1,1); e = new Date(2015,12,31); dates.inRange(Date(2015,1,1),s,e); dates.inRange(Date(2015,12,31),s,e); both returned true... so not sure what your problem is - Simon Hänisch
@Minato I've edited the post to show my input - Linda

1 Answers

0
votes

The program is quite correct, but there is a problem with the input you are passing. The input you get from your service is only the date i.e d = "2015-11-11" converting it to date using dates.convert(d) call which internally calls new Date(d) since you only pass the date the Date object that is returned has an output like Fri Dec 11 2015 00:00:00 GMT+0500 (PKT) notice the time in the output that is the case when you only pass the date string but NOT the time. now since you're assigning today like

$scope.today = new Date(); //without the arguments.

Thee result will in something like Tue Nov 10 2015 09:44:12 GMT+0500 (PKT). Notice the time here. so the call to Date(); constructor outputs the CURRENT TIME and DATE. so when you compare it with the end date you might be falling SHORT of time since you might be comparing the 12:00AM or simply 00:00 being the end time with XX:XX AM/PM or XX:XX i.e. the current time on the clock where XX:XX AM/PM was greater than 12:00AM or XX:XX was greater than 00:00 so it returned false on comparison.

There are multiple option you can try one being in the later comment I suggested.

  1. First Option

    var x = new Date(); // This ass usual gives you the current date and time
    $scope.today = $scope.dates.convert([x.getFullYear(),x.getMonth(),x.getDate()]);
    

    This call here passes only today's date to the convert function as an array.

  2. Second Option a more cleaner one :P

    $scope.today = $scope.dates.convert((new Date()).toJSON().split("T")[0]);
    

    This call will simply split the time and date returned and Pass the date only to convert call like convert("2015-11-10")

  3. Third Option is fairly similar to the Second.

    $scope.today = new Date((new Date()).toJSON().split("T")[0]);
    

    this option saves a level of call and a few condition checks. but is bit dirtier IMHO.

Summary

You can avail your goal by using any of the three options provided Though I'd suggest to use either option 2 or 3 as both are similar but 3rd is computationally efficient.