Skip to content

Commit de6ae73

Browse files
atopos31claude
andcommitted
feat: add relative time filtering (1h, 2d, 30m)
Support filtering by relative time in addition to absolute time: - 1h: past 1 hour - 2d: past 2 days - 30m: past 30 minutes Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 7eae6c7 commit de6ae73

5 files changed

Lines changed: 95 additions & 9 deletions

File tree

README.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,14 @@ agent-rss fetch --all --format json
6363
### Filtering
6464

6565
```bash
66-
# Filter by time range
66+
# Filter by relative time (past hours/days/minutes)
67+
agent-rss fetch --all --since 1h # past 1 hour
68+
agent-rss fetch --all --since 2d # past 2 days
69+
agent-rss fetch --all --since 30m # past 30 minutes
70+
71+
# Filter by absolute time
6772
agent-rss fetch --all --since 2026-03-12
68-
agent-rss fetch --all --since 2026-03-12T08:00:00Z --until 2026-03-12T18:00:00Z
73+
agent-rss fetch --all --since 2026-03-12T08:00:00+08:00 --until 2026-03-12T18:00:00+08:00
6974

7075
# Filter by title keyword
7176
agent-rss fetch --all --title "AI"
@@ -74,7 +79,7 @@ agent-rss fetch --all --title "AI"
7479
agent-rss fetch --all --content "machine learning"
7580

7681
# Combine filters
77-
agent-rss fetch --all --since 2026-03-12 --title "Go" --title "Rust"
82+
agent-rss fetch --all --since 1d --title "Go" --title "Rust"
7883
```
7984

8085
### Global Options

README_CN.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,12 @@ agent-rss fetch --all --format json
6363
### 过滤
6464

6565
```bash
66-
# 按时间范围过滤
66+
# 按相对时间过滤(过去几小时/几天/几分钟)
67+
agent-rss fetch --all --since 1h # 过去 1 小时
68+
agent-rss fetch --all --since 2d # 过去 2 天
69+
agent-rss fetch --all --since 30m # 过去 30 分钟
70+
71+
# 按绝对时间过滤
6772
agent-rss fetch --all --since 2026-03-12
6873
agent-rss fetch --all --since 2026-03-12T08:00:00+08:00 --until 2026-03-12T18:00:00+08:00
6974

@@ -74,7 +79,7 @@ agent-rss fetch --all --title "AI"
7479
agent-rss fetch --all --content "机器学习"
7580

7681
# 组合过滤
77-
agent-rss fetch --all --since 2026-03-12 --title "Go" --title "Rust"
82+
agent-rss fetch --all --since 1d --title "Go" --title "Rust"
7883
```
7984

8085
### 全局选项

internal/cli/cli.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -209,11 +209,11 @@ func fetchCmd() *cli.Command {
209209
},
210210
&cli.StringFlag{
211211
Name: "since",
212-
Usage: "filter items published after this time (RFC3339 or YYYY-MM-DD)",
212+
Usage: "filter items after this time (RFC3339, YYYY-MM-DD, or relative: 1h, 2d, 30m)",
213213
},
214214
&cli.StringFlag{
215215
Name: "until",
216-
Usage: "filter items published before this time (RFC3339 or YYYY-MM-DD)",
216+
Usage: "filter items before this time (RFC3339, YYYY-MM-DD, or relative: 1h, 2d, 30m)",
217217
},
218218
&cli.StringSliceFlag{
219219
Name: "title",

internal/filter/filter.go

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
package filter
33

44
import (
5+
"regexp"
6+
"strconv"
57
"strings"
68
"time"
79

@@ -60,21 +62,58 @@ func containsAny(text string, keywords []string) bool {
6062
return false
6163
}
6264

63-
// ParseTime attempts to parse a time string in RFC3339 or YYYY-MM-DD format.
65+
// ParseTime attempts to parse a time string.
66+
// Supported formats:
67+
// - RFC3339: 2026-03-12T08:30:00Z
68+
// - Date: 2026-03-12
69+
// - Relative: 1h, 2d, 30m (hours, days, minutes ago)
6470
func ParseTime(s string) (time.Time, error) {
71+
// Try RFC3339
6572
if t, err := time.Parse(time.RFC3339, s); err == nil {
6673
return t, nil
6774
}
6875

76+
// Try YYYY-MM-DD
6977
if t, err := time.ParseInLocation("2006-01-02", s, time.Local); err == nil {
7078
return t, nil
7179
}
7280

81+
// Try relative time (e.g., 1h, 2d, 30m)
82+
if t, ok := parseRelativeTime(s); ok {
83+
return t, nil
84+
}
85+
7386
return time.Time{}, &time.ParseError{
74-
Layout: "RFC3339 or YYYY-MM-DD",
87+
Layout: "RFC3339, YYYY-MM-DD, or relative (1h, 2d, 30m)",
7588
Value: s,
7689
LayoutElem: "",
7790
ValueElem: s,
7891
Message: "invalid time format",
7992
}
8093
}
94+
95+
var relativeTimeRegex = regexp.MustCompile(`^(\d+)(m|h|d)$`)
96+
97+
func parseRelativeTime(s string) (time.Time, bool) {
98+
matches := relativeTimeRegex.FindStringSubmatch(strings.TrimSpace(s))
99+
if matches == nil {
100+
return time.Time{}, false
101+
}
102+
103+
value, _ := strconv.Atoi(matches[1])
104+
unit := matches[2]
105+
106+
var duration time.Duration
107+
switch unit {
108+
case "m":
109+
duration = time.Duration(value) * time.Minute
110+
case "h":
111+
duration = time.Duration(value) * time.Hour
112+
case "d":
113+
duration = time.Duration(value) * 24 * time.Hour
114+
default:
115+
return time.Time{}, false
116+
}
117+
118+
return time.Now().Add(-duration), true
119+
}

internal/filter/filter_test.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,3 +96,40 @@ func TestParseTime(t *testing.T) {
9696
}
9797
}
9898
}
99+
100+
func TestParseTime_Relative(t *testing.T) {
101+
tests := []struct {
102+
input string
103+
minAgo time.Duration
104+
maxAgo time.Duration
105+
wantErr bool
106+
}{
107+
{"1h", 59 * time.Minute, 61 * time.Minute, false},
108+
{"2h", 119 * time.Minute, 121 * time.Minute, false},
109+
{"1d", 23 * time.Hour, 25 * time.Hour, false},
110+
{"30m", 29 * time.Minute, 31 * time.Minute, false},
111+
{"0m", 0, 1 * time.Minute, false},
112+
{"abc", 0, 0, true},
113+
{"1x", 0, 0, true},
114+
{"h1", 0, 0, true},
115+
}
116+
117+
for _, tt := range tests {
118+
parsed, err := ParseTime(tt.input)
119+
if tt.wantErr {
120+
if err == nil {
121+
t.Errorf("ParseTime(%q): expected error, got nil", tt.input)
122+
}
123+
continue
124+
}
125+
if err != nil {
126+
t.Errorf("ParseTime(%q): unexpected error: %v", tt.input, err)
127+
continue
128+
}
129+
130+
ago := time.Since(parsed)
131+
if ago < tt.minAgo || ago > tt.maxAgo {
132+
t.Errorf("ParseTime(%q): got %v ago, want between %v and %v", tt.input, ago, tt.minAgo, tt.maxAgo)
133+
}
134+
}
135+
}

0 commit comments

Comments
 (0)