diff --git a/on-host/arpist-traject/src/syntax.rs b/on-host/arpist-traject/src/syntax.rs
index 0387a875f60a8e35cc9acb5f7b993ac292614e61..7d92614c27f67e60a48d40b4655e6121465630a9 100644
--- a/on-host/arpist-traject/src/syntax.rs
+++ b/on-host/arpist-traject/src/syntax.rs
@@ -24,7 +24,7 @@ struct Parameter {
 enum Expr {
     Op(Box<Operation>),
     Num(Number),
-    TimeVar(Range<usize>),
+    TimeVar(TimeVar),
     Group(GroupExpr),
 }
 
@@ -33,7 +33,7 @@ impl Expr {
         match self {
             Expr::Op(op) => op.span.clone(),
             Expr::Num(num) => num.span.clone(),
-            Expr::TimeVar(ix) => ix.clone(),
+            Expr::TimeVar(tv) => tv.span.clone(),
             Expr::Group(expr) => expr.span.clone(),
         }
     }
@@ -84,3 +84,8 @@ struct TimeRef {
     span: Range<usize>,
     offset: f64,
 }
+
+#[derive(Debug, Clone)]
+struct TimeVar {
+    span: Range<usize>,
+}
diff --git a/on-host/arpist-traject/src/syntax/parser.rs b/on-host/arpist-traject/src/syntax/parser.rs
index 194c1719d67764599b14aee6e6afd851d9f5aaab..0230ea8116885832dd0ec58c6bc463f87e7e08b7 100644
--- a/on-host/arpist-traject/src/syntax/parser.rs
+++ b/on-host/arpist-traject/src/syntax/parser.rs
@@ -310,6 +310,15 @@ fn parse_product(mut view: LexerView<'_>) -> Option<Expr> {
                 rhs: Box::new(rhs),
             }))
         }
+        Some((Token::Time, _)) => {
+            let rhs = parse_power(view.view())?;
+            Expr::Op(Box::new(Operation {
+                span: lhs.span().start..rhs.span().end,
+                op: Operator::Mul,
+                lhs: Box::new(lhs),
+                rhs: Box::new(rhs),
+            }))
+        }
         _ => lhs,
     };
     view.commit();
@@ -337,10 +346,16 @@ fn parse_power(mut view: LexerView<'_>) -> Option<Expr> {
 }
 
 fn parse_expr_value(mut view: LexerView<'_>) -> Option<Expr> {
+    println!("{:?}", view.peek());
+    println!("parse_expr_value");
     if let Some(number) = parse_number(view.view()) {
         view.commit();
         return Some(Expr::Num(number));
     }
+    if let Some(time_var) = parse_time_var(view.view()) {
+        view.commit();
+        return Some(Expr::TimeVar(time_var));
+    }
     if let Some(group) = parse_group(view.view()) {
         view.commit();
         return Some(Expr::Group(group));
@@ -383,6 +398,17 @@ fn parse_group(mut view: LexerView<'_>) -> Option<GroupExpr> {
     None
 }
 
+fn parse_time_var(mut view: LexerView<'_>) -> Option<TimeVar> {
+    println!("{:?}", view.peek());
+    println!("parse_time_var");
+    if let (Token::Time, r) = view.next()? {
+        view.commit();
+        Some(TimeVar { span: r })
+    } else {
+        None
+    }
+}
+
 fn consume_any_space(mut view: LexerView<'_>) {
     while let Some((Token::Spaces, _)) = view.peek() {
         view.next();
@@ -429,5 +455,8 @@ mod tests {
 
         let mut lex = CachedLexer::new("(3^2+1) / 2");
         let expr = parse_expr(lex.view()).unwrap();
+
+        let mut lex = CachedLexer::new("2t^2+1.5t-3");
+        let expr = parse_expr(lex.view()).unwrap();
     }
 }