diff --git a/promql/parser/generated_parser.y b/promql/parser/generated_parser.y index 6f398addf..f80f5f45d 100644 --- a/promql/parser/generated_parser.y +++ b/promql/parser/generated_parser.y @@ -383,7 +383,12 @@ paren_expr : LEFT_PAREN expr RIGHT_PAREN offset_expr: expr OFFSET duration { - yylex.(*parser).addOffset($1, $3) + yylex.(*parser).addOffset($1, $3, 1) + $$ = $1 + } + | expr OFFSET SUB duration + { + yylex.(*parser).addOffset($1, $4, -1) $$ = $1 } | expr OFFSET error diff --git a/promql/parser/parse.go b/promql/parser/parse.go index 6b81f35f9..53db7ebc6 100644 --- a/promql/parser/parse.go +++ b/promql/parser/parse.go @@ -683,7 +683,7 @@ func (p *parser) newLabelMatcher(label Item, operator Item, value Item) *labels. } // addOffset is used to set the offset in the generated parser. -func (p *parser) addOffset(e Node, offset time.Duration) { +func (p *parser) addOffset(e Node, offset time.Duration, direction int) { var orgoffsetp *time.Duration var endPosp *Pos @@ -711,7 +711,7 @@ func (p *parser) addOffset(e Node, offset time.Duration) { if *orgoffsetp != 0 { p.addParseErrf(e.PositionRange(), "offset may not be set multiple times") } else if orgoffsetp != nil { - *orgoffsetp = offset + *orgoffsetp = offset * time.Duration(direction) } *endPosp = p.lastClosing diff --git a/promql/parser/parse_test.go b/promql/parser/parse_test.go index 10096188a..73cdfd209 100644 --- a/promql/parser/parse_test.go +++ b/promql/parser/parse_test.go @@ -1362,6 +1362,19 @@ var testExpr = []struct { End: 13, }, }, + }, { + input: "foo offset -7m", + expected: &VectorSelector{ + Name: "foo", + OriginalOffset: -7 * time.Minute, + LabelMatchers: []*labels.Matcher{ + MustLabelMatcher(labels.MatchEqual, model.MetricNameLabel, "foo"), + }, + PosRange: PositionRange{ + Start: 0, + End: 14, + }, + }, }, { input: `foo OFFSET 1h30m`, expected: &VectorSelector{