// ParseDuration parses a time duration from a string.
// This is needed instead of time.ParseDuration because this will support
// the full syntax that InfluxQL supports for specifying durations
// including weeks and days.
773711
func ParseDuration(s string) (time.Duration, error) {
	// Return an error if the string is blank or one character
	if len(s) < 2 {
		return 0, ErrInvalidDuration
	}

	// Split string into individual runes.
	a := split(s)

	// Start with a zero duration.
	var d time.Duration
	i := 0

	// Check for a negative.
	isNegative := false
	if a[i] == '-' {
		isNegative = true
		i++
	}

	var measure int64
	var unit string

	// Parsing loop.
	for i < len(a) {
		// Find the number portion.
		start := i
		for ; i < len(a) && isDigit(a[i]); i++ {
			// Scan for the digits.
		}

		// Check if we reached the end of the string prematurely.
		if i >= len(a) || i == start {
			return 0, ErrInvalidDuration
		}

		// Parse the numeric part.
		n, err := strconv.ParseInt(string(a[start:i]), 10, 64)
		if err != nil {
			return 0, ErrInvalidDuration
		}
		measure = n

		// Extract the unit of measure.
		unit = string(a[i])
		switch a[i] {
		case 'n':
			d += time.Duration(n) * time.Nanosecond
			if i+1 < len(a) && a[i+1] == 's' {
				unit = string(a[i : i+2])
				i += 2
				continue
			}
		case 'u', 'µ':
			d += time.Duration(n) * time.Microsecond
			if i+1 < len(a) && a[i+1] == 's' {
				unit = string(a[i : i+2])
				i += 2
				continue
			}
		case 'm':
			// Check for `mo` and `ms`; month and millisecond, respectively.
			if i+1 < len(a) {
				switch a[i+1] {
				case 's': // ms == milliseconds
					unit = string(a[i : i+2])
					d += time.Duration(n) * time.Millisecond
					i += 2
					continue
				case 'o': // mo == month
					// TODO(goller): use real duration values:
					// https://github.com/influxdata/platform/issues/657
					unit = string(a[i : i+2])
					d += time.Duration(n) * 30 * 24 * time.Hour
					i += 2
					continue
				}
			}
			d += time.Duration(n) * time.Minute
		case 's':
			d += time.Duration(n) * time.Second
		case 'h':
			d += time.Duration(n) * time.Hour
		case 'd':
			d += time.Duration(n) * 24 * time.Hour
		case 'w':
			// TODO(goller): use real duration values:
			// https://github.com/influxdata/platform/issues/657
			d += time.Duration(n) * 7 * 24 * time.Hour
		case 'y':
			// TODO(goller): use real duration values:
			// https://github.com/influxdata/platform/issues/657
			d += time.Duration(n) * 365 * 24 * time.Hour
		default:
			return 0, ErrInvalidDuration
		}
		i++
	}

	// Check to see if we overflowed a duration
	if d < 0 && !isNegative {
		return 0, fmt.Errorf("overflowed duration %d%s: choose a smaller duration or INF", measure, unit)
	}

	if isNegative {
		d = -d
	}
	return d, nil
}
638024
func (b *builtinTimeLiteralSig) evalDuration(row chunk.Row) (types.Duration, bool, error) {
	return b.duration, false, nil
}
1240770
func (a *Duration) Parse(s string) error {
	q, err := parseSignedDuration(s)
	if err != nil {
		return err
	}
	a.Node = *q
	return nil
}
259040
func ParseDate(ds string) (t time.Time, err error) {
	d := strings.TrimSpace(ds)
	if d == "" {
		return t, fmt.Errorf("Date string is empty")
	}
	for _, f := range dateFormats {
		if t, err = time.Parse(f, d); err == nil {
			return
		}
	}
	for _, f := range dateFormatsWithNamedZone {
		t, err = time.Parse(f, d)
		if err != nil {
			continue
		}

		// This is a format match! Now try to load the timezone name
		loc, err := time.LoadLocation(t.Location().String())
		if err != nil {
			// We couldn't load the TZ name. Just use UTC instead...
			return t, nil
		}

		if t, err = time.ParseInLocation(f, ds, loc); err == nil {
			return t, nil
		}
		// This should not be reachable
	}

	err = fmt.Errorf("Failed to parse date: %s", ds)
	return
}
417867
func (b *builtinUTCTimeWithoutArgSig) evalDuration(row chunk.Row) (types.Duration, bool, error) {
	var nowTs = &b.ctx.GetSessionVars().StmtCtx.NowTs
	if nowTs.Equal(time.Time{}) {
		*nowTs = time.Now()
	}
	v, err := types.ParseDuration(b.ctx.GetSessionVars().StmtCtx, nowTs.UTC().Format(types.TimeFormat), 0)
	return v, false, err
}
377912
func (p *parserMixin) Duration() (target *time.Duration) {
	target = new(time.Duration)
	p.DurationVar(target)
	return
}
239902
func (c *CmdChatSetRetention) parseExpireAgeLimited(s string) (gregor1.DurationSec, error) {
	var d time.Duration
	switch s {
	case "1d", "24h":
		d = 24 * time.Hour
	case "7d", "1w":
		d = 7 * 24 * time.Hour
	case "30d", "1m":
		d = 30 * 24 * time.Hour
	case "3m":
		d = 90 * 24 * time.Hour
	case "12m", "1y":
		d = 365 * 24 * time.Hour
	default:
		return 0, fmt.Errorf("invalid expiration age: %v", s)
	}
	return gregor1.DurationSec(d.Seconds()), nil
}
23004
func Duration(val string) (*duration.Duration, error) {
	var r *duration.Duration
	err := jsonpb.UnmarshalString(val, r)
	return r, err
}
812637
func ParseDestination(targetString string, defaultTabletType topodatapb.TabletType) (string, topodatapb.TabletType, key.Destination, error) {
	var dest key.Destination
	var keyspace string
	tabletType := defaultTabletType

	last := strings.LastIndexAny(targetString, "@")
	if last != -1 {
		// No need to check the error. UNKNOWN will be returned on
		// error and it will fail downstream.
		tabletType, _ = ParseTabletType(targetString[last+1:])
		targetString = targetString[:last]
	}
	last = strings.LastIndexAny(targetString, "/:")
	if last != -1 {
		dest = key.DestinationShard(targetString[last+1:])
		targetString = targetString[:last]
	}
	// Try to parse it as a keyspace id or range
	last = strings.LastIndexAny(targetString, "[")
	if last != -1 {
		rangeEnd := strings.LastIndexAny(targetString, "]")
		if rangeEnd == -1 {
			return keyspace, tabletType, dest, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "invalid key range provided. Couldn't find range end ']'")
		}
		rangeString := targetString[last+1 : rangeEnd]
		if strings.Contains(rangeString, "-") {
			// Parse as range
			keyRange, err := key.ParseShardingSpec(rangeString)
			if err != nil {
				return keyspace, tabletType, dest, err
			}
			if len(keyRange) != 1 {
				return keyspace, tabletType, dest, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "single keyrange expected in %s", rangeString)
			}
			dest = key.DestinationExactKeyRange{KeyRange: keyRange[0]}
		} else {
			// Parse as keyspace id
			destBytes, err := hex.DecodeString(rangeString)
			if err != nil {
				return keyspace, tabletType, dest, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "expected valid hex in keyspace id %s", rangeString)
			}
			dest = key.DestinationKeyspaceID(destBytes)
		}
		targetString = targetString[:last]
	}
	keyspace = targetString
	return keyspace, tabletType, dest, nil
}
1138998
func (p *parserMixin) DurationVar(target *time.Duration) {
	p.SetValue(newDurationValue(target))
}
343302
func (c *CmdChatSetRetention) parseEphemeralAgeLimited(s string) (gregor1.DurationSec, error) {
	var d time.Duration
	var err error
	switch s {
	case "30s",
		"5m",
		"1h",
		"6h":
		d, err = time.ParseDuration(s)
	case "1d", "24h":
		d = 24 * time.Hour
	case "3d":
		d = 3 * 24 * time.Hour
	case "7d", "1w":
		d = 7 * 24 * time.Hour
	default:
		return 0, fmt.Errorf("invalid expiration age: %v", s)
	}
	return gregor1.DurationSec(d.Seconds()), err
}
31634
func ParseDate(sc *stmtctx.StatementContext, str string) (Time, error) {
	// date has no fractional seconds precision
	return ParseTime(sc, str, mysql.TypeDate, MinFsp)
}
1356117
func (tr Row) ForceDuration(nn int) (val time.Duration) {
	val, _ = tr.DurationErr(nn)
	return
}
525585
func Duration(name string, value time.Duration, usage string) *time.Duration {
	return CommandLine.Duration(name, value, usage)
}
774851
func (b *builtinTimeSig) evalDuration(row chunk.Row) (res types.Duration, isNull bool, err error) {
	expr, isNull, err := b.args[0].EvalString(b.ctx, row)
	if isNull || err != nil {
		return res, isNull, err
	}

	fsp := 0
	if idx := strings.Index(expr, "."); idx != -1 {
		fsp = len(expr) - idx - 1
	}

	if fsp, err = types.CheckFsp(fsp); err != nil {
		return res, isNull, err
	}

	sc := b.ctx.GetSessionVars().StmtCtx
	res, err = types.ParseDuration(sc, expr, fsp)
	if types.ErrTruncatedWrongVal.Equal(err) {
		err = sc.HandleTruncate(err)
	}
	return res, isNull, err
}
923577
func (b *builtinTimeStringTimeDiffSig) evalDuration(row chunk.Row) (d types.Duration, isNull bool, err error) {
	lhs, isNull, err := b.args[0].EvalTime(b.ctx, row)
	if isNull || err != nil {
		return d, isNull, err
	}

	rhsStr, isNull, err := b.args[1].EvalString(b.ctx, row)
	if isNull || err != nil {
		return d, isNull, err
	}

	sc := b.ctx.GetSessionVars().StmtCtx
	_, rhs, isDuration, err := convertStringToDuration(sc, rhsStr, b.tp.Decimal)
	if err != nil || isDuration {
		return d, true, err
	}

	d, isNull, err = calculateTimeDiff(sc, lhs, rhs)
	return d, isNull, err
}
597023
func truncateDuration(d time.Duration) time.Duration {
	for _, t := range durTransactions {
		if d > t.threshold {
			return d.Round(t.round)
		}
	}
	return d
}