Сравните и отфильтруйте свойства даты в объекте

У меня есть объект, который выглядит так:

    myObject = {
      publishedDate: string;
      Url: string;
      Title: string;
  }

Свойство «publishedDate» представляет собой строку в формате «19.01.2021». Например, он может иметь дату в будущем, то есть значение больше, чем сегодня. Другими словами, я хочу сохранить все объекты, у которых publishDate меньше или равно сегодняшнему дню (и удалить все, что закончилось). Объекты сохраняются в моем состоянии (массив):

this.state.data

Сначала я создаю переменную даты для сегодняшнего значения, чтобы сравнить ее с опубликованной датой. Я также использую moment() для форматирования даты в том же формате, что и объект:

let today = moment().format("DD/MM/YYYY");

Затем я использую метод фильтра для сравнения и фильтрации данных:

  this.state.data.filter(item => new Date(item.publishedDate) >= new Date(today))

И я также пробовал:

  this.state.data.filter(function(item) {
    
      if (new Date(item.publishedDate) >= new Date(today)) {
        return false;
      }
    return true;
  });

Мало того, что не работает, у меня еще все объекты в массиве и ничего не отфильтровывается. Что не так с кодом?

new Date("19/01/2021") возвращает: Invalid Date
Davin Tryon 18.12.2020 20:05
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
Раскрытие чувствительных данных
Раскрытие чувствительных данных
Все внешние компоненты, рассмотренные здесь до сих пор, взаимодействуют с клиентской стороной. Однако, если они подвергаются атаке, они не...
Зод: сила проверки и преобразования данных
Зод: сила проверки и преобразования данных
Сегодня я хочу познакомить вас с библиотекой Zod и раскрыть некоторые ее особенности, например, возможности валидации и трансформации данных, а также...
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Мы провели Twitter Space, обсудив несколько проблем, связанных с последними дополнениями в Angular. Также прошла Angular Tiny Conf с 25 докладами.
Руководство ChatGPT по продаже мини JS-файлов
Руководство ChatGPT по продаже мини JS-файлов
JS-файл - это файл, содержащий код JavaScript. JavaScript - это язык программирования, который в основном используется для добавления интерактивности...
4
1
1 157
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Ответ принят как подходящий

Конструктор Date не примет формат, который вы сейчас используете, но распознает формат MM/DD/YYYY. Кроме того, filter сохраняет элементы, для которых функция возвращает значение true, поэтому вам следует проверить, меньше или равно ли Date текущему Date.

const today = new Date;
this.state.data = this.state.data.filter(({publishedDate})=>{
    const [d, m, y] = publishedDate.split("/");
    return new Date(m + "/" + d + "/" + y) <= today;
});

На данный момент new Date("19/01/2021") возвращается: Invalid Date.

Это возможное решение:

let today = moment().format("YYYY-MM-DD");

this.state.data.filter(function(item) {
    const pubDate = item.publishedDate.split('/').reverse().join('-');
    if (new Date(pubDate) >= new Date(today)) {
        return false;
    }
    return true;
});

Вы должны сделать небольшую точную настройку строки даты, прежде чем сравнивать с сегодняшним днем. Вы можете попробовать это-

const data = [
  {
    publishedDate: "19/01/2021",
    url: '',
    title: 'date1'
  },
  {
    publishedDate: "19/05/2021",
    url: '',
    title: 'date2'
  },
  {
    publishedDate: "13/01/2020",
    url: '',
    title: 'date3'
  },
  {
    publishedDate: "16/09/2009",
    url: '',
    title: 'date4'
  },
];

const parseDate = (dateString) => new Date(...dateString.split('/').reverse());


const result = data.filter(item => parseDate(item.publishedDate) <= new Date());

console.info(result);

Хранение дат в виде строк — это запах кода. Их сложнее сравнивать, хранить и преобразовывать, а не хранить как собственный формат даты JS или альтернативы, такие как объект даты Moment.JS.

Вот тривиальный пример того, как вы могли бы это сделать, если бы вы сохранили свои объекты как дату.

Обратите внимание, что третий объект был отфильтрован.

const myObject1 = {
  publishedDate: new Date("2019-01-01"), // NEW
  Url: "whatever",
  Title: "sample",
}

const myObject2 = {
  publishedDate: new Date("2020-01-01"), // NEW
  Url: "whatever",
  Title: "sample",
}

const myObject3 = {
  publishedDate: new Date("2099-01-01"), // NEW
  Url: "whatever",
  Title: "sample",
}

const arr = [myObject1, myObject2, myObject3];

const today = new Date();

const filtered = arr.filter((obj) => obj.publishedDate < today);

console.info(filtered);

Напротив, строки сериализуются тривиально, поэтому их можно использовать, например, в представлениях JSON. Но соответствующий формат был бы гораздо полезнее, если бы OP контролировала структуру данных.

Scott Sauyet 18.12.2020 20:25

Я согласен с тем, что строки легко конвертируются в JSON и удобочитаемы для людей. Однако у хранения дат в виде строк есть множество недостатков: их сложно преобразовать, трудно обеспечить достоверность, сложнее арифметика дат и т. д. См. refactoring.guru/smells/primitive-obsession

IvanD 18.12.2020 20:45

Помните, что OP начался с «У меня есть объект, который выглядит» с датами в строковом формате. Мы оба согласны с тем, что формат ужасен, но я не согласен с тем, что строковый формат здесь неуместен. Я определенно думаю, что это лучше, чем настоятельно не рекомендуется синтаксический анализ строк для создания новой даты. Я нахожу ISO 8601 полезной серединой — простой, сортируемый, сериализуемый, относительно легко конвертируемый в объекты Date. Если делать математику даты, я согласен.

Scott Sauyet 21.12.2020 17:19

Вы можете просто использовать встроенные компараторы moment, подобные этому

this.state.data.filter(item => moment(item.publishedDate,'DD/MM/YYYY').isSameOrAfter(today))

Используя момент String + инициализатор формата и Is Same Or After:

this.state.data.filter(item => moment(item.publishedDate, 'DD/MM/YYYY').isSameOrAfter())

Одна из возможностей — использование вспомогательной функции notAfterToday, которая принимает имя свойства (в нашем случае 'publishedDate') и возвращает функцию, которая принимает объект с этим именем свойства и сообщает, является ли эта дата предшествующей или текущей датой.

Он делает это путем преобразования, скажем, 18 декабря 2020 года в «20201218» и использует эту строку для сравнения. Обратите внимание, что одним из преимуществ этого является то, что конструктор Date вызывается только один раз для первоначального вычисления сегодняшней даты.

const data = [{publishedDate: '18/12/2020', Url: 'http://example.com/1', Title: 'abc'}, {publishedDate: '19/01/2021', Url: 'http://example.com/2', Title: 'def'}, {publishedDate: '07/04/2014', Url: 'http://example.com/3', Title: 'ghi'}, {publishedDate: '19/07/2023', Url: 'http://example.com/4', Title: 'jkl'}, {publishedDate: '05/01/1966', Url: 'http://example.com/5', Title: 'mno'}, {publishedDate: '01/07/2041', Url: 'http://example.com/6', Title: 'pqr'}, {publishedDate: '08/05/2061', Url: 'http://example.com/7', Title: 'stu'}, {publishedDate: '10/08/1999', Url: 'http://example.com/8', Title: 'vwx'}]

const notAfterToday = (prop) => {
  const reorg = (date, [d, m, y] = date.split('/')) => y + m + d 
  const today = new Date()
  const compare = today .getFullYear() + 
                  String ((today .getMonth () + 1)) .padStart (2, '0') +
                  String (today .getDate ()) .padStart (2, '0')
  return (d) => compare >= reorg (d [prop])
}

console .log (data .filter (notAfterToday ('publishedDate')))
.as-console-wrapper {max-height: 100% !important; top: 0}

Другие вопросы по теме