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  }