【问题标题】:How to filter json data by date range in javascript如何在javascript中按日期范围过滤json数据
【发布时间】:2015-11-05 19:13:20
【问题描述】:

我想按开始日期和结束日期过滤下面的 json 数据,它应该返回开始日期和结束日期之间的数据,我尝试使用下面的代码来实现,但我做错了过滤。我是 Javascript 和 jquery 等前端技术的新手,如果有人能纠正我在这里做错了什么,我将不胜感激:

<html>
    <head>
        <title>Test</title>

    </head>

    <body>

        <script type="text/javascript">
            var product_data = [
                {
                    "productId": "12",
                    "productName": "ProductA",
                    "productPrice": "1562",
                    "ProductDateCreated": "2015-07-24T12:58:17.430Z",
                    "TotalProduct": 294
                },
                {
                    "productId": "13",
                    "productName": "ProductB",
                    "productPrice": "8545",
                    "TotalProduct": 294,
                    "ProductHits": {
                        "2015-08-01T00:00:00Z"
                    }
                },
                {
                    "productId": "14",
                    "productName": "ProductC",
                    "productPrice": "8654",
                    "TotalProduct": 78,
                    "ProductHits": {
                        "2015-08-10T00:00:00Z"
                    }
                },
                {
                    "productId": "15",
                    "productName": "ProductD",
                    "productPrice": "87456",
                    "TotalProduct": 878,
                    "ProductHits": {
                        "2015-05-12T00:00:00Z"
                    }
                }
            ];

            var startDate = "2015-08-04";
            var endDate = "2015-08-12";

            var resultProductData = product_data.filter(
                    function (a)
                    {
                        return (a.ProductHits) > startDate && (a.ProductHits) < endDate;
                    });
            console.log(resultProductData);
        </script>

    </body>
</html>

【问题讨论】:

  • 你比较字符串。你必须比较日期。解决方案:将字符串转换为 Date 对象并进行比较。编辑: ProductHits 不是字符串。它是一个对象。您必须转换此对象的所有键并一一进行比较。
  • 如何将key转化为对象?
  • 第一:请告诉我为什么你的日期字符串中冒号后面有空格?
  • 第二:请告诉我 ProductHits 的规则。有多个条目(日期)。它们都匹配范围还是只匹配其中一个?
  • aaand(最后一个 ;))。你确定它是 ProductHits 而不是 ProductDateCreated 吗?在我看来,这会更有意义......

标签: javascript jquery json


【解决方案1】:
        var startDate = new Date("2015-08-04");
        var endDate = new Date("2015-08-12");

        var resultProductData = product_data.filter(function (a) {
            var hitDates = a.ProductHits || {};
            // extract all date strings
            hitDates = Object.keys(hitDates);
            // convert strings to Date objcts
            hitDates = hitDates.map(function(date) { return new Date(date); });
            // filter this dates by startDate and endDate
            var hitDateMatches = hitDates.filter(function(date) { return date >= startDate && date <= endDate });
            // if there is more than 0 results keep it. if 0 then filter it away
            return hitDateMatches.length>0;
        });
        console.log(resultProductData);

小提琴:http://jsfiddle.net/4nz1ahuw/


UPDATE 正如 Ates Goral 在 cmets 中建议的那样,上述解决方案可以通过使用 Array.protype.some 进行优化:

        var startDate = new Date("2015-08-04");
        var endDate = new Date("2015-08-12");

        var resultProductData = product_data.filter(function (a) {
            var hitDates = a.ProductHits || {};
            // extract all date strings
            hitDates = Object.keys(hitDates);
            // improvement: use some. this is an improment because .map()
            // and .filter() are walking through all elements.
            // .some() stops this process if one item is found that returns true in the callback function and returns true for the whole expression
            hitDateMatchExists = hitDates.some(function(dateStr) {
                var date = new Date(dateStr);
                return date >= startDate && date <= endDate
            });
            return hitDateMatchExists;
        });
        console.log(resultProductData);

谢谢你的好建议:)

【讨论】:

  • 您也可以使用Array.prototype.some 作为优化:return Object.keys(a.ProductHits || {}).some(function (dateStr) { var date = new Date(dateStr); return date &gt;= startDate &amp;&amp; date &lt;= endDate; });(在匹配的那一刻终止迭代。)
  • @AtesGoral 好建议。如果需要,请随时将其作为更新块编辑到帖子中。谢谢你:)
  • 我的荣幸。我不想破坏您原始答案的清晰度:)
  • @AtesGoral 将您的解决方案添加到答案中。我希望它也有明确的记录;)
  • @jquerybeginner 这取决于您的时区。看到日期末尾的 -0700 了吗? 17:00:00 点 + 7 小时为午夜。如果您想将日期转换为 GMT +0,您可以使用 Date.prototype.getTimezoneOffset()Date.prototype.valueOf()。但想一想:这重要吗?所有日期都以相同的方式更改,您可以将它们与更大和更低的运算符进行比较。所以……没关系;)
【解决方案2】:

我无法使上述解决方案发挥作用。我发现对批准的答案 that worked for me here 进行了轻微修改。下面的代码 sn-p 完成了工作。

var startDate = new Date("2015-08-04");
var endDate = new Date("2015-08-12");

var resultProductData = product_data.filter(a => {
  var date = new Date(a.ProductHits);
  return (date >= startDate && date <= endDate);
});
console.log(resultProductData)

【讨论】:

  • 谢谢,这无疑帮助了我! @Seunope
【解决方案3】:

对您来说,日期值需要这样封装,例如。新日期(您的日期值)

使用以下示例作为指导给出了另一种方法:

https://jsfiddle.net/ladiv7/tb66ya67/

/*Dummy Data, Courtesy of: https://www.generatedata.com/*/
var dataDates = [{
    "date": "Nov 28, 2017",
    "name": "Samuel A. Kidd",
    "email": "dui.nec@sapienimperdietornare.ca",
    "address": "944-343 Nec Avenue"
  },
  {
    "date": "May 20, 2015",
    "name": "Jenna R. Alston",
    "email": "semper.auctor.Mauris@acrisus.edu",
    "address": "5316 Mollis Av."
  },
  {
    "date": "Mar 11, 2018",
    "name": "Magee K. Mcfarland",
    "email": "Maecenas@egetmollis.co.uk",
    "address": "Ap #605-1298 Id Rd."
  },
  {
    "date": "Dec 9, 2016",
    "name": "Claudia V. Campbell",
    "email": "Donec@semegestas.ca",
    "address": "Ap #935-7909 Lectus Rd."
  },
  {
    "date": "Aug 4, 2015",
    "name": "Steven V. Reynolds",
    "email": "est.ac@ut.net",
    "address": "Ap #501-8119 Vel, Rd."
  },
  {
    "date": "Mar 25, 2019",
    "name": "Amy O. Bean",
    "email": "risus.quis.diam@adipiscingelitEtiam.org",
    "address": "1855 Euismod Ave"
  },
  {
    "date": "Jan 12, 2019",
    "name": "Quintessa H. Clay",
    "email": "arcu.Sed.eu@variusNam.net",
    "address": "P.O. Box 127, 812 Lobortis Rd."
  },
  {
    "date": "Feb 7, 2015",
    "name": "Marvin P. Golden",
    "email": "pellentesque@lobortistellusjusto.org",
    "address": "P.O. Box 936, 8921 Augue Av."
  },
  {
    "date": "Aug 4, 2015",
    "name": "Shay Z. Clayton",
    "email": "sem.egestas@maurisidsapien.org",
    "address": "5862 Pede St."
  },
  {
    "date": "Feb 12, 2015",
    "name": "Jin G. Jimenez",
    "email": "dictum.magna@parturientmontes.org",
    "address": "4310 Malesuada Av."
  },
  {
    "date": "Feb 10, 2017",
    "name": "Dawn R. Blackwell",
    "email": "risus.varius.orci@ipsumdolor.com",
    "address": "5585 Metus. St."
  },
  {
    "date": "Apr 28, 2015",
    "name": "Audra A. Gates",
    "email": "consectetuer.adipiscing@libero.ca",
    "address": "448-332 Iaculis Ave"
  },
  {
    "date": "May 6, 2018",
    "name": "Gloria K. Dodson",
    "email": "mauris.Integer.sem@purusinmolestie.co.uk",
    "address": "564-3879 Vel, St."
  },
  {
    "date": "Jan 1, 2015",
    "name": "Inga I. Vinson",
    "email": "Donec@enimnec.net",
    "address": "320-4632 Lacus. Road"
  },
  {
    "date": "Jul 21, 2015",
    "name": "Berk M. Owen",
    "email": "eros@mi.co.uk",
    "address": "727 Bibendum Ave"
  },
  {
    "date": "Feb 27, 2016",
    "name": "Jessica C. Thompson",
    "email": "Donec@anteNunc.com",
    "address": "P.O. Box 903, 2394 A, St."
  }
];



$(document).ready(function() {

  $('.datepicker').datepicker(); //Activates the datepicker Materialize CSS element

  preview_json(dataDates, $("#view_rawData")); //show the original data on the screen
  $("#count_RawData").html("(" + dataDates.length + ")");

  $("#filter-button").click(function(e) {

    console.log("Hello world");

    //Gets the form data in a unified manner
    var getFormData = {
      dates: {
        start: $("#date_from").val(),
        end: $("#date_to").val()
      }
    };

    //Function to filter the result
    var filteredData = dateFilterer(dataDates, getFormData.dates.start, getFormData.dates.end);
    preview_json(filteredData.finalValues, $("#view_filteredData")); //show the final result on the screen
    $("#count_FilteredData").html("(" + filteredData.finalValues.length + ")");

  });


});


//Filter function to ensure that the final result set is within a particular range
function dateFilterer(sourceValues, startDate, endDate) {

  /*Curtosy of the tutorial found here: https://www.w3schools.com/jsref/jsref_filter.asp*/
  function filterFunction_dates(sourceValue) {

    //Aim: To test if the tested date is valid within a particular range
    var rangeAcceptance = {
      minValid: new Date(sourceValue.date) >= new Date(startDate),
      maxValid: new Date(sourceValue.date) <= new Date(endDate)
    };

    var acceptanceResult; //boolean to determine if the relevant range specified is valid

    if (startDate != "" && endDate != "") {

      acceptanceResult = (rangeAcceptance.minValid && rangeAcceptance.maxValid);

    } else if (startDate != "") {

      acceptanceResult = rangeAcceptance.minValid;

    } else if (endDate != "") {

      acceptanceResult = rangeAcceptance.maxValid;

    } else {

      acceptanceResult = (1 == 1); //show all results if no specific range has been selected

    }

    return (acceptanceResult);

  }

  /*console.log({

    originalValues: sourceValues,
    finalValues: sourceValues.filter(filterFunction_dates),
    "time of filter": new Date()

  });*/

  //Return the data for display
  return ({

    originalValues: sourceValues,
    finalValues: sourceValues.filter(filterFunction_dates)

  });

}



//Aim: To make the dates into something that the Range filter function can work with
function normalize_date(fieldValue) {

  var monthPossibilities = {
    longStructure: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
    shortStructure: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
  }; //To store what the month values could possibly be for returning their relevant index number

  var datePartitions = fieldValue.split(", ");
  var year = datePartitions[1];
  var month = datePartitions[0].substring(0, 3); //first three characters of section 1

  if (monthPossibilities.longStructure.indexOf(month) > -1) {

    month = (monthPossibilities.longStructure.indexOf(month) + 1).toString(); //Increments by one to give the actual month number

  } else if (monthPossibilities.shortStructure.indexOf(month) > -1) {

    month = (monthPossibilities.shortStructure.indexOf(month) + 1).toString();

  } else {

    month = "";

  }

  //Aim: Add that customary zero to prepend the date value
  if ((month.length < 2) && (month.length > 0)) {

    month = "0" + month;

  }

  var day = datePartitions[0].slice(-2); //last two characters of section 1    
  var finalResult = year + "-" + month + "-" + day;

  return (finalResult);

}




//Aim: Display json in a nicely formatted way
function preview_json(data, target) {

  /*Curtosy of fellow fiddler: http://jsfiddle.net/unLSJ/*/
  var library = {};

  library.json = {
    replacer: function(match, pIndent, pKey, pVal, pEnd) {
      var key = '<span class=json-key>';
      var val = '<span class=json-value>';
      var str = '<span class=json-string>';
      var r = pIndent || '';
      if (pKey)
        r = r + key + pKey.replace(/[": ]/g, '') + '</span>: ';
      if (pVal)
        r = r + (pVal[0] == '"' ? str : val) + pVal + '</span>';
      return r + (pEnd || '');
    },
    prettyPrint: function(obj) {
      var jsonLine = /^( *)("[\w]+": )?("[^"]*"|[\w.+-]*)?([,[{])?$/mg;
      return JSON.stringify(obj, null, 3)
        .replace(/&/g, '&amp;').replace(/\\"/g, '&quot;')
        .replace(/</g, '&lt;').replace(/>/g, '&gt;')
        .replace(jsonLine, library.json.replacer);
    }
  };

  //Show json in desired target
  target.html(library.json.prettyPrint(data));

}
#count_RawData {
  color: #89cbfa;
}

#view_rawData,
#view_filteredData {
  min-height: 50px;
  max-height: 700px;
  overflow-y: scroll;
  width: 100%;
  box-shadow: 0 0 5px #cfcfcf;
  border-radius: 5px;
  border: none;
}

#count_FilteredData {
  color: #498e88;
}

#filter-button {
  width: 100%;
}

#filter_section {
  width: 100%;
  margin-left: auto;
  margin-right: auto;
  padding: 20px;
  /* background-color: #f1f1f1; */
  border: 1px solid #cfcfcf;
}


/*Curtosy of the fellow fiddler's code: http://jsfiddle.net/unLSJ/*/

pre {
  background-color: ghostwhite;
  border: 1px solid silver;
  padding: 10px 20px;
  margin: 20px;
}

.json-key {
  color: brown;
}

.json-value {
  color: navy;
}

.json-string {
  color: olive;
}


/*Update the scrollbar*/

::-webkit-scrollbar {
  width: 7px;
}

::-webkit-scrollbar-track {
  -webkit-box-shadow: inset 0 0 10px rgb(255, 255, 255);
  border-radius: 10px;
}

::-webkit-scrollbar-thumb {
  border-radius: 10px;
  -webkit-box-shadow: inset 0 0 6px rgba(132, 144, 154);
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0" />
  <title>JSON - Date Range Filter Concept</title>

  <!-- CSS  -->
  <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">

  <link href="https://materializecss.com/templates/starter-template/css/style.css" rel="stylesheet" />
  <link href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0-beta/css/materialize.min.css" rel="stylesheet" />

  <link href="css/style.css" type="text/css" rel="stylesheet" media="screen,projection" />

</head>

<body>

  <nav class="light-blue lighten-1" role="navigation">
    <div class="nav-wrapper container"><a id="logo-container" href="#" class="brand-logo">JSON Date Range Filter</a>
      <ul class="right hide-on-med-and-down">
        <li><a href="#">Home</a></li>
      </ul>

      <ul id="nav-mobile" class="sidenav">
        <li><a href="#">Home</a></li>
      </ul>

      <a href="#" data-target="nav-mobile" class="sidenav-trigger">
        <i class="material-icons">menu</i>
      </a>
    </div>
  </nav>

  <div class="container">

    <div class="section">

      <!--   Raw Data Section   -->
      <div class="row">
        <div class="col s12">
          <div class="icon-block">
            <h4 class="center">Raw Data <small id="count_RawData">(0)</small></h4>
            <pre id="view_rawData" class="light">
              Your raw data will be previewed here
            </pre>
          </div>
        </div>
      </div>

      <!--Filter Form-->
      <div class="row center" id="filter_section">
        <div class="input-field col s6">
          <input id="date_from" type="text" placeholder="From" class="datepicker">
        </div>
        <div class="input-field col s6">
          <input id="date_to" type="text" placeholder="To" class="datepicker">
        </div>
        <button id="filter-button" class="btn-large waves-effect waves-light">Filtra</button>
      </div>

      <!--   Filtered Data Section   -->
      <div class="row">
        <div class="col s12">
          <div class="icon-block">
            <h4 class="center">Filtered Data <small id="count_FilteredData">(0)</small></h4>
            <pre id="view_filteredData" class="light">
              Your final data will be previewed here
            </pre>
          </div>
        </div>
      </div>

    </div>

    <br><br>
  </div>

</body>

</html>


<script src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0-beta/js/materialize.min.js"></script>
<script src="https://materializecss.com/templates/starter-template/js/init.js"></script>

【讨论】:

  • 看来您忘记包含示例了 ^
  • 您想要 iframe,还是只想链接到 Fiddle? iframe 在这里不起作用(谢天谢地)。
  • 我的错……谢谢你的英特尔。刚刚更新了帖子以获得更清晰的信息。希望它可以帮助那里的人。
【解决方案4】:

这就是我在two 日期之间进行过滤的方式。我正在从yesterday 过滤数据到last7Days

public itemFilter()
{ 
  var now = new Date();
  let yesterday=new Date(new Date().getTime() - (1 * 24 * 60 * 60 * 1000));
  let last7Days=new Date(new Date().getTime() - (7 * 24 * 60 * 60 * 1000));
  var data=obj.filter(p => new Date(p.LastSeenDate) <= yesterday && new Date(p.LastSeenDate) >= last3Days);     
}

这里LastSeenDate是我们产品的日期。

【讨论】:

    【解决方案5】:

    嗨,你可以使用时刻

    moment('2010-10-20').isBetween('2010-10-19', '2010-10-25');
    

    这里是文档的链接:https://momentjs.com/docs/#/query/is-dst-shifted/

    【讨论】:

      【解决方案6】:

      重构joshua k 的方法使其变得简单

      const data = product_data.filter(data => {
        if(!data.ProductHits) {return};
        const [strDate] = Object.keys(data.ProductHits);           
        const date = new Date(strDate);
        return date > new Date('2015-05-01') && date < new Date('2015-08-10')
       });
       console.log(data);
       

      【讨论】:

        猜你喜欢
        • 2015-10-02
        • 1970-01-01
        • 2018-06-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-10-20
        • 1970-01-01
        • 2023-03-13
        相关资源
        最近更新 更多