Repository: brimsec/zq (go)

Issue:
Cannot cast to duration
`duration` was forgotten when we added primitive casts a while back:

```
$ echo {}  | zq -t "put a=1 | cut a=a:duration" -
rhs of assigment expression: cast to 'duration' not implemented
```

Pull request description:
Add duration cast
close #2193 

Patch:
diff --git a/expr/cast.go b/expr/cast.go
index 48e5dca99..70ebae6d1 100644
--- a/expr/cast.go
+++ b/expr/cast.go
@@ -33,6 +33,8 @@ func LookupPrimitiveCaster(typ zng.Type) PrimitiveCaster {
 		return castToFloat64
 	case zng.TypeIP:
 		return castToIP
+	case zng.TypeDuration:
+		return castToDuration
 	case zng.TypeTime:
 		return castToTime
 	case zng.TypeString:
@@ -100,6 +102,20 @@ func castToIP(zv zng.Value) (zng.Value, error) {
 	return zng.Value{zng.TypeIP, zng.EncodeIP(ip)}, nil
 }
 
+func castToDuration(zv zng.Value) (zng.Value, error) {
+	if zng.IsFloat(zv.Type.ID()) {
+		f, _ := zng.DecodeFloat64(zv.Bytes)
+		ts := int64(nano.FloatToTs(f))
+		// XXX GC
+		return zng.Value{zng.TypeDuration, zng.EncodeDuration(ts)}, nil
+	}
+	ns, ok := coerce.ToInt(zv)
+	if !ok {
+		return zng.Value{}, ErrBadCast
+	}
+	return zng.Value{zng.TypeDuration, zng.EncodeDuration(ns)}, nil
+}
+
 func castToTime(zv zng.Value) (zng.Value, error) {
 	if zng.IsFloat(zv.Type.ID()) {
 		f, _ := zng.DecodeFloat64(zv.Bytes)


Test patch:
diff --git a/expr/ztests/time-duration-cast.yaml b/expr/ztests/time-duration-cast.yaml
new file mode 100644
index 000000000..e3df75dfa
--- /dev/null
+++ b/expr/ztests/time-duration-cast.yaml
@@ -0,0 +1,17 @@
+zql: cut t=t:time,d=d:duration
+
+input: |
+  #0:record[t:string,d:string]
+  0:[1;1;]
+  #1:record[t:int64,d:int64]
+  1:[1;1;]
+  #2:record[t:float64,d:float64]
+  2:[1;1;]
+
+output-flags: -f tzng
+
+output: |
+  #0:record[t:time,d:duration]
+  0:[0.000000001;0.000000001;]
+  0:[0.000000001;0.000000001;]
+  0:[1;1;]