...

Source file src/github.com/go-openapi/strfmt/duration.go

Documentation: github.com/go-openapi/strfmt

     1  // Copyright 2015 go-swagger maintainers
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //    http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package strfmt
    16  
    17  import (
    18  	"database/sql/driver"
    19  	"encoding/json"
    20  	"errors"
    21  	"fmt"
    22  	"regexp"
    23  	"strconv"
    24  	"strings"
    25  	"time"
    26  
    27  	"go.mongodb.org/mongo-driver/bson"
    28  )
    29  
    30  func init() {
    31  	d := Duration(0)
    32  	// register this format in the default registry
    33  	Default.Add("duration", &d, IsDuration)
    34  }
    35  
    36  var (
    37  	timeUnits = [][]string{
    38  		{"ns", "nano"},
    39  		{"us", "µs", "micro"},
    40  		{"ms", "milli"},
    41  		{"s", "sec"},
    42  		{"m", "min"},
    43  		{"h", "hr", "hour"},
    44  		{"d", "day"},
    45  		{"w", "wk", "week"},
    46  	}
    47  
    48  	timeMultiplier = map[string]time.Duration{
    49  		"ns": time.Nanosecond,
    50  		"us": time.Microsecond,
    51  		"ms": time.Millisecond,
    52  		"s":  time.Second,
    53  		"m":  time.Minute,
    54  		"h":  time.Hour,
    55  		"d":  24 * time.Hour,
    56  		"w":  7 * 24 * time.Hour,
    57  	}
    58  
    59  	durationMatcher = regexp.MustCompile(`((\d+)\s*([A-Za-zµ]+))`)
    60  )
    61  
    62  // IsDuration returns true if the provided string is a valid duration
    63  func IsDuration(str string) bool {
    64  	_, err := ParseDuration(str)
    65  	return err == nil
    66  }
    67  
    68  // Duration represents a duration
    69  //
    70  // Duration stores a period of time as a nanosecond count, with the largest
    71  // repesentable duration being approximately 290 years.
    72  //
    73  // swagger:strfmt duration
    74  type Duration time.Duration
    75  
    76  // MarshalText turns this instance into text
    77  func (d Duration) MarshalText() ([]byte, error) {
    78  	return []byte(time.Duration(d).String()), nil
    79  }
    80  
    81  // UnmarshalText hydrates this instance from text
    82  func (d *Duration) UnmarshalText(data []byte) error { // validation is performed later on
    83  	dd, err := ParseDuration(string(data))
    84  	if err != nil {
    85  		return err
    86  	}
    87  	*d = Duration(dd)
    88  	return nil
    89  }
    90  
    91  // ParseDuration parses a duration from a string, compatible with scala duration syntax
    92  func ParseDuration(cand string) (time.Duration, error) {
    93  	if dur, err := time.ParseDuration(cand); err == nil {
    94  		return dur, nil
    95  	}
    96  
    97  	var dur time.Duration
    98  	ok := false
    99  	for _, match := range durationMatcher.FindAllStringSubmatch(cand, -1) {
   100  
   101  		factor, err := strconv.Atoi(match[2]) // converts string to int
   102  		if err != nil {
   103  			return 0, err
   104  		}
   105  		unit := strings.ToLower(strings.TrimSpace(match[3]))
   106  
   107  		for _, variants := range timeUnits {
   108  			last := len(variants) - 1
   109  			multiplier := timeMultiplier[variants[0]]
   110  
   111  			for i, variant := range variants {
   112  				if (last == i && strings.HasPrefix(unit, variant)) || strings.EqualFold(variant, unit) {
   113  					ok = true
   114  					dur += (time.Duration(factor) * multiplier)
   115  				}
   116  			}
   117  		}
   118  	}
   119  
   120  	if ok {
   121  		return dur, nil
   122  	}
   123  	return 0, fmt.Errorf("unable to parse %s as duration", cand)
   124  }
   125  
   126  // Scan reads a Duration value from database driver type.
   127  func (d *Duration) Scan(raw interface{}) error {
   128  	switch v := raw.(type) {
   129  	// TODO: case []byte: // ?
   130  	case int64:
   131  		*d = Duration(v)
   132  	case float64:
   133  		*d = Duration(int64(v))
   134  	case nil:
   135  		*d = Duration(0)
   136  	default:
   137  		return fmt.Errorf("cannot sql.Scan() strfmt.Duration from: %#v", v)
   138  	}
   139  
   140  	return nil
   141  }
   142  
   143  // Value converts Duration to a primitive value ready to be written to a database.
   144  func (d Duration) Value() (driver.Value, error) {
   145  	return driver.Value(int64(d)), nil
   146  }
   147  
   148  // String converts this duration to a string
   149  func (d Duration) String() string {
   150  	return time.Duration(d).String()
   151  }
   152  
   153  // MarshalJSON returns the Duration as JSON
   154  func (d Duration) MarshalJSON() ([]byte, error) {
   155  	return json.Marshal(time.Duration(d).String())
   156  }
   157  
   158  // UnmarshalJSON sets the Duration from JSON
   159  func (d *Duration) UnmarshalJSON(data []byte) error {
   160  	if string(data) == jsonNull {
   161  		return nil
   162  	}
   163  
   164  	var dstr string
   165  	if err := json.Unmarshal(data, &dstr); err != nil {
   166  		return err
   167  	}
   168  	tt, err := ParseDuration(dstr)
   169  	if err != nil {
   170  		return err
   171  	}
   172  	*d = Duration(tt)
   173  	return nil
   174  }
   175  
   176  func (d Duration) MarshalBSON() ([]byte, error) {
   177  	return bson.Marshal(bson.M{"data": d.String()})
   178  }
   179  
   180  func (d *Duration) UnmarshalBSON(data []byte) error {
   181  	var m bson.M
   182  	if err := bson.Unmarshal(data, &m); err != nil {
   183  		return err
   184  	}
   185  
   186  	if data, ok := m["data"].(string); ok {
   187  		rd, err := ParseDuration(data)
   188  		if err != nil {
   189  			return err
   190  		}
   191  		*d = Duration(rd)
   192  		return nil
   193  	}
   194  
   195  	return errors.New("couldn't unmarshal bson bytes value as Date")
   196  }
   197  
   198  // DeepCopyInto copies the receiver and writes its value into out.
   199  func (d *Duration) DeepCopyInto(out *Duration) {
   200  	*out = *d
   201  }
   202  
   203  // DeepCopy copies the receiver into a new Duration.
   204  func (d *Duration) DeepCopy() *Duration {
   205  	if d == nil {
   206  		return nil
   207  	}
   208  	out := new(Duration)
   209  	d.DeepCopyInto(out)
   210  	return out
   211  }
   212  

View as plain text