miller/pkg/bifs/relative_time.go
Adam Lesperance 085e831668
The package version must match the major tag version (#1654)
* Update package version

* Update makefile targets

* Update readme packages

* Remaining old packages via rg/sd
2024-09-20 12:10:11 -04:00

350 lines
6.6 KiB
Go

package bifs
import (
"fmt"
"math"
"strings"
"github.com/johnkerl/miller/v6/pkg/mlrval"
)
func BIF_dhms2sec(input1 *mlrval.Mlrval) *mlrval.Mlrval {
if !input1.IsString() {
return mlrval.FromNotStringError("dhms2sec", input1)
}
input := input1.String()
if input == "" {
return mlrval.FromNotStringError("dhms2sec", input1)
}
negate := false
if input[0] == '-' {
input = input[1:]
negate = true
}
remainingInput := input
var seconds int64
for {
if remainingInput == "" {
break
}
var n int64
var rest string
_, err := fmt.Sscanf(remainingInput, "%d%s", &n, &rest)
if err != nil {
return mlrval.FromError(err)
}
if len(rest) < 1 {
return mlrval.FromErrorString("dhms2sec: input too short")
}
unitPart := rest[0]
remainingInput = rest[1:]
switch unitPart {
case 'd':
seconds += n * 86400
case 'h':
seconds += n * 3600
case 'm':
seconds += n * 60
case 's':
seconds += n
default:
return mlrval.FromError(
fmt.Errorf(
"dhms2sec(\"%s\"): unrecognized unit '%c'",
input1.OriginalString(),
unitPart,
),
)
}
}
if negate {
seconds = -seconds
}
return mlrval.FromInt(seconds)
}
func BIF_dhms2fsec(input1 *mlrval.Mlrval) *mlrval.Mlrval {
if !input1.IsString() {
return mlrval.FromNotStringError("dhms2fsec", input1)
}
input := input1.String()
if input == "" {
return mlrval.FromNotStringError("dhms2fsec", input1)
}
negate := false
if input[0] == '-' {
input = input[1:]
negate = true
}
remainingInput := input
var seconds float64
for {
if remainingInput == "" {
break
}
var f float64
var rest string
_, err := fmt.Sscanf(remainingInput, "%f%s", &f, &rest)
if err != nil {
return mlrval.FromError(err)
}
if len(rest) < 1 {
return mlrval.FromErrorString("dhms2fsec: input too short")
}
unitPart := rest[0]
remainingInput = rest[1:]
switch unitPart {
case 'd':
seconds += f * 86400.0
case 'h':
seconds += f * 3600.0
case 'm':
seconds += f * 60.0
case 's':
seconds += f
default:
return mlrval.FromError(
fmt.Errorf(
"dhms2fsec(\"%s\"): unrecognized unit '%c'",
input1.OriginalString(),
unitPart,
),
)
}
}
if negate {
seconds = -seconds
}
return mlrval.FromFloat(seconds)
}
func BIF_hms2sec(input1 *mlrval.Mlrval) *mlrval.Mlrval {
if !input1.IsString() {
return mlrval.FromNotStringError("hms2sec", input1)
}
if input1.AcquireStringValue() == "" {
return mlrval.FromNotStringError("hms2sec", input1)
}
var h, m, s int64
if strings.HasPrefix(input1.AcquireStringValue(), "-") {
n, err := fmt.Sscanf(input1.AcquireStringValue(), "-%d:%d:%d", &h, &m, &s)
if n == 3 && err == nil {
return mlrval.FromInt(-(s + m*60 + h*60*60))
}
} else {
n, err := fmt.Sscanf(input1.AcquireStringValue(), "%d:%d:%d", &h, &m, &s)
if n == 3 && err == nil {
return mlrval.FromInt(s + m*60 + h*60*60)
}
}
return mlrval.FromError(
fmt.Errorf("hsm2sec: could not parse input \"%s\"", input1.OriginalString()),
)
}
func BIF_hms2fsec(input1 *mlrval.Mlrval) *mlrval.Mlrval {
if !input1.IsString() {
return mlrval.FromNotStringError("hms2fsec", input1)
}
var h, m int
var s float64
if strings.HasPrefix(input1.AcquireStringValue(), "-") {
n, err := fmt.Sscanf(input1.AcquireStringValue(), "-%d:%d:%f", &h, &m, &s)
if n == 3 && err == nil {
return mlrval.FromFloat(-(s + float64(m*60+h*60*60)))
}
} else {
n, err := fmt.Sscanf(input1.AcquireStringValue(), "%d:%d:%f", &h, &m, &s)
if n == 3 && err == nil {
return mlrval.FromFloat(s + float64(m*60+h*60*60))
}
}
return mlrval.FromError(
fmt.Errorf("hsm2fsec: could not parse input \"%s\"", input1.OriginalString()),
)
}
func BIF_sec2dhms(input1 *mlrval.Mlrval) *mlrval.Mlrval {
isec, ok := input1.GetIntValue()
if !ok {
return mlrval.FromNotIntError("sec2dhms", input1)
}
var d, h, m, s int64
splitIntToDHMS(isec, &d, &h, &m, &s)
if d != 0 {
return mlrval.FromString(
fmt.Sprintf("%dd%02dh%02dm%02ds", d, h, m, s),
)
} else if h != 0 {
return mlrval.FromString(
fmt.Sprintf("%dh%02dm%02ds", h, m, s),
)
} else if m != 0 {
return mlrval.FromString(
fmt.Sprintf("%dm%02ds", m, s),
)
} else {
return mlrval.FromString(
fmt.Sprintf("%ds", s),
)
}
}
func BIF_sec2hms(input1 *mlrval.Mlrval) *mlrval.Mlrval {
isec, ok := input1.GetIntValue()
if !ok {
return mlrval.FromNotIntError("sec2hms", input1)
}
sign := ""
if isec < 0 {
sign = "-"
isec = -isec
}
var d, h, m, s int64
splitIntToDHMS(isec, &d, &h, &m, &s)
h += d * 24
return mlrval.FromString(
fmt.Sprintf("%s%02d:%02d:%02d", sign, h, m, s),
)
}
func BIF_fsec2dhms(input1 *mlrval.Mlrval) *mlrval.Mlrval {
fsec, ok := input1.GetNumericToFloatValue()
if !ok {
return mlrval.FromNotIntError("fsec2dhms", input1)
}
sign := int64(1)
if fsec < 0 {
sign = -1
fsec = -fsec
}
isec := int64(math.Trunc(fsec))
fractional := fsec - float64(isec)
var d, h, m, s int64
splitIntToDHMS(isec, &d, &h, &m, &s)
if d != 0 {
d = sign * d
return mlrval.FromString(
fmt.Sprintf(
"%dd%02dh%02dm%09.6fs",
d, h, m, float64(s)+fractional),
)
} else if h != 0 {
h = sign * h
return mlrval.FromString(
fmt.Sprintf(
"%dh%02dm%09.6fs",
h, m, float64(s)+fractional),
)
} else if m != 0 {
m = sign * m
return mlrval.FromString(
fmt.Sprintf(
"%dm%09.6fs",
m, float64(s)+fractional),
)
} else {
s = sign * s
fractional = float64(sign) * fractional
return mlrval.FromString(
fmt.Sprintf(
"%.6fs",
float64(s)+fractional),
)
}
}
func BIF_fsec2hms(input1 *mlrval.Mlrval) *mlrval.Mlrval {
fsec, ok := input1.GetNumericToFloatValue()
if !ok {
return mlrval.FromNotIntError("fsec2hms", input1)
}
sign := ""
if fsec < 0 {
sign = "-"
fsec = -fsec
}
isec := int64(math.Trunc(fsec))
fractional := fsec - float64(isec)
var d, h, m, s int64
splitIntToDHMS(isec, &d, &h, &m, &s)
h += d * 24
// "%02.6f" does not exist so we have to do our own zero-pad
if s < 10 {
return mlrval.FromString(
fmt.Sprintf("%s%02d:%02d:0%.6f", sign, h, m, float64(s)+fractional),
)
} else {
return mlrval.FromString(
fmt.Sprintf("%s%02d:%02d:%.6f", sign, h, m, float64(s)+fractional),
)
}
}
// Helper function
func splitIntToDHMS(u int64, pd, ph, pm, ps *int64) {
d := int64(0)
h := int64(0)
m := int64(0)
s := int64(0)
sign := int64(1)
if u < 0 {
u = -u
sign = -1
}
s = u % 60
u = u / 60
if u == 0 {
s = s * sign
} else {
m = u % 60
u = u / 60
if u == 0 {
m = m * sign
} else {
h = u % 24
u = u / 24
if u == 0 {
h = h * sign
} else {
d = u * sign
}
}
}
*pd = d
*ph = h
*pm = m
*ps = s
}