4949import java .util .concurrent .Executors ;
5050import java .util .concurrent .ScheduledExecutorService ;
5151import java .util .concurrent .TimeUnit ;
52+ import java .util .regex .Matcher ;
53+ import java .util .regex .Pattern ;
5254
5355/**
5456 * data storage by duckdb
@@ -64,6 +66,9 @@ public class DuckdbDatabaseDataStorage extends AbstractHistoryDataStorage {
6466 // Ideal number of data points for charting (avoids frontend lag)
6567 private static final int TARGET_CHART_POINTS = 800 ;
6668
69+ // Regex to strictly match days format, e.g., "90d", "7D". Group 1 captures the digits.
70+ private static final Pattern DAY_PATTERN = Pattern .compile ("^(\\ d+)[dD]$" );
71+
6772 private final String expireTimeStr ;
6873 private final String dbPath ;
6974 private HikariDataSource dataSource ;
@@ -136,11 +141,21 @@ private void startExpiredDataCleaner() {
136141 log .info ("[duckdb] start data cleaner and checkpoint..." );
137142 long expireTime ;
138143 try {
139- if (NumberUtils .isParsable (expireTimeStr )) {
140- expireTime = NumberUtils .toLong (expireTimeStr );
144+ // Ensure no whitespace issues
145+ String cleanExpireStr = expireTimeStr == null ? "" : expireTimeStr .trim ();
146+ Matcher dayMatcher = DAY_PATTERN .matcher (cleanExpireStr );
147+
148+ if (NumberUtils .isParsable (cleanExpireStr )) {
149+ expireTime = NumberUtils .toLong (cleanExpireStr );
141150 expireTime = (ZonedDateTime .now ().toEpochSecond () - expireTime ) * 1000L ;
151+ } else if (dayMatcher .matches ()) {
152+ // Strictly matched "90d" or "90D" format
153+ long days = Long .parseLong (dayMatcher .group (1 ));
154+ ZonedDateTime dateTime = ZonedDateTime .now ().minus (Duration .ofDays (days ));
155+ expireTime = dateTime .toEpochSecond () * 1000L ;
142156 } else {
143- TemporalAmount temporalAmount = TimePeriodUtil .parseTokenTime (expireTimeStr );
157+ // Fallback to existing utility for other units (h, m, s, etc.)
158+ TemporalAmount temporalAmount = TimePeriodUtil .parseTokenTime (cleanExpireStr );
144159 ZonedDateTime dateTime = ZonedDateTime .now ().minus (temporalAmount );
145160 expireTime = dateTime .toEpochSecond () * 1000L ;
146161 }
0 commit comments