github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/dm/pkg/utils/time.go (about)

     1  // Copyright 2021 PingCAP, Inc.
     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  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package utils
    15  
    16  import (
    17  	"strings"
    18  	"time"
    19  
    20  	"github.com/pingcap/tidb/pkg/types"
    21  	"github.com/pingcap/tidb/pkg/util/dbutil"
    22  	"github.com/pingcap/tiflow/dm/pkg/terror"
    23  )
    24  
    25  const (
    26  	StartTimeFormat  = "2006-01-02 15:04:05"
    27  	StartTimeFormat2 = "2006-01-02T15:04:05"
    28  )
    29  
    30  // ParseTimeZone parse the time zone location by name or offset
    31  //
    32  // NOTE: we don't support the "SYSTEM" or "Local" time_zone.
    33  func ParseTimeZone(s string) (*time.Location, error) {
    34  	if s == "SYSTEM" || s == "Local" {
    35  		return nil, terror.ErrConfigInvalidTimezone.New("'SYSTEM' or 'Local' time_zone is not supported")
    36  	}
    37  
    38  	loc, err := time.LoadLocation(s)
    39  	if err == nil {
    40  		return loc, nil
    41  	}
    42  
    43  	// The value can be given as a string indicating an offset from UTC, such as '+10:00' or '-6:00'.
    44  	// The time zone's value should in [-12:59,+14:00].
    45  	// See: https://dev.mysql.com/doc/refman/8.0/en/time-zone-support.html#time-zone-variables
    46  	if strings.HasPrefix(s, "+") || strings.HasPrefix(s, "-") {
    47  		d, _, err := types.ParseDuration(types.DefaultStmtNoWarningContext, s[1:], 0)
    48  		if err == nil {
    49  			if s[0] == '-' {
    50  				if d.Duration > 12*time.Hour+59*time.Minute {
    51  					return nil, terror.ErrConfigInvalidTimezone.Generate(s)
    52  				}
    53  			} else {
    54  				if d.Duration > 14*time.Hour {
    55  					return nil, terror.ErrConfigInvalidTimezone.Generate(s)
    56  				}
    57  			}
    58  
    59  			ofst := int(d.Duration / time.Second)
    60  			if s[0] == '-' {
    61  				ofst = -ofst
    62  			}
    63  			name := dbutil.FormatTimeZoneOffset(d.Duration)
    64  			return time.FixedZone(name, ofst), nil
    65  		}
    66  	}
    67  
    68  	return nil, terror.ErrConfigInvalidTimezone.Generate(s)
    69  }
    70  
    71  // ParseStartTime parses start-time of task-start and validation-start in local location.
    72  func ParseStartTime(timeStr string) (time.Time, error) {
    73  	return ParseStartTimeInLoc(timeStr, time.Local)
    74  }
    75  
    76  // ParseStartTimeInLoc parses start-time of task-start and validation-start.
    77  func ParseStartTimeInLoc(timeStr string, loc *time.Location) (time.Time, error) {
    78  	t, err := time.ParseInLocation(StartTimeFormat, timeStr, loc)
    79  	if err != nil {
    80  		return time.ParseInLocation(StartTimeFormat2, timeStr, loc)
    81  	}
    82  	return t, nil
    83  }