time_unit.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. package option
  2. import (
  3. "errors"
  4. "time"
  5. )
  6. // Copyright 2010 The Go Authors. All rights reserved.
  7. // Use of this source code is governed by a BSD-style
  8. // license that can be found in the LICENSE file.
  9. const durationDay = 24 * time.Hour
  10. var unitMap = map[string]uint64{
  11. "ns": uint64(time.Nanosecond),
  12. "us": uint64(time.Microsecond),
  13. "µs": uint64(time.Microsecond), // U+00B5 = micro symbol
  14. "μs": uint64(time.Microsecond), // U+03BC = Greek letter mu
  15. "ms": uint64(time.Millisecond),
  16. "s": uint64(time.Second),
  17. "m": uint64(time.Minute),
  18. "h": uint64(time.Hour),
  19. "d": uint64(durationDay),
  20. }
  21. // ParseDuration parses a duration string.
  22. // A duration string is a possibly signed sequence of
  23. // decimal numbers, each with optional fraction and a unit suffix,
  24. // such as "300ms", "-1.5h" or "2h45m".
  25. // Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
  26. func ParseDuration(s string) (Duration, error) {
  27. // [-+]?([0-9]*(\.[0-9]*)?[a-z]+)+
  28. orig := s
  29. var d uint64
  30. neg := false
  31. // Consume [-+]?
  32. if s != "" {
  33. c := s[0]
  34. if c == '-' || c == '+' {
  35. neg = c == '-'
  36. s = s[1:]
  37. }
  38. }
  39. // Special case: if all that is left is "0", this is zero.
  40. if s == "0" {
  41. return 0, nil
  42. }
  43. if s == "" {
  44. return 0, errors.New("time: invalid duration " + quote(orig))
  45. }
  46. for s != "" {
  47. var (
  48. v, f uint64 // integers before, after decimal point
  49. scale float64 = 1 // value = v + f/scale
  50. )
  51. var err error
  52. // The next character must be [0-9.]
  53. if !(s[0] == '.' || '0' <= s[0] && s[0] <= '9') {
  54. return 0, errors.New("time: invalid duration " + quote(orig))
  55. }
  56. // Consume [0-9]*
  57. pl := len(s)
  58. v, s, err = leadingInt(s)
  59. if err != nil {
  60. return 0, errors.New("time: invalid duration " + quote(orig))
  61. }
  62. pre := pl != len(s) // whether we consumed anything before a period
  63. // Consume (\.[0-9]*)?
  64. post := false
  65. if s != "" && s[0] == '.' {
  66. s = s[1:]
  67. pl := len(s)
  68. f, scale, s = leadingFraction(s)
  69. post = pl != len(s)
  70. }
  71. if !pre && !post {
  72. // no digits (e.g. ".s" or "-.s")
  73. return 0, errors.New("time: invalid duration " + quote(orig))
  74. }
  75. // Consume unit.
  76. i := 0
  77. for ; i < len(s); i++ {
  78. c := s[i]
  79. if c == '.' || '0' <= c && c <= '9' {
  80. break
  81. }
  82. }
  83. if i == 0 {
  84. return 0, errors.New("time: missing unit in duration " + quote(orig))
  85. }
  86. u := s[:i]
  87. s = s[i:]
  88. unit, ok := unitMap[u]
  89. if !ok {
  90. return 0, errors.New("time: unknown unit " + quote(u) + " in duration " + quote(orig))
  91. }
  92. if v > 1<<63/unit {
  93. // overflow
  94. return 0, errors.New("time: invalid duration " + quote(orig))
  95. }
  96. v *= unit
  97. if f > 0 {
  98. // float64 is needed to be nanosecond accurate for fractions of hours.
  99. // v >= 0 && (f*unit/scale) <= 3.6e+12 (ns/h, h is the largest unit)
  100. v += uint64(float64(f) * (float64(unit) / scale))
  101. if v > 1<<63 {
  102. // overflow
  103. return 0, errors.New("time: invalid duration " + quote(orig))
  104. }
  105. }
  106. d += v
  107. if d > 1<<63 {
  108. return 0, errors.New("time: invalid duration " + quote(orig))
  109. }
  110. }
  111. if neg {
  112. return -Duration(d), nil
  113. }
  114. if d > 1<<63-1 {
  115. return 0, errors.New("time: invalid duration " + quote(orig))
  116. }
  117. return Duration(d), nil
  118. }
  119. var errLeadingInt = errors.New("time: bad [0-9]*") // never printed
  120. // leadingInt consumes the leading [0-9]* from s.
  121. func leadingInt[bytes []byte | string](s bytes) (x uint64, rem bytes, err error) {
  122. i := 0
  123. for ; i < len(s); i++ {
  124. c := s[i]
  125. if c < '0' || c > '9' {
  126. break
  127. }
  128. if x > 1<<63/10 {
  129. // overflow
  130. return 0, rem, errLeadingInt
  131. }
  132. x = x*10 + uint64(c) - '0'
  133. if x > 1<<63 {
  134. // overflow
  135. return 0, rem, errLeadingInt
  136. }
  137. }
  138. return x, s[i:], nil
  139. }
  140. // leadingFraction consumes the leading [0-9]* from s.
  141. // It is used only for fractions, so does not return an error on overflow,
  142. // it just stops accumulating precision.
  143. func leadingFraction(s string) (x uint64, scale float64, rem string) {
  144. i := 0
  145. scale = 1
  146. overflow := false
  147. for ; i < len(s); i++ {
  148. c := s[i]
  149. if c < '0' || c > '9' {
  150. break
  151. }
  152. if overflow {
  153. continue
  154. }
  155. if x > (1<<63-1)/10 {
  156. // It's possible for overflow to give a positive number, so take care.
  157. overflow = true
  158. continue
  159. }
  160. y := x*10 + uint64(c) - '0'
  161. if y > 1<<63 {
  162. overflow = true
  163. continue
  164. }
  165. x = y
  166. scale *= 10
  167. }
  168. return x, scale, s[i:]
  169. }
  170. // These are borrowed from unicode/utf8 and strconv and replicate behavior in
  171. // that package, since we can't take a dependency on either.
  172. const (
  173. lowerhex = "0123456789abcdef"
  174. runeSelf = 0x80
  175. runeError = '\uFFFD'
  176. )
  177. func quote(s string) string {
  178. buf := make([]byte, 1, len(s)+2) // slice will be at least len(s) + quotes
  179. buf[0] = '"'
  180. for i, c := range s {
  181. if c >= runeSelf || c < ' ' {
  182. // This means you are asking us to parse a time.Duration or
  183. // time.Location with unprintable or non-ASCII characters in it.
  184. // We don't expect to hit this case very often. We could try to
  185. // reproduce strconv.Quote's behavior with full fidelity but
  186. // given how rarely we expect to hit these edge cases, speed and
  187. // conciseness are better.
  188. var width int
  189. if c == runeError {
  190. width = 1
  191. if i+2 < len(s) && s[i:i+3] == string(runeError) {
  192. width = 3
  193. }
  194. } else {
  195. width = len(string(c))
  196. }
  197. for j := 0; j < width; j++ {
  198. buf = append(buf, `\x`...)
  199. buf = append(buf, lowerhex[s[i+j]>>4])
  200. buf = append(buf, lowerhex[s[i+j]&0xF])
  201. }
  202. } else {
  203. if c == '"' || c == '\\' {
  204. buf = append(buf, '\\')
  205. }
  206. buf = append(buf, string(c)...)
  207. }
  208. }
  209. buf = append(buf, '"')
  210. return string(buf)
  211. }