github.com/vedadiyan/sqlparser@v1.0.0/pkg/sqlparser/parse_date.go (about)

     1  /*
     2  Copyright 2019 The Vitess Authors.
     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 sqlparser
    18  
    19  import (
    20  	"fmt"
    21  	"strconv"
    22  	"strings"
    23  	"time"
    24  
    25  	"github.com/vedadiyan/sqlparser/pkg/vterrors"
    26  	vtrpcpb "github.com/vedadiyan/sqlparser/pkg/vtrpc"
    27  )
    28  
    29  var dateFormats = []string{"2006-01-02", "06-01-02", "20060102", "060102"}
    30  var datetimeFormats = []string{"2006-01-02 15:04:05.9", "06-01-02 15:04:05.9", "20060102150405.9", "060102150405.9"}
    31  var timeWithDayFormats = []string{"15:04:05.9", "15:04", "15"}
    32  var timeWithoutDayFormats = []string{"15:04:05.9", "15:04", "150405.9", "0405", "05"}
    33  
    34  func ParseDate(in string) (t time.Time, err error) {
    35  	for _, f := range dateFormats {
    36  		t, err = time.Parse(f, in)
    37  		if err == nil {
    38  			return t, nil
    39  		}
    40  	}
    41  	return t, vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.WrongValue, "incorrect DATE value: '%s'", in)
    42  }
    43  
    44  func ParseTime(in string) (t time.Time, err error) {
    45  	// ParseTime is right now only excepting on specific
    46  	// time format and doesn't accept all formats MySQL accepts.
    47  	// Can be improved in the future as needed.
    48  	if in == "" {
    49  		return t, vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.WrongValue, "incorrect TIME value: '%s'", in)
    50  	}
    51  	start := 0
    52  	neg := in[start] == '-'
    53  	if neg {
    54  		start++
    55  	}
    56  
    57  	parts := strings.Split(in[start:], " ")
    58  	if len(parts) > 2 {
    59  		return t, vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.WrongValue, "incorrect TIME value: '%s'", in)
    60  	}
    61  	days := 0
    62  	hourMinuteSeconds := parts[0]
    63  	if len(parts) == 2 {
    64  		days, err = strconv.Atoi(parts[0])
    65  		if err != nil {
    66  			fmt.Printf("atoi failed: %+v\n", err)
    67  			return t, vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.WrongValue, "incorrect TIME value: '%s'", in)
    68  		}
    69  		if days < 0 {
    70  			// Double negative which is not allowed
    71  			return t, vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.WrongValue, "incorrect TIME value: '%s'", in)
    72  		}
    73  		if days > 34 {
    74  			return t, vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.WrongValue, "incorrect TIME value: '%s'", in)
    75  		}
    76  		for _, f := range timeWithDayFormats {
    77  			t, err = time.Parse(f, parts[1])
    78  			if err == nil {
    79  				break
    80  			}
    81  		}
    82  	} else {
    83  		for _, f := range timeWithoutDayFormats {
    84  			t, err = time.Parse(f, hourMinuteSeconds)
    85  			if err == nil {
    86  				break
    87  			}
    88  		}
    89  	}
    90  
    91  	if err != nil {
    92  		return t, vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.WrongValue, "incorrect TIME value: '%s'", in)
    93  	}
    94  
    95  	// setting the date to today's date, because t is "0000-01-01 xx:xx:xx"
    96  	now := time.Now()
    97  	year, month, day := now.Date()
    98  	if neg {
    99  		// If we have a negative time, we start with the start of today
   100  		// and substract the total duration of the parsed time.
   101  		today := time.Date(year, month, day, 0, 0, 0, 0, t.Location())
   102  		duration := time.Duration(days)*24*time.Hour +
   103  			time.Duration(t.Hour())*time.Hour +
   104  			time.Duration(t.Minute())*time.Minute +
   105  			time.Duration(t.Second())*time.Second +
   106  			time.Duration(t.Nanosecond())*time.Nanosecond
   107  		t = today.Add(-duration)
   108  	} else {
   109  		// In case of a positive time, we can take a quicker
   110  		// shortcut and add the date of today.
   111  		t = t.AddDate(year, int(month-1), day-1+days)
   112  	}
   113  	return t, nil
   114  }
   115  
   116  func ParseDateTime(in string) (t time.Time, err error) {
   117  	for _, f := range datetimeFormats {
   118  		t, err = time.Parse(f, in)
   119  		if err == nil {
   120  			return t, nil
   121  		}
   122  	}
   123  	return t, vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.WrongValue, "incorrect DATETIME value: '%s'", in)
   124  }