// parseDate converts the given datestring (from one of the allowable formats) into a millisecond offset from the Unix epoch. func parseDate(date string, now time.Time) (int64, error) { if date == "now" { return now.Unix() * 1000, nil } // Millisecond epoch timestamp. if epoch, err := strconv.ParseInt(date, 10, 0); err == nil { return epoch, nil } relativeTime, err := function.StringToDuration(date) if err == nil { // A relative date. if relativeTime > 0 { return -1, fmt.Errorf("relative times should be negative: %s", date) } return now.Add(relativeTime).Unix() * 1000, nil } errorMessage := fmt.Sprintf("Expected formatted date or relative time but got '%s'", date) for _, format := range dateFormats { t, err := time.Parse(format, date) if err == nil { return t.Unix()*1000 + int64(t.Nanosecond()/1000000), nil } } return -1, errors.New(errorMessage) }
func (p *Parser) addDurationNode(value string) { duration, err := function.StringToDuration(value) p.pushNode(&durationExpression{value, duration}) if err != nil { p.flagSyntaxError(SyntaxError{ token: value, message: fmt.Sprintf("'%s' is not a valid duration: %s", value, err.Error()), }) } }
func (p *Parser) insertPropertyKeyValue() { valueNode, ok := p.popNode(evaluationContextValuePointer).(*evaluationContextValue) if !ok { p.flagTypeAssertion() return } keyNode, ok := p.popNode(evaluationContextKeyPointer).(*evaluationContextKey) if !ok { p.flagTypeAssertion() return } contextNode, ok := p.popNode(evaluationContextNodePointer).(*evaluationContextNode) if !ok { p.flagTypeAssertion() return } key := keyNode.key value := valueNode.value // Authenticate the validity of the given key and value... // The key must be one of "sample"(by), "from", "to", "resolution" // First check that the key has been assigned only once: if contextNode.assigned[key] { p.flagSyntaxError(SyntaxError{ token: key, message: fmt.Sprintf("Key %s has already been assigned", key), }) } contextNode.assigned[key] = true switch key { case "sample": // If the key is "sample", it means we're in a "sample by" declaration. // Only three possible sample methods are defined: min, max, or mean. switch value { case "max": contextNode.SampleMethod = api.SampleMax case "min": contextNode.SampleMethod = api.SampleMin case "mean": contextNode.SampleMethod = api.SampleMean default: p.flagSyntaxError(SyntaxError{ token: value, message: fmt.Sprintf("Expected sampling method 'max', 'min', or 'mean' but got %s", value), }) } case "from", "to": var unix int64 var err error now := time.Now() if unix, err = parseDate(value, now); err != nil { p.flagSyntaxError(SyntaxError{ token: value, message: err.Error(), }) } if key == "from" { contextNode.Start = unix } else { contextNode.End = unix } case "resolution": // The value must be determined to be an int if the key is "resolution". if intValue, err := strconv.ParseInt(value, 10, 64); err == nil { contextNode.Resolution = intValue } else if duration, err := function.StringToDuration(value); err == nil { contextNode.Resolution = int64(duration / time.Millisecond) } else { p.flagSyntaxError(SyntaxError{ token: value, message: fmt.Sprintf("Expected number but parse failed; %s", err.Error()), }) } default: p.flagSyntaxError(SyntaxError{ token: key, message: fmt.Sprintf("Unknown property key %s", key), }) } p.pushNode(contextNode) }