podman
319 строк · 9.5 Кб
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
15package strfmt
16
17import (
18"database/sql/driver"
19"encoding/binary"
20"encoding/json"
21"errors"
22"fmt"
23"regexp"
24"strings"
25"time"
26
27"go.mongodb.org/mongo-driver/bson"
28
29"go.mongodb.org/mongo-driver/bson/bsontype"
30)
31
32var (
33// UnixZero sets the zero unix timestamp we want to compare against.
34// Unix 0 for an EST timezone is not equivalent to a UTC timezone.
35UnixZero = time.Unix(0, 0).UTC()
36)
37
38func init() {
39dt := DateTime{}
40Default.Add("datetime", &dt, IsDateTime)
41}
42
43// IsDateTime returns true when the string is a valid date-time
44func IsDateTime(str string) bool {
45if len(str) < 4 {
46return false
47}
48s := strings.Split(strings.ToLower(str), "t")
49if len(s) < 2 || !IsDate(s[0]) {
50return false
51}
52
53matches := rxDateTime.FindAllStringSubmatch(s[1], -1)
54if len(matches) == 0 || len(matches[0]) == 0 {
55return false
56}
57m := matches[0]
58res := m[1] <= "23" && m[2] <= "59" && m[3] <= "59"
59return res
60}
61
62const (
63// RFC3339Millis represents a ISO8601 format to millis instead of to nanos
64RFC3339Millis = "2006-01-02T15:04:05.000Z07:00"
65// RFC3339MillisNoColon represents a ISO8601 format to millis instead of to nanos
66RFC3339MillisNoColon = "2006-01-02T15:04:05.000Z0700"
67// RFC3339Micro represents a ISO8601 format to micro instead of to nano
68RFC3339Micro = "2006-01-02T15:04:05.000000Z07:00"
69// RFC3339MicroNoColon represents a ISO8601 format to micro instead of to nano
70RFC3339MicroNoColon = "2006-01-02T15:04:05.000000Z0700"
71// ISO8601LocalTime represents a ISO8601 format to ISO8601 in local time (no timezone)
72ISO8601LocalTime = "2006-01-02T15:04:05"
73// ISO8601TimeWithReducedPrecision represents a ISO8601 format with reduced precision (dropped secs)
74ISO8601TimeWithReducedPrecision = "2006-01-02T15:04Z"
75// ISO8601TimeWithReducedPrecisionLocaltime represents a ISO8601 format with reduced precision and no timezone (dropped seconds + no timezone)
76ISO8601TimeWithReducedPrecisionLocaltime = "2006-01-02T15:04"
77// ISO8601TimeUniversalSortableDateTimePattern represents a ISO8601 universal sortable date time pattern.
78ISO8601TimeUniversalSortableDateTimePattern = "2006-01-02 15:04:05"
79// DateTimePattern pattern to match for the date-time format from http://tools.ietf.org/html/rfc3339#section-5.6
80DateTimePattern = `^([0-9]{2}):([0-9]{2}):([0-9]{2})(.[0-9]+)?(z|([+-][0-9]{2}:[0-9]{2}))$`
81)
82
83var (
84rxDateTime = regexp.MustCompile(DateTimePattern)
85
86// DateTimeFormats is the collection of formats used by ParseDateTime()
87DateTimeFormats = []string{RFC3339Micro, RFC3339MicroNoColon, RFC3339Millis, RFC3339MillisNoColon, time.RFC3339, time.RFC3339Nano, ISO8601LocalTime, ISO8601TimeWithReducedPrecision, ISO8601TimeWithReducedPrecisionLocaltime, ISO8601TimeUniversalSortableDateTimePattern}
88
89// MarshalFormat sets the time resolution format used for marshaling time (set to milliseconds)
90MarshalFormat = RFC3339Millis
91
92// NormalizeTimeForMarshal provides a normalization function on time befeore marshalling (e.g. time.UTC).
93// By default, the time value is not changed.
94NormalizeTimeForMarshal = func(t time.Time) time.Time { return t }
95
96// DefaultTimeLocation provides a location for a time when the time zone is not encoded in the string (ex: ISO8601 Local variants).
97DefaultTimeLocation = time.UTC
98)
99
100// ParseDateTime parses a string that represents an ISO8601 time or a unix epoch
101func ParseDateTime(data string) (DateTime, error) {
102if data == "" {
103return NewDateTime(), nil
104}
105var lastError error
106for _, layout := range DateTimeFormats {
107dd, err := time.ParseInLocation(layout, data, DefaultTimeLocation)
108if err != nil {
109lastError = err
110continue
111}
112return DateTime(dd), nil
113}
114return DateTime{}, lastError
115}
116
117// DateTime is a time but it serializes to ISO8601 format with millis
118// It knows how to read 3 different variations of a RFC3339 date time.
119// Most APIs we encounter want either millisecond or second precision times.
120// This just tries to make it worry-free.
121//
122// swagger:strfmt date-time
123type DateTime time.Time
124
125// NewDateTime is a representation of zero value for DateTime type
126func NewDateTime() DateTime {
127return DateTime(time.Unix(0, 0).UTC())
128}
129
130// String converts this time to a string
131func (t DateTime) String() string {
132return NormalizeTimeForMarshal(time.Time(t)).Format(MarshalFormat)
133}
134
135// IsZero returns whether the date time is a zero value
136func (t *DateTime) IsZero() bool {
137if t == nil {
138return true
139}
140return time.Time(*t).IsZero()
141}
142
143// IsUnixZerom returns whether the date time is equivalent to time.Unix(0, 0).UTC().
144func (t *DateTime) IsUnixZero() bool {
145if t == nil {
146return true
147}
148return time.Time(*t).Equal(UnixZero)
149}
150
151// MarshalText implements the text marshaller interface
152func (t DateTime) MarshalText() ([]byte, error) {
153return []byte(t.String()), nil
154}
155
156// UnmarshalText implements the text unmarshaller interface
157func (t *DateTime) UnmarshalText(text []byte) error {
158tt, err := ParseDateTime(string(text))
159if err != nil {
160return err
161}
162*t = tt
163return nil
164}
165
166// Scan scans a DateTime value from database driver type.
167func (t *DateTime) Scan(raw interface{}) error {
168// TODO: case int64: and case float64: ?
169switch v := raw.(type) {
170case []byte:
171return t.UnmarshalText(v)
172case string:
173return t.UnmarshalText([]byte(v))
174case time.Time:
175*t = DateTime(v)
176case nil:
177*t = DateTime{}
178default:
179return fmt.Errorf("cannot sql.Scan() strfmt.DateTime from: %#v", v)
180}
181
182return nil
183}
184
185// Value converts DateTime to a primitive value ready to written to a database.
186func (t DateTime) Value() (driver.Value, error) {
187return driver.Value(t.String()), nil
188}
189
190// MarshalJSON returns the DateTime as JSON
191func (t DateTime) MarshalJSON() ([]byte, error) {
192return json.Marshal(NormalizeTimeForMarshal(time.Time(t)).Format(MarshalFormat))
193}
194
195// UnmarshalJSON sets the DateTime from JSON
196func (t *DateTime) UnmarshalJSON(data []byte) error {
197if string(data) == jsonNull {
198return nil
199}
200
201var tstr string
202if err := json.Unmarshal(data, &tstr); err != nil {
203return err
204}
205tt, err := ParseDateTime(tstr)
206if err != nil {
207return err
208}
209*t = tt
210return nil
211}
212
213// MarshalBSON renders the DateTime as a BSON document
214func (t DateTime) MarshalBSON() ([]byte, error) {
215return bson.Marshal(bson.M{"data": t})
216}
217
218// UnmarshalBSON reads the DateTime from a BSON document
219func (t *DateTime) UnmarshalBSON(data []byte) error {
220var obj struct {
221Data DateTime
222}
223
224if err := bson.Unmarshal(data, &obj); err != nil {
225return err
226}
227
228*t = obj.Data
229
230return nil
231}
232
233// MarshalBSONValue is an interface implemented by types that can marshal themselves
234// into a BSON document represented as bytes. The bytes returned must be a valid
235// BSON document if the error is nil.
236// Marshals a DateTime as a bsontype.DateTime, an int64 representing
237// milliseconds since epoch.
238func (t DateTime) MarshalBSONValue() (bsontype.Type, []byte, error) {
239// UnixNano cannot be used directly, the result of calling UnixNano on the zero
240// Time is undefined. Thats why we use time.Nanosecond() instead.
241
242tNorm := NormalizeTimeForMarshal(time.Time(t))
243i64 := tNorm.Unix()*1000 + int64(tNorm.Nanosecond())/1e6
244
245buf := make([]byte, 8)
246binary.LittleEndian.PutUint64(buf, uint64(i64))
247
248return bsontype.DateTime, buf, nil
249}
250
251// UnmarshalBSONValue is an interface implemented by types that can unmarshal a
252// BSON value representation of themselves. The BSON bytes and type can be
253// assumed to be valid. UnmarshalBSONValue must copy the BSON value bytes if it
254// wishes to retain the data after returning.
255func (t *DateTime) UnmarshalBSONValue(tpe bsontype.Type, data []byte) error {
256if tpe == bsontype.Null {
257*t = DateTime{}
258return nil
259}
260
261if len(data) != 8 {
262return errors.New("bson date field length not exactly 8 bytes")
263}
264
265i64 := int64(binary.LittleEndian.Uint64(data))
266// TODO: Use bsonprim.DateTime.Time() method
267*t = DateTime(time.Unix(i64/1000, i64%1000*1000000))
268
269return nil
270}
271
272// DeepCopyInto copies the receiver and writes its value into out.
273func (t *DateTime) DeepCopyInto(out *DateTime) {
274*out = *t
275}
276
277// DeepCopy copies the receiver into a new DateTime.
278func (t *DateTime) DeepCopy() *DateTime {
279if t == nil {
280return nil
281}
282out := new(DateTime)
283t.DeepCopyInto(out)
284return out
285}
286
287// GobEncode implements the gob.GobEncoder interface.
288func (t DateTime) GobEncode() ([]byte, error) {
289return t.MarshalBinary()
290}
291
292// GobDecode implements the gob.GobDecoder interface.
293func (t *DateTime) GobDecode(data []byte) error {
294return t.UnmarshalBinary(data)
295}
296
297// MarshalBinary implements the encoding.BinaryMarshaler interface.
298func (t DateTime) MarshalBinary() ([]byte, error) {
299return NormalizeTimeForMarshal(time.Time(t)).MarshalBinary()
300}
301
302// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.
303func (t *DateTime) UnmarshalBinary(data []byte) error {
304var original time.Time
305
306err := original.UnmarshalBinary(data)
307if err != nil {
308return err
309}
310
311*t = DateTime(original)
312
313return nil
314}
315
316// Equal checks if two DateTime instances are equal using time.Time's Equal method
317func (t DateTime) Equal(t2 DateTime) bool {
318return time.Time(t).Equal(time.Time(t2))
319}
320