diff --git a/spring-integration-ftp/src/main/java/org/springframework/integration/ftp/filters/LastModifiedFTPFileListFilter.java b/spring-integration-ftp/src/main/java/org/springframework/integration/ftp/filters/LastModifiedFTPFileListFilter.java
new file mode 100644
index 00000000000..c843384dc72
--- /dev/null
+++ b/spring-integration-ftp/src/main/java/org/springframework/integration/ftp/filters/LastModifiedFTPFileListFilter.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2015-2023 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.integration.ftp.filters;
+
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+
+import org.apache.commons.net.ftp.FTPFile;
+
+import org.springframework.integration.file.filters.DiscardAwareFileListFilter;
+import org.springframework.lang.Nullable;
+
+/**
+ * The {@link org.springframework.integration.file.filters.FileListFilter} implementation to filter those files which
+ * {@link FTPFile#getTimestamp()} is less than the {@link #age} in comparison
+ * with the current time.
+ *
+ * The resolution is done in seconds.
+ *
+ * When {@link #discardCallback} is provided, it called for all the rejected files.
+ *
+ * @author Adama Sorho
+ *
+ * @since 6.2
+ */
+public class LastModifiedFTPFileListFilter implements DiscardAwareFileListFilter {
+
+ private static final long ONE_SECOND = 1000;
+ private static final long DEFAULT_AGE = 60;
+ private volatile long age = DEFAULT_AGE;
+
+ @Nullable
+ private Consumer discardCallback;
+
+ public LastModifiedFTPFileListFilter() {
+ }
+
+ /**
+ * Construct a {@link LastModifiedFTPFileListFilter} instance with provided {@link #age}.
+ * Defaults to 60 seconds.
+ * @param age the age in seconds.
+ */
+ public LastModifiedFTPFileListFilter(long age) {
+ this.age = age;
+ }
+
+ /**
+ * Set the age that the files have to be before being passed by this filter.
+ * If {@link FTPFile#getTimestamp()} plus age is greater than the current time, the file
+ * is filtered. The resolution is seconds.
+ * Defaults to 60 seconds.
+ * @param age the age in seconds.
+ * @param unit the timeUnit.
+ */
+ public void setAge(long age, TimeUnit unit) {
+ this.age = unit.toSeconds(age);
+ }
+
+ /**
+ * Set the age that files have to be before being passed by this filter.
+ * If {@link FTPFile#getTimestamp()} plus age is greater than the current time, the file
+ * is filtered. The resolution is seconds.
+ * Defaults to 60 seconds.
+ * @param age the age in seconds.
+ */
+ public void setAge(Duration age) {
+ setAge(age.getSeconds());
+ }
+
+ /**
+ * Set the age that files have to be before being passed by this filter.
+ * If {@link FTPFile#getTimestamp()} plus age is greater than the current time, the file
+ * is filtered. The resolution is seconds.
+ * Defaults to 60 seconds.
+ * @param age the age in seconds.
+ */
+ public void setAge(long age) {
+ setAge(age, TimeUnit.SECONDS);
+ }
+
+ @Override
+ public void addDiscardCallback(@Nullable Consumer discardCallback) {
+ this.discardCallback = discardCallback;
+ }
+
+ @Override
+ public List filterFiles(FTPFile[] files) {
+ List list = new ArrayList<>();
+ long now = System.currentTimeMillis() / ONE_SECOND;
+ for (FTPFile file: files) {
+ if (fileIsAged(file, now)) {
+ list.add(file);
+ }
+ else if (this.discardCallback != null) {
+ this.discardCallback.accept(file);
+ }
+ }
+
+ return list;
+ }
+
+ @Override
+ public boolean accept(FTPFile file) {
+ if (fileIsAged(file, System.currentTimeMillis() / ONE_SECOND)) {
+ return true;
+ }
+ else if (this.discardCallback != null) {
+ this.discardCallback.accept(file);
+ }
+
+ return false;
+ }
+
+ private boolean fileIsAged(FTPFile file, long now) {
+ return file.getTimestamp().getTimeInMillis() / ONE_SECOND + this.age <= now;
+ }
+
+ @Override
+ public boolean supportsSingleFileFiltering() {
+ return true;
+ }
+}
diff --git a/spring-integration-ftp/src/test/java/org/springframework/integration/ftp/filters/LastModifiedFTPFileListFilterTests.java b/spring-integration-ftp/src/test/java/org/springframework/integration/ftp/filters/LastModifiedFTPFileListFilterTests.java
new file mode 100644
index 00000000000..bf8c877f055
--- /dev/null
+++ b/spring-integration-ftp/src/test/java/org/springframework/integration/ftp/filters/LastModifiedFTPFileListFilterTests.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2015-2023 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.integration.ftp.filters;
+
+import java.util.Calendar;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.commons.net.ftp.FTPFile;
+import org.junit.jupiter.api.Test;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.integration.file.remote.session.SessionFactory;
+import org.springframework.integration.ftp.FtpTestSupport;
+import org.springframework.integration.ftp.session.FtpRemoteFileTemplate;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * @author Adama Sorho
+ * @since 6.2
+ */
+@SpringJUnitConfig
+@DirtiesContext
+public class LastModifiedFTPFileListFilterTests extends FtpTestSupport {
+
+ @Autowired
+ private FtpRemoteFileTemplate ftpRemoteFileTemplate;
+
+ @Test
+ public void testAge() {
+ LastModifiedFTPFileListFilter filter = new LastModifiedFTPFileListFilter();
+ filter.setAge(60, TimeUnit.SECONDS);
+ FTPFile[] files = ftpRemoteFileTemplate.list("ftpSource");
+ assertThat(files.length).isGreaterThan(0);
+ assertThat(filter.filterFiles(files)).hasSize(0);
+ FTPFile ftpFile = files[1];
+ assertThat(filter.accept(ftpFile)).isFalse();
+
+ // Make a file as of yesterday's
+ final Calendar calendar = Calendar.getInstance();
+ calendar.add(Calendar.DATE, -1);
+ ftpFile.setTimestamp(calendar);
+ assertThat(filter.filterFiles(files)).hasSize(1);
+ assertThat(filter.accept(ftpFile)).isTrue();
+ }
+
+ @Configuration
+ public static class Config {
+
+ @Bean
+ public SessionFactory ftpFileSessionFactory() {
+ return LastModifiedFTPFileListFilterTests.sessionFactory();
+ }
+
+ @Bean
+ public FtpRemoteFileTemplate ftpRemoteFileTemplate() {
+ return new FtpRemoteFileTemplate(ftpFileSessionFactory());
+ }
+ }
+}
diff --git a/spring-integration-smb/src/main/java/org/springframework/integration/smb/filters/LastModifiedSmbFileListFilter.java b/spring-integration-smb/src/main/java/org/springframework/integration/smb/filters/LastModifiedSmbFileListFilter.java
new file mode 100644
index 00000000000..b32a4f6ce81
--- /dev/null
+++ b/spring-integration-smb/src/main/java/org/springframework/integration/smb/filters/LastModifiedSmbFileListFilter.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2015-2023 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.integration.smb.filters;
+
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+
+import jcifs.smb.SmbFile;
+
+import org.springframework.integration.file.filters.DiscardAwareFileListFilter;
+import org.springframework.lang.Nullable;
+
+/**
+ * The {@link org.springframework.integration.file.filters.FileListFilter} implementation to filter those files which
+ * {@link SmbFile#getLastModified()} is less than the {@link #age} in comparison
+ * with the current time.
+ *
+ * The resolution is done in seconds.
+ *
+ * When {@link #discardCallback} is provided, it called for all the rejected files.
+ *
+ * @author Adama Sorho
+ *
+ * @since 6.2
+ */
+public class LastModifiedSmbFileListFilter implements DiscardAwareFileListFilter {
+
+ private static final long ONE_SECOND = 1000;
+ private static final long DEFAULT_AGE = 60;
+ private volatile long age = DEFAULT_AGE;
+
+ @Nullable
+ private Consumer discardCallback;
+
+ public LastModifiedSmbFileListFilter() {
+ }
+
+ /**
+ * Construct a {@link LastModifiedSmbFileListFilter} instance with provided {@link #age}.
+ * Defaults to 60 seconds.
+ * @param age the age in seconds.
+ */
+ public LastModifiedSmbFileListFilter(long age) {
+ this.age = age;
+ }
+
+ /**
+ * Set the age that the files have to be before being passed by this filter.
+ * If {@link SmbFile#getLastModified()} plus age is greater than the current time, the file
+ * is filtered. The resolution is seconds.
+ * Defaults to 60 seconds.
+ * @param age the age in seconds.
+ * @param unit the timeUnit.
+ */
+ public void setAge(long age, TimeUnit unit) {
+ this.age = unit.toSeconds(age);
+ }
+
+ /**
+ * Set the age that the files have to be before being passed by this filter.
+ * If {@link SmbFile#getLastModified()} plus age is greater than the current time, the file
+ * is filtered. The resolution is seconds.
+ * Defaults to 60 seconds.
+ * @param age the age in seconds.
+ */
+ public void setAge(Duration age) {
+ setAge(age.getSeconds());
+ }
+
+ /**
+ * Set the age that the files have to be before being passed by this filter.
+ * If {@link SmbFile#getLastModified()} plus age is greater than the current time, the file
+ * is filtered. The resolution is seconds.
+ * Defaults to 60 seconds.
+ * @param age the age in seconds.
+ */
+ public void setAge(long age) {
+ setAge(age, TimeUnit.SECONDS);
+ }
+
+ @Override
+ public void addDiscardCallback(@Nullable Consumer discardCallback) {
+ this.discardCallback = discardCallback;
+ }
+
+ @Override
+ public List filterFiles(SmbFile[] files) {
+ List list = new ArrayList<>();
+ long now = System.currentTimeMillis() / ONE_SECOND;
+ for (SmbFile file: files) {
+ if (fileIsAged(file, now)) {
+ list.add(file);
+ }
+ else if (this.discardCallback != null) {
+ this.discardCallback.accept(file);
+ }
+ }
+
+ return list;
+ }
+
+ @Override
+ public boolean accept(SmbFile file) {
+ if (fileIsAged(file, System.currentTimeMillis() / ONE_SECOND)) {
+ return true;
+ }
+ else if (this.discardCallback != null) {
+ this.discardCallback.accept(file);
+ }
+
+ return false;
+ }
+
+ private boolean fileIsAged(SmbFile file, long now) {
+ return file.getLastModified() / ONE_SECOND + this.age <= now;
+ }
+
+ @Override
+ public boolean supportsSingleFileFiltering() {
+ return true;
+ }
+}
diff --git a/spring-integration-smb/src/test/java/org/springframework/integration/smb/filters/LastModifiedSmbFileListFilterTests.java b/spring-integration-smb/src/test/java/org/springframework/integration/smb/filters/LastModifiedSmbFileListFilterTests.java
new file mode 100644
index 00000000000..5f8c400b2f3
--- /dev/null
+++ b/spring-integration-smb/src/test/java/org/springframework/integration/smb/filters/LastModifiedSmbFileListFilterTests.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2015-2023 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.integration.smb.filters;
+
+import java.util.concurrent.TimeUnit;
+
+import jcifs.smb.SmbException;
+import jcifs.smb.SmbFile;
+import org.junit.jupiter.api.Test;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.integration.file.remote.session.SessionFactory;
+import org.springframework.integration.smb.SmbTestSupport;
+import org.springframework.integration.smb.session.SmbRemoteFileTemplate;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * @author Adama Sorho
+ * @since 6.2
+ */
+@SpringJUnitConfig
+@DirtiesContext
+public class LastModifiedSmbFileListFilterTests extends SmbTestSupport {
+
+ @Autowired
+ private SmbRemoteFileTemplate smbRemoteFileTemplate;
+
+ @Test
+ public void testAge() throws SmbException {
+ LastModifiedSmbFileListFilter filter = new LastModifiedSmbFileListFilter();
+ filter.setAge(60, TimeUnit.SECONDS);
+ SmbFile[] files = smbRemoteFileTemplate.list("smbSource");
+ assertThat(files.length).isGreaterThan(0);
+ assertThat(filter.filterFiles(files)).hasSize(0);
+ SmbFile smbFile = files[1];
+ assertThat(filter.accept(smbFile)).isFalse();
+
+ // Make a file as of yesterday's
+ smbFile.setLastModified(System.currentTimeMillis() - 1000 * 60 * 60 * 24);
+ assertThat(filter.filterFiles(files)).hasSize(1);
+ assertThat(filter.accept(smbFile)).isTrue();
+ }
+
+ @Configuration
+ public static class Config {
+
+ @Bean
+ public SessionFactory smbFileSessionFactory() {
+ return LastModifiedSmbFileListFilterTests.sessionFactory();
+ }
+
+ @Bean
+ public SmbRemoteFileTemplate smbRemoteFileTemplate() {
+ return new SmbRemoteFileTemplate(smbFileSessionFactory());
+ }
+ }
+}