You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

263 lines
7.4 KiB

  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. package strfmt
  15. import (
  16. "database/sql/driver"
  17. "encoding/binary"
  18. "encoding/json"
  19. "fmt"
  20. "regexp"
  21. "strings"
  22. "time"
  23. "go.mongodb.org/mongo-driver/bson"
  24. "go.mongodb.org/mongo-driver/bson/bsontype"
  25. )
  26. func init() {
  27. dt := DateTime{}
  28. Default.Add("datetime", &dt, IsDateTime)
  29. }
  30. // IsDateTime returns true when the string is a valid date-time
  31. func IsDateTime(str string) bool {
  32. if len(str) < 4 {
  33. return false
  34. }
  35. s := strings.Split(strings.ToLower(str), "t")
  36. if len(s) < 2 || !IsDate(s[0]) {
  37. return false
  38. }
  39. matches := rxDateTime.FindAllStringSubmatch(s[1], -1)
  40. if len(matches) == 0 || len(matches[0]) == 0 {
  41. return false
  42. }
  43. m := matches[0]
  44. res := m[1] <= "23" && m[2] <= "59" && m[3] <= "59"
  45. return res
  46. }
  47. const (
  48. // RFC3339Millis represents a ISO8601 format to millis instead of to nanos
  49. RFC3339Millis = "2006-01-02T15:04:05.000Z07:00"
  50. // RFC3339Micro represents a ISO8601 format to micro instead of to nano
  51. RFC3339Micro = "2006-01-02T15:04:05.000000Z07:00"
  52. // ISO8601LocalTime represents a ISO8601 format to ISO8601 in local time (no timezone)
  53. ISO8601LocalTime = "2006-01-02T15:04:05"
  54. // ISO8601TimeWithReducedPrecision represents a ISO8601 format with reduced precision (dropped secs)
  55. ISO8601TimeWithReducedPrecision = "2006-01-02T15:04Z"
  56. // ISO8601TimeWithReducedPrecision represents a ISO8601 format with reduced precision and no timezone (dropped seconds + no timezone)
  57. ISO8601TimeWithReducedPrecisionLocaltime = "2006-01-02T15:04"
  58. // DateTimePattern pattern to match for the date-time format from http://tools.ietf.org/html/rfc3339#section-5.6
  59. DateTimePattern = `^([0-9]{2}):([0-9]{2}):([0-9]{2})(.[0-9]+)?(z|([+-][0-9]{2}:[0-9]{2}))$`
  60. )
  61. var (
  62. dateTimeFormats = []string{RFC3339Micro, RFC3339Millis, time.RFC3339, time.RFC3339Nano, ISO8601LocalTime, ISO8601TimeWithReducedPrecision, ISO8601TimeWithReducedPrecisionLocaltime}
  63. rxDateTime = regexp.MustCompile(DateTimePattern)
  64. // MarshalFormat sets the time resolution format used for marshaling time (set to milliseconds)
  65. MarshalFormat = RFC3339Millis
  66. )
  67. // ParseDateTime parses a string that represents an ISO8601 time or a unix epoch
  68. func ParseDateTime(data string) (DateTime, error) {
  69. if data == "" {
  70. return NewDateTime(), nil
  71. }
  72. var lastError error
  73. for _, layout := range dateTimeFormats {
  74. dd, err := time.Parse(layout, data)
  75. if err != nil {
  76. lastError = err
  77. continue
  78. }
  79. return DateTime(dd), nil
  80. }
  81. return DateTime{}, lastError
  82. }
  83. // DateTime is a time but it serializes to ISO8601 format with millis
  84. // It knows how to read 3 different variations of a RFC3339 date time.
  85. // Most APIs we encounter want either millisecond or second precision times.
  86. // This just tries to make it worry-free.
  87. //
  88. // swagger:strfmt date-time
  89. type DateTime time.Time
  90. // NewDateTime is a representation of zero value for DateTime type
  91. func NewDateTime() DateTime {
  92. return DateTime(time.Unix(0, 0).UTC())
  93. }
  94. // String converts this time to a string
  95. func (t DateTime) String() string {
  96. return time.Time(t).Format(MarshalFormat)
  97. }
  98. // MarshalText implements the text marshaller interface
  99. func (t DateTime) MarshalText() ([]byte, error) {
  100. return []byte(t.String()), nil
  101. }
  102. // UnmarshalText implements the text unmarshaller interface
  103. func (t *DateTime) UnmarshalText(text []byte) error {
  104. tt, err := ParseDateTime(string(text))
  105. if err != nil {
  106. return err
  107. }
  108. *t = tt
  109. return nil
  110. }
  111. // Scan scans a DateTime value from database driver type.
  112. func (t *DateTime) Scan(raw interface{}) error {
  113. // TODO: case int64: and case float64: ?
  114. switch v := raw.(type) {
  115. case []byte:
  116. return t.UnmarshalText(v)
  117. case string:
  118. return t.UnmarshalText([]byte(v))
  119. case time.Time:
  120. *t = DateTime(v)
  121. case nil:
  122. *t = DateTime{}
  123. default:
  124. return fmt.Errorf("cannot sql.Scan() strfmt.DateTime from: %#v", v)
  125. }
  126. return nil
  127. }
  128. // Value converts DateTime to a primitive value ready to written to a database.
  129. func (t DateTime) Value() (driver.Value, error) {
  130. return driver.Value(t.String()), nil
  131. }
  132. // MarshalJSON returns the DateTime as JSON
  133. func (t DateTime) MarshalJSON() ([]byte, error) {
  134. return json.Marshal(time.Time(t).Format(MarshalFormat))
  135. }
  136. // UnmarshalJSON sets the DateTime from JSON
  137. func (t *DateTime) UnmarshalJSON(data []byte) error {
  138. if string(data) == jsonNull {
  139. return nil
  140. }
  141. var tstr string
  142. if err := json.Unmarshal(data, &tstr); err != nil {
  143. return err
  144. }
  145. tt, err := ParseDateTime(tstr)
  146. if err != nil {
  147. return err
  148. }
  149. *t = tt
  150. return nil
  151. }
  152. // MarshalBSON renders the DateTime as a BSON document
  153. func (t DateTime) MarshalBSON() ([]byte, error) {
  154. return bson.Marshal(bson.M{"data": t})
  155. }
  156. // UnmarshalBSON reads the DateTime from a BSON document
  157. func (t *DateTime) UnmarshalBSON(data []byte) error {
  158. var obj struct {
  159. Data DateTime
  160. }
  161. if err := bson.Unmarshal(data, &obj); err != nil {
  162. return err
  163. }
  164. *t = obj.Data
  165. return nil
  166. }
  167. // MarshalBSONValue is an interface implemented by types that can marshal themselves
  168. // into a BSON document represented as bytes. The bytes returned must be a valid
  169. // BSON document if the error is nil.
  170. // Marshals a DateTime as a bsontype.DateTime, an int64 representing
  171. // milliseconds since epoch.
  172. func (t DateTime) MarshalBSONValue() (bsontype.Type, []byte, error) {
  173. // UnixNano cannot be used, the result of calling UnixNano on the zero
  174. // Time is undefined.
  175. i64 := time.Time(t).Unix() * 1000
  176. buf := make([]byte, 8)
  177. binary.LittleEndian.PutUint64(buf, uint64(i64))
  178. return bsontype.DateTime, buf, nil
  179. }
  180. // UnmarshalBSONValue is an interface implemented by types that can unmarshal a
  181. // BSON value representation of themselves. The BSON bytes and type can be
  182. // assumed to be valid. UnmarshalBSONValue must copy the BSON value bytes if it
  183. // wishes to retain the data after returning.
  184. func (t *DateTime) UnmarshalBSONValue(tpe bsontype.Type, data []byte) error {
  185. i64 := int64(binary.LittleEndian.Uint64(data))
  186. // TODO: Use bsonprim.DateTime.Time() method
  187. *t = DateTime(time.Unix(i64/1000, i64%1000*1000000))
  188. return nil
  189. }
  190. // DeepCopyInto copies the receiver and writes its value into out.
  191. func (t *DateTime) DeepCopyInto(out *DateTime) {
  192. *out = *t
  193. }
  194. // DeepCopy copies the receiver into a new DateTime.
  195. func (t *DateTime) DeepCopy() *DateTime {
  196. if t == nil {
  197. return nil
  198. }
  199. out := new(DateTime)
  200. t.DeepCopyInto(out)
  201. return out
  202. }
  203. // GobEncode implements the gob.GobEncoder interface.
  204. func (t DateTime) GobEncode() ([]byte, error) {
  205. return t.MarshalBinary()
  206. }
  207. // GobDecode implements the gob.GobDecoder interface.
  208. func (t *DateTime) GobDecode(data []byte) error {
  209. return t.UnmarshalBinary(data)
  210. }
  211. // MarshalBinary implements the encoding.BinaryMarshaler interface.
  212. func (t DateTime) MarshalBinary() ([]byte, error) {
  213. return time.Time(t).MarshalBinary()
  214. }
  215. // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.
  216. func (t *DateTime) UnmarshalBinary(data []byte) error {
  217. var original time.Time
  218. err := original.UnmarshalBinary(data)
  219. if err != nil {
  220. return err
  221. }
  222. *t = DateTime(original)
  223. return nil
  224. }