time.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  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. "errors"
  18. "fmt"
  19. "regexp"
  20. "strings"
  21. "time"
  22. "github.com/globalsign/mgo/bson"
  23. "github.com/mailru/easyjson/jlexer"
  24. "github.com/mailru/easyjson/jwriter"
  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. // DateTimePattern pattern to match for the date-time format from http://tools.ietf.org/html/rfc3339#section-5.6
  53. DateTimePattern = `^([0-9]{2}):([0-9]{2}):([0-9]{2})(.[0-9]+)?(z|([+-][0-9]{2}:[0-9]{2}))$`
  54. )
  55. var (
  56. dateTimeFormats = []string{RFC3339Micro, RFC3339Millis, time.RFC3339, time.RFC3339Nano}
  57. rxDateTime = regexp.MustCompile(DateTimePattern)
  58. // MarshalFormat sets the time resolution format used for marshaling time (set to milliseconds)
  59. MarshalFormat = RFC3339Millis
  60. )
  61. // ParseDateTime parses a string that represents an ISO8601 time or a unix epoch
  62. func ParseDateTime(data string) (DateTime, error) {
  63. if data == "" {
  64. return NewDateTime(), nil
  65. }
  66. var lastError error
  67. for _, layout := range dateTimeFormats {
  68. dd, err := time.Parse(layout, data)
  69. if err != nil {
  70. lastError = err
  71. continue
  72. }
  73. lastError = nil
  74. return DateTime(dd), nil
  75. }
  76. return DateTime{}, lastError
  77. }
  78. // DateTime is a time but it serializes to ISO8601 format with millis
  79. // It knows how to read 3 different variations of a RFC3339 date time.
  80. // Most APIs we encounter want either millisecond or second precision times.
  81. // This just tries to make it worry-free.
  82. //
  83. // swagger:strfmt date-time
  84. type DateTime time.Time
  85. // NewDateTime is a representation of zero value for DateTime type
  86. func NewDateTime() DateTime {
  87. return DateTime(time.Unix(0, 0).UTC())
  88. }
  89. // String converts this time to a string
  90. func (t DateTime) String() string {
  91. return time.Time(t).Format(MarshalFormat)
  92. }
  93. // MarshalText implements the text marshaller interface
  94. func (t DateTime) MarshalText() ([]byte, error) {
  95. return []byte(t.String()), nil
  96. }
  97. // UnmarshalText implements the text unmarshaller interface
  98. func (t *DateTime) UnmarshalText(text []byte) error {
  99. tt, err := ParseDateTime(string(text))
  100. if err != nil {
  101. return err
  102. }
  103. *t = tt
  104. return nil
  105. }
  106. // Scan scans a DateTime value from database driver type.
  107. func (t *DateTime) Scan(raw interface{}) error {
  108. // TODO: case int64: and case float64: ?
  109. switch v := raw.(type) {
  110. case []byte:
  111. return t.UnmarshalText(v)
  112. case string:
  113. return t.UnmarshalText([]byte(v))
  114. case time.Time:
  115. *t = DateTime(v)
  116. case nil:
  117. *t = DateTime{}
  118. default:
  119. return fmt.Errorf("cannot sql.Scan() strfmt.DateTime from: %#v", v)
  120. }
  121. return nil
  122. }
  123. // Value converts DateTime to a primitive value ready to written to a database.
  124. func (t DateTime) Value() (driver.Value, error) {
  125. return driver.Value(t.String()), nil
  126. }
  127. // MarshalJSON returns the DateTime as JSON
  128. func (t DateTime) MarshalJSON() ([]byte, error) {
  129. var w jwriter.Writer
  130. t.MarshalEasyJSON(&w)
  131. return w.BuildBytes()
  132. }
  133. // MarshalEasyJSON writes the DateTime to a easyjson.Writer
  134. func (t DateTime) MarshalEasyJSON(w *jwriter.Writer) {
  135. w.String(time.Time(t).Format(MarshalFormat))
  136. }
  137. // UnmarshalJSON sets the DateTime from JSON
  138. func (t *DateTime) UnmarshalJSON(data []byte) error {
  139. l := jlexer.Lexer{Data: data}
  140. t.UnmarshalEasyJSON(&l)
  141. return l.Error()
  142. }
  143. // UnmarshalEasyJSON sets the DateTime from a easyjson.Lexer
  144. func (t *DateTime) UnmarshalEasyJSON(in *jlexer.Lexer) {
  145. if data := in.String(); in.Ok() {
  146. tt, err := ParseDateTime(data)
  147. if err != nil {
  148. in.AddError(err)
  149. return
  150. }
  151. *t = tt
  152. }
  153. }
  154. // GetBSON returns the DateTime as a bson.M{} map.
  155. func (t *DateTime) GetBSON() (interface{}, error) {
  156. return bson.M{"data": t.String()}, nil
  157. }
  158. // SetBSON sets the DateTime from raw bson data
  159. func (t *DateTime) SetBSON(raw bson.Raw) error {
  160. var m bson.M
  161. if err := raw.Unmarshal(&m); err != nil {
  162. return err
  163. }
  164. if data, ok := m["data"].(string); ok {
  165. var err error
  166. *t, err = ParseDateTime(data)
  167. return err
  168. }
  169. return errors.New("couldn't unmarshal bson raw value as Duration")
  170. }