package timeconv
import (
"fmt"
"math"
"regexp"
"strconv"
"strings"
)
// MillisPerSecond is the number of millseconds per second.
const MillisPerSecond int64 = 1000
// MillisPerMinute is the number of millseconds per minute.
const MillisPerMinute int64 = MillisPerSecond * 60
// MillisPerHour is the number of millseconds per hour.
const MillisPerHour int64 = MillisPerMinute * 60
// MillisPerDay is the number of millseconds per day.
const MillisPerDay int64 = MillisPerHour * 24
// MillisPerWeek is the number of millseconds per week.
const MillisPerWeek int64 = MillisPerDay * 7
// MillisPerYear is the approximate number of millseconds per year.
const MillisPerYear int64 = MillisPerDay*365 + int64((float64(MillisPerDay) * 0.25))
// ParseMilliseconds parses a string containing a number plus
// a unit of measure for time and returns the number of milliseconds
// it represents.
//
// Example:
// * "1 second" returns 1000
// * "1 minute" returns 60000
// * "1 hour" returns 3600000
//
// See config.UnitsToMillis for a list of supported units of measure.
func ParseMilliseconds(str string) (int64, error) {
s := strings.TrimSpace(str)
reg := regexp.MustCompile("([0-9\\.\\-+]*)(.*)")
matches := reg.FindStringSubmatch(s)
if matches == nil || len(matches) < 1 || matches[1] == "" {
return 0, fmt.Errorf("invalid syntax - '%s'", s)
}
digits := matches[1]
units := "ms"
if len(matches) > 1 && matches[2] != "" {
units = matches[2]
}
fDigits, err := strconv.ParseFloat(digits, 64)
if err != nil {
return 0, err
}
msPerUnit, err := UnitsToMillis(units)
if err != nil {
return 0, err
}
// Check for overflow.
fms := float64(msPerUnit) * fDigits
if fms > math.MaxInt64 || fms < math.MinInt64 {
return 0, fmt.Errorf("out of range - '%s' overflows", s)
}
ms := int64(fms)
return ms, nil
}
// UnitsToMillis returns the number of milliseconds represented by the specified unit of measure.
//
// Example:
// * "second" returns 1000
// * "minute" returns 60000
// * "hour" returns 3600000
//
// Supported units of measure:
// * "milliseconds", "millis", "ms", "millisecond"
// * "seconds", "sec", "s", "second"
// * "minutes", "mins", "min", "m", "minute"
// * "hours", "h", "hour"
// * "days", "d", "day"
// * "weeks", "w", "week"
// * "years", "y", "year"
func UnitsToMillis(units string) (ms int64, err error) {
u := strings.TrimSpace(units)
u = strings.ToLower(u)
switch u {
case "milliseconds", "millisecond", "millis", "ms":
ms = 1
case "seconds", "second", "sec", "s":
ms = MillisPerSecond
case "minutes", "minute", "mins", "min", "m":
ms = MillisPerMinute
case "hours", "hour", "h":
ms = MillisPerHour
case "days", "day", "d":
ms = MillisPerDay
case "weeks", "week", "w":
ms = MillisPerWeek
case "years", "year", "y":
ms = MillisPerYear
default:
err = fmt.Errorf("invalid syntax - '%s' not a supported unit of measure", u)
}
return
}