Merge branch 'main' into 18842-arv-mount-disk-config
[arvados.git] / sdk / go / arvados / duration.go
index 7b87aee6ab7b14c875aa044e3b88e11ed22bd567..9df210ccb016ef85327b9eaf09ca3aacec0ae9f2 100644 (file)
@@ -1,8 +1,14 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: Apache-2.0
+
 package arvados
 
 import (
+       "bytes"
        "encoding/json"
        "fmt"
+       "strings"
        "time"
 )
 
@@ -10,25 +16,43 @@ import (
 // a number of nanoseconds.
 type Duration time.Duration
 
-// UnmarshalJSON implements json.Unmarshaler
+// UnmarshalJSON implements json.Unmarshaler.
 func (d *Duration) UnmarshalJSON(data []byte) error {
+       if bytes.Equal(data, []byte(`"0"`)) || bytes.Equal(data, []byte(`0`)) {
+               // Unitless 0 is not accepted by ParseDuration, but we
+               // accept it as a reasonable spelling of 0
+               // nanoseconds.
+               *d = 0
+               return nil
+       }
        if data[0] == '"' {
                return d.Set(string(data[1 : len(data)-1]))
        }
-       return fmt.Errorf("duration must be given as a string like \"600s\" or \"1h30m\"")
+       // Mimic error message returned by ParseDuration for a number
+       // without units.
+       return fmt.Errorf("missing unit in duration %q", data)
 }
 
-// MarshalJSON implements json.Marshaler
-func (d *Duration) MarshalJSON() ([]byte, error) {
+// MarshalJSON implements json.Marshaler.
+func (d Duration) MarshalJSON() ([]byte, error) {
        return json.Marshal(d.String())
 }
 
-// String implements fmt.Stringer
+// String returns a format similar to (time.Duration)String() but with
+// "0m" and "0s" removed: e.g., "1h" instead of "1h0m0s".
 func (d Duration) String() string {
-       return time.Duration(d).String()
+       s := time.Duration(d).String()
+       s = strings.Replace(s, "m0s", "m", 1)
+       s = strings.Replace(s, "h0m", "h", 1)
+       return s
+}
+
+// Duration returns a time.Duration.
+func (d Duration) Duration() time.Duration {
+       return time.Duration(d)
 }
 
-// Value implements flag.Value
+// Set implements the flag.Value interface and sets the duration value by using time.ParseDuration to parse the string.
 func (d *Duration) Set(s string) error {
        dur, err := time.ParseDuration(s)
        *d = Duration(dur)