Sorting and filtering on Date

I have a date column and need to be able to both sort and filter on it. The data comes in as strings like 2010-12-23 and can pre-processed as needed. It should be shown as 23.12.2010 . Some internationalization will come later.

I wonder what's the proper internal representation:

  • a string like "23.12.2010" is bad for sorting (it could be done by sorting on function result, but it'd be slow)
  • a string like "2010-12-23" sorts correctly, can be formatted easily, but filtering for 23.12 does not work (it could be done, but it'd be slow)
  • Date would probably get sorted correctly, but filtering would be slow
  • moment could be the solution, no idea
  • My current idea is to create an object containing both milliseconds and the displayed string, so that all operations can be fast. But I'd bet that someone was that smart before me....


    Let's assume that showing dates in the form like 2010-12-23 is unacceptable, otherwise the problem is solved. To summarize, the problem is that I need to

  • display and filter in the DD.MM.YYYY format
  • sort according to the numerical value (or equivalently, as if it was in th ISO format).

  • I think the method you're proposing wouldn't run in to too many performance issues, unless you're going for really old browsers or mobile devices.

    I've mocked up an example to do a quick (performance) test. First, I'm defining an object that holds a value optimized for sorting, and a value optimized for display:

    var MyDate = function(dateString) {
        var date = new Date(dateString);
        var displayValue = "{0}.{1}.{2}"
            .replace("{0}", prefixZeroIfNeeded(date.getUTCDate()))
            .replace("{1}", prefixZeroIfNeeded(date.getUTCMonth() + 1))
            .replace("{2}", date.getUTCFullYear());
    
        return {
            sortKey: date.getTime(),
            displayValue: displayValue
        };
    };
    

    The prefixZeroIfNeeded method ensures we get the DD.MM format rather than the dd.mm one:

    var prefixZeroIfNeeded = function(nr) {
        return nr < 10 ? "0" + nr : "" + nr;
    };
    

    Then, we need some data to convert:

    var data = [];
    var myDates = data
        .map(MyDate)
        .sort(function(date1, date2) {
            return date1.sortKey - date2.sortKey;
        });
    

    Finally, a quick example of a very basic search function:

    var searchMyDates = function(str) {
        return myDates.filter(function(myDate) {
            return myDate.displayValue.indexOf(str) !== -1;
        });
    };
    

    Now, we can create some mockup data and check how long it would actually take to A) map and sort the raw strings to the MyDate objects, and B) search for a string in our collection.

    Here's how I generated the raw data:

    for (var i = 0; i < 10000; i += 1) {
        var y = Math.floor(Math.random() * 101) + 1900;
        var m = prefixZeroIfNeeded(Math.floor(Math.random() * 13));
        var d = prefixZeroIfNeeded(Math.floor(Math.random() * 29));
    
        data.push(y + "-" + d + "-" + m);
    }
    

    Using console.time to measure, processing the data on my machine (A) takes around 40ms. Searching for the string .12. takes around 5-10ms.

    Concluding: I think you were definitely on the right track and could continue work in the proposed direction. However , in my personal experience, I've learned that whenever I start work on a feature that involves dates and times, moment.js is the way to go. You'll eventually run in to daylight saving time, time zones, you name it and regret you thought it was simple...

    Let me know if this is of any help.

    Edit: the code in a snippet (check your browser console for output)

    var data = [];
    
    var prefixZeroIfNeeded = function(nr) {
      return nr < 10 ? "0" + nr : "" + nr;
    };
    
    // Generate random data:
    for (var i = 0; i < 10000; i += 1) {
      var y = Math.floor(Math.random() * 101) + 1900;
      var m = prefixZeroIfNeeded(Math.floor(Math.random() * 13));
      var d = prefixZeroIfNeeded(Math.floor(Math.random() * 29));
    
      data.push(y + "-" + d + "-" + m);
    }
    
    
    
    var MyDate = function(dateString) {
      var date = new Date(dateString);
      var displayValue = "{0}.{1}.{2}"
        .replace("{0}", prefixZeroIfNeeded(date.getUTCDate()))
        .replace("{1}", prefixZeroIfNeeded(date.getUTCMonth() + 1))
        .replace("{2}", date.getUTCFullYear());
    
      return {
        sortKey: date.getTime(),
        displayValue: displayValue
      };
    };
    
    console.time("Map and sorting");
    
    var myDates = data
      .map(MyDate)
      .sort(function(date1, date2) {
        return date1.sortKey - date2.sortKey;
      });
    
    var searchMyDates = function(str) {
      return myDates.filter(function(myDate) {
        return myDate.displayValue.indexOf(str) !== -1;
      });
    };
    
    console.timeEnd("Map and sorting");
    
    console.time("Search");
    
    console.log("Searching for the month 12, %d results.", searchMyDates(".12.").length);
    
    
    console.timeEnd("Search");

    This may help you a bit. I have used the same thing working with React. Here is a link for Moment.js - http://momentjs.com/docs/#/displaying/format/ If you go under Display -> Format on the right menu bar, you'll see localized formats, you will need to use format L - pre defined format from moment which will show you 09/04/1986 (September 4, 1986); otherwise you can create your own using DD-MM-YYYY format.

    For Example, The way I used in React for my exercise is

    To define a variable using let: let deadlineFormated = Moment(this.props.ToDoItem.deadline).format('llll');

    Hope this helps for Angular!


    Gist: Decouple sorting and filtering. Do sorting on the internal representation and filtering on the presentation.

    Sort on internal representation that is in any naturally sortable format. Your raw YYYY-MM-DD date strings would work, so would parsing them into Date objects. The performance difference could be negligible unless you're dealing with lots and lots of rows -- but in that case you would already have other issues with latency and rendering performance.

    It's more intuitive if free-text filtering is done on what's displayed (the presentation). So if you're formatting the dates as "May 7, 2016", do a substring match on that. If you're formatting the dates as DD.MM.YYYY, do a substring match on that.

    If filtering is driven by actual date selections from controls like a date picker or a select field, you can do the filtering on the internal representation.

    链接地址: http://www.djcxy.com/p/91580.html

    上一篇: 我怎样才能围绕堆叠元素(即具有负边距的元素)换行?

    下一篇: 在日期排序和筛选