storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/pkg/s3select/sql/timestampfuncs.go (about) 1 /* 2 * MinIO Cloud Storage, (C) 2019 MinIO, Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package sql 18 19 import ( 20 "time" 21 ) 22 23 const ( 24 layoutYear = "2006T" 25 layoutMonth = "2006-01T" 26 layoutDay = "2006-01-02T" 27 layoutMinute = "2006-01-02T15:04Z07:00" 28 layoutSecond = "2006-01-02T15:04:05Z07:00" 29 layoutNanosecond = "2006-01-02T15:04:05.999999999Z07:00" 30 ) 31 32 var ( 33 tformats = []string{ 34 layoutYear, 35 layoutMonth, 36 layoutDay, 37 layoutMinute, 38 layoutSecond, 39 layoutNanosecond, 40 } 41 ) 42 43 func parseSQLTimestamp(s string) (t time.Time, err error) { 44 for _, f := range tformats { 45 t, err = time.Parse(f, s) 46 if err == nil { 47 break 48 } 49 } 50 return 51 } 52 53 // FormatSQLTimestamp - returns the a string representation of the 54 // timestamp as used in S3 Select 55 func FormatSQLTimestamp(t time.Time) string { 56 _, zoneOffset := t.Zone() 57 hasZone := zoneOffset != 0 58 hasFracSecond := t.Nanosecond() != 0 59 hasSecond := t.Second() != 0 60 hasTime := t.Hour() != 0 || t.Minute() != 0 61 hasDay := t.Day() != 1 62 hasMonth := t.Month() != 1 63 64 switch { 65 case hasFracSecond: 66 return t.Format(layoutNanosecond) 67 case hasSecond: 68 return t.Format(layoutSecond) 69 case hasTime || hasZone: 70 return t.Format(layoutMinute) 71 case hasDay: 72 return t.Format(layoutDay) 73 case hasMonth: 74 return t.Format(layoutMonth) 75 default: 76 return t.Format(layoutYear) 77 } 78 } 79 80 const ( 81 timePartYear = "YEAR" 82 timePartMonth = "MONTH" 83 timePartDay = "DAY" 84 timePartHour = "HOUR" 85 timePartMinute = "MINUTE" 86 timePartSecond = "SECOND" 87 timePartTimezoneHour = "TIMEZONE_HOUR" 88 timePartTimezoneMinute = "TIMEZONE_MINUTE" 89 ) 90 91 func extract(what string, t time.Time) (v *Value, err error) { 92 switch what { 93 case timePartYear: 94 return FromInt(int64(t.Year())), nil 95 case timePartMonth: 96 return FromInt(int64(t.Month())), nil 97 case timePartDay: 98 return FromInt(int64(t.Day())), nil 99 case timePartHour: 100 return FromInt(int64(t.Hour())), nil 101 case timePartMinute: 102 return FromInt(int64(t.Minute())), nil 103 case timePartSecond: 104 return FromInt(int64(t.Second())), nil 105 case timePartTimezoneHour: 106 _, zoneOffset := t.Zone() 107 return FromInt(int64(zoneOffset / 3600)), nil 108 case timePartTimezoneMinute: 109 _, zoneOffset := t.Zone() 110 return FromInt(int64((zoneOffset % 3600) / 60)), nil 111 default: 112 // This does not happen 113 return nil, errNotImplemented 114 } 115 } 116 117 func dateAdd(timePart string, qty float64, t time.Time) (*Value, error) { 118 var duration time.Duration 119 switch timePart { 120 case timePartYear: 121 return FromTimestamp(t.AddDate(int(qty), 0, 0)), nil 122 case timePartMonth: 123 return FromTimestamp(t.AddDate(0, int(qty), 0)), nil 124 case timePartDay: 125 return FromTimestamp(t.AddDate(0, 0, int(qty))), nil 126 case timePartHour: 127 duration = time.Duration(qty) * time.Hour 128 case timePartMinute: 129 duration = time.Duration(qty) * time.Minute 130 case timePartSecond: 131 duration = time.Duration(qty) * time.Second 132 default: 133 return nil, errNotImplemented 134 } 135 return FromTimestamp(t.Add(duration)), nil 136 } 137 138 // dateDiff computes the difference between two times in terms of the 139 // `timePart` which can be years, months, days, hours, minutes or 140 // seconds. For difference in years, months or days, the time part, 141 // including timezone is ignored. 142 func dateDiff(timePart string, ts1, ts2 time.Time) (*Value, error) { 143 if ts2.Before(ts1) { 144 v, err := dateDiff(timePart, ts2, ts1) 145 if err == nil { 146 v.negate() 147 } 148 return v, err 149 } 150 151 duration := ts2.Sub(ts1) 152 y1, m1, d1 := ts1.Date() 153 y2, m2, d2 := ts2.Date() 154 155 switch timePart { 156 case timePartYear: 157 dy := int64(y2 - y1) 158 if m2 > m1 || (m2 == m1 && d2 >= d1) { 159 return FromInt(dy), nil 160 } 161 return FromInt(dy - 1), nil 162 case timePartMonth: 163 m1 += time.Month(12 * y1) 164 m2 += time.Month(12 * y2) 165 166 return FromInt(int64(m2 - m1)), nil 167 case timePartDay: 168 return FromInt(int64(duration / (24 * time.Hour))), nil 169 case timePartHour: 170 hours := duration / time.Hour 171 return FromInt(int64(hours)), nil 172 case timePartMinute: 173 minutes := duration / time.Minute 174 return FromInt(int64(minutes)), nil 175 case timePartSecond: 176 seconds := duration / time.Second 177 return FromInt(int64(seconds)), nil 178 default: 179 180 } 181 return nil, errNotImplemented 182 }