func ParseDuration(sc *stmtctx.StatementContext, str string, fsp int) (Duration, error) {
	var (
		day, hour, minute, second int
		err                       error
		sign                      = 0
		dayExists                 = false
		origStr                   = str
	)
	fsp, err = CheckFsp(fsp)
	if err != nil {
		return ZeroDuration, errors.Trace(err)
	}
	if len(str) == 0 {
		return ZeroDuration, nil
	} else if str[0] == '-' {
		str = str[1:]
		sign = -1
	}
	if n := strings.IndexByte(str, ' '); n >= 0 {
		if day, err = strconv.Atoi(str[:n]); err == nil {
			dayExists = true
		}
		str = str[n+1:]
	}
	var (
		integeralPart = str
		fracPart      int
		overflow      bool
	)
	if n := strings.IndexByte(str, '.'); n >= 0 {
		fracStr := str[n+1:]
		fracPart, overflow, err = ParseFrac(fracStr, fsp)
		if err != nil {
			return ZeroDuration, errors.Trace(err)
		}
		integeralPart = str[0:n]
	}
	seps := strings.Split(integeralPart, ":")
	switch len(seps) {
	case 1:
		if dayExists {
			hour, err = strconv.Atoi(seps[0])
		} else {
			switch len(integeralPart) {
			case 7:  
				_, err = fmt.Sscanf(integeralPart, "%3d%2d%2d", &hour, &minute, &second)
			case 6:  
				_, err = fmt.Sscanf(integeralPart, "%2d%2d%2d", &hour, &minute, &second)
			case 5:  
				_, err = fmt.Sscanf(integeralPart, "%1d%2d%2d", &hour, &minute, &second)
			case 4:  
				_, err = fmt.Sscanf(integeralPart, "%2d%2d", &minute, &second)
			case 3:  
				_, err = fmt.Sscanf(integeralPart, "%1d%2d", &minute, &second)
			case 2:  
				_, err = fmt.Sscanf(integeralPart, "%2d", &second)
			case 1:  
				_, err = fmt.Sscanf(integeralPart, "%1d", &second)
			default:  
				t, err1 := ParseDatetime(sc, str)
				if err1 != nil {
					return ZeroDuration, ErrTruncatedWrongVal.GenWithStackByArgs("time", origStr)
				}
				var dur Duration
				dur, err1 = t.ConvertToDuration()
				if err1 != nil {
					return ZeroDuration, errors.Trace(err)
				}
				return dur.RoundFrac(fsp)
			}
		}
	case 2:
		_, err = fmt.Sscanf(integeralPart, "%2d:%2d", &hour, &minute)
	case 3:
		if len(seps[0]) == 3 {
			_, err = fmt.Sscanf(integeralPart, "%3d:%2d:%2d", &hour, &minute, &second)
		} else {
			_, err = fmt.Sscanf(integeralPart, "%2d:%2d:%2d", &hour, &minute, &second)
		}
	default:
		return ZeroDuration, ErrTruncatedWrongVal.GenWithStackByArgs("time", origStr)
	}
	if err != nil {
		return ZeroDuration, errors.Trace(err)
	}
	if overflow {
		second++
		fracPart = 0
	}
	if minute >= 60 || second > 60 || (!overflow && second == 60) {
		return ZeroDuration, ErrTruncatedWrongVal.GenWithStackByArgs("time", origStr)
	}
	d := gotime.Duration(day*24*3600+hour*3600+minute*60+second)*gotime.Second + gotime.Duration(fracPart)*gotime.Microsecond
	if sign == -1 {
		d = -d
	}
	d, err = TruncateOverflowMySQLTime(d)
	return Duration{Duration: d, Fsp: fsp}, errors.Trace(err)
}
ParseDuration parses the time form a formatted string with a fractional seconds part,
returns the duration type Time value.
See http://dev.mysql.com/doc/refman/5.7/en/fractional-seconds.html
package types
import (
	"bytes"
	"fmt"
	"math"
	"regexp"
	"strconv"
	"strings"
	gotime "time"
	"unicode"
	"github.com/pingcap/errors"
	"github.com/pingcap/parser/mysql"
	"github.com/pingcap/parser/terror"
	"github.com/pingcap/tidb/sessionctx/stmtctx"
	log "github.com/sirupsen/logrus"
)
var (
	ErrInvalidTimeFormat      = terror.ClassTypes.New(mysql.ErrTruncatedWrongValue, "invalid time format: '%v'")
	ErrInvalidYearFormat      = errors.New("invalid year format")
	ErrInvalidYear            = errors.New("invalid year")
	ErrZeroDate               = errors.New("datetime zero in date")
	ErrIncorrectDatetimeValue = terror.ClassTypes.New(mysql.ErrTruncatedWrongValue, "Incorrect datetime value: '%s'")
	ErrTruncatedWrongValue    = terror.ClassTypes.New(mysql.ErrTruncatedWrongValue, mysql.MySQLErrName[mysql.ErrTruncatedWrongValue])
)
const (
	DateFormat = "2006-01-02"
	TimeFormat = "2006-01-02 15:04:05"
	TimeFSPFormat = "2006-01-02 15:04:05.000000"
)
const (
	MinYear int16 = 1901
	MaxYear int16 = 2155
	MaxDuration int64 = 838*10000 + 59*100 + 59
	MinTime = -gotime.Duration(838*3600+59*60+59) * gotime.Second
	MaxTime = gotime.Duration(838*3600+59*60+59) * gotime.Second
	ZeroDatetimeStr = "0000-00-00 00:00:00"
	ZeroDateStr = "0000-00-00"
	TimeMaxHour = 838
	TimeMaxMinute = 59
	TimeMaxSecond = 59
	TimeMaxValue = TimeMaxHour*10000 + TimeMaxMinute*100 + TimeMaxSecond
	TimeMaxValueSeconds = TimeMaxHour*3600 + TimeMaxMinute*60 + TimeMaxSecond
)
var (
	ZeroDuration = Duration{Duration: gotime.Duration(0), Fsp: DefaultFsp}
	ZeroTime = MysqlTime{}
	ZeroDatetime = Time{
		Time: ZeroTime,
		Type: mysql.TypeDatetime,
		Fsp:  DefaultFsp,
	}
	ZeroTimestamp = Time{
		Time: ZeroTime,
		Type: mysql.TypeTimestamp,
		Fsp:  DefaultFsp,
	}
	ZeroDate = Time{
		Time: ZeroTime,
		Type: mysql.TypeDate,
		Fsp:  DefaultFsp,
	}
)
var (
	MinDatetime = FromDate(1000, 1, 1, 0, 0, 0, 0)
	MaxDatetime = FromDate(9999, 12, 31, 23, 59, 59, 999999)
	BoundTimezone = gotime.UTC
	MinTimestamp = Time{
		Time: FromDate(1970, 1, 1, 0, 0, 1, 0),
		Type: mysql.TypeTimestamp,
		Fsp:  DefaultFsp,
	}
	MaxTimestamp = Time{
		Time: FromDate(2038, 1, 19, 3, 14, 7, 999999),
		Type: mysql.TypeTimestamp,
		Fsp:  DefaultFsp,
	}
	WeekdayNames = []string{
		"Monday",
		"Tuesday",
		"Wednesday",
		"Thursday",
		"Friday",
		"Saturday",
		"Sunday",
	}
	MonthNames = []string{
		"January", "February",
		"March", "April",
		"May", "June",
		"July", "August",
		"September", "October",
		"November", "December",
	}
)
func FromGoTime(t gotime.Time) MysqlTime {
	year, month, day := t.Date()
	hour, minute, second := t.Clock()
	microsecond := (t.Nanosecond() + 500) / 1000
	return FromDate(year, int(month), day, hour, minute, second, microsecond)
}
func FromDate(year int, month int, day int, hour int, minute int, second int, microsecond int) MysqlTime {
	return MysqlTime{
		uint16(year),
		uint8(month),
		uint8(day),
		hour,
		uint8(minute),
		uint8(second),
		uint32(microsecond),
	}
}
func (t Time) Clock() (hour int, minute int, second int) {
	return t.Time.Hour(), t.Time.Minute(), t.Time.Second()
}
type Time struct {
	Time MysqlTime
	Type uint8
	Fsp int
}
func MaxMySQLTime(fsp int) Time {
	return Time{Time: FromDate(0, 0, 0, TimeMaxHour, TimeMaxMinute, TimeMaxSecond, 0), Type: mysql.TypeDuration, Fsp: fsp}
}
func CurrentTime(tp uint8) Time {
	return Time{Time: FromGoTime(gotime.Now()), Type: tp, Fsp: 0}
}
func (t *Time) ConvertTimeZone(from, to *gotime.Location) error {
	if !t.IsZero() {
		raw, err := t.Time.GoTime(from)
		if err != nil {
			return errors.Trace(err)
		}
		converted := raw.In(to)
		t.Time = FromGoTime(converted)
	}
	return nil
}
func (t Time) String() string {
	if t.Type == mysql.TypeDate {
		str, err := t.DateFormat("%Y-%m-%d")
		terror.Log(errors.Trace(err))
		return str
	}
	str, err := t.DateFormat("%Y-%m-%d %H:%i:%s")
	terror.Log(errors.Trace(err))
	if t.Fsp > 0 {
		tmp := fmt.Sprintf(".%06d", t.Time.Microsecond())
		str = str + tmp[:1+t.Fsp]
	}
	return str
}
func (t Time) IsZero() bool {
	return compareTime(t.Time, ZeroTime) == 0
}
func (t Time) InvalidZero() bool {
	return t.Time.Month() == 0 || t.Time.Day() == 0
}
const numberFormat = "%Y%m%d%H%i%s"
const dateFormat = "%Y%m%d"
func (t Time) ToNumber() *MyDecimal {
	if t.IsZero() {
		return &MyDecimal{}
	}
	var tfStr string
	if t.Type == mysql.TypeDate {
		tfStr = dateFormat
	} else {
		tfStr = numberFormat
	}
	s, err := t.DateFormat(tfStr)
	if err != nil {
		log.Error("Fatal: never happen because we've control the format!")
	}
	if t.Fsp > 0 {
		s1 := fmt.Sprintf("%s.%06d", s, t.Time.Microsecond())
		s = s1[:len(s)+t.Fsp+1]
	}
	dec := new(MyDecimal)
	err = dec.FromString([]byte(s))
	terror.Log(errors.Trace(err))
	return dec
}
func (t Time) Convert(sc *stmtctx.StatementContext, tp uint8) (Time, error) {
	if t.Type == tp || t.IsZero() {
		return Time{Time: t.Time, Type: tp, Fsp: t.Fsp}, nil
	}
	t1 := Time{Time: t.Time, Type: tp, Fsp: t.Fsp}
	err := t1.check(sc)
	return t1, errors.Trace(err)
}
func (t Time) ConvertToDuration() (Duration, error) {
	if t.IsZero() {
		return ZeroDuration, nil
	}
	hour, minute, second := t.Clock()
	frac := t.Time.Microsecond() * 1000
	d := gotime.Duration(hour*3600+minute*60+second)*gotime.Second + gotime.Duration(frac)
	return Duration{Duration: d, Fsp: t.Fsp}, nil
}
func (t Time) Compare(o Time) int {
	return compareTime(t.Time, o.Time)
}
func compareTime(a, b MysqlTime) int {
	ta := datetimeToUint64(a)
	tb := datetimeToUint64(b)
	switch {
	case ta < tb:
		return -1
	case ta > tb:
		return 1
	}
	switch {
	case a.Microsecond() < b.Microsecond():
		return -1
	case a.Microsecond() > b.Microsecond():
		return 1
	}
	return 0
}
func (t Time) CompareString(sc *stmtctx.StatementContext, str string) (int, error) {
	o, err := ParseTime(sc, str, t.Type, MaxFsp)
	if err != nil {
		return 0, errors.Trace(err)
	}
	return t.Compare(o), nil
}
func roundTime(t gotime.Time, fsp int) gotime.Time {
	d := gotime.Duration(math.Pow10(9 - fsp))
	return t.Round(d)
}
func (t Time) RoundFrac(sc *stmtctx.StatementContext, fsp int) (Time, error) {
	if t.Type == mysql.TypeDate || t.IsZero() {
		return t, nil
	}
	fsp, err := CheckFsp(fsp)
	if err != nil {
		return t, errors.Trace(err)
	}
	if fsp == t.Fsp {
		return t, nil
	}
	var nt MysqlTime
	if t1, err := t.Time.GoTime(sc.TimeZone); err == nil {
		t1 = roundTime(t1, fsp)
		nt = FromGoTime(t1)
	} else {
		hour, minute, second, microsecond := t.Time.Hour(), t.Time.Minute(), t.Time.Second(), t.Time.Microsecond()
		t1 := gotime.Date(1, 1, 1, hour, minute, second, microsecond*1000, gotime.Local)
		t2 := roundTime(t1, fsp)
		hour, minute, second = t2.Clock()
		microsecond = t2.Nanosecond() / 1000
		if t2.Day()-1 > 0 {
			return t, errors.Trace(ErrInvalidTimeFormat.GenWithStackByArgs(t.String()))
		}
		nt = FromDate(t.Time.Year(), t.Time.Month(), t.Time.Day(), hour, minute, second, microsecond)
	}
	return Time{Time: nt, Type: t.Type, Fsp: fsp}, nil
}
func GetFsp(s string) (fsp int) {
	fsp = len(s) - strings.LastIndex(s, ".") - 1
	if fsp == len(s) {
		fsp = 0
	} else if fsp > 6 {
		fsp = 6
	}
	return
}
func RoundFrac(t gotime.Time, fsp int) (gotime.Time, error) {
	_, err := CheckFsp(fsp)
	if err != nil {
		return t, errors.Trace(err)
	}
	return t.Round(gotime.Duration(math.Pow10(9-fsp)) * gotime.Nanosecond), nil
}
func (t Time) ToPackedUint() (uint64, error) {
	tm := t.Time
	if t.IsZero() {
		return 0, nil
	}
	year, month, day := tm.Year(), tm.Month(), tm.Day()
	hour, minute, sec := tm.Hour(), tm.Minute(), tm.Second()
	ymd := uint64(((year*13 + month) << 5) | day)
	hms := uint64(hour<<12 | minute<<6 | sec)
	micro := uint64(tm.Microsecond())
	return ((ymd<<17 | hms) << 24) | micro, nil
}
func (t *Time) FromPackedUint(packed uint64) error {
	if packed == 0 {
		t.Time = ZeroTime
		return nil
	}
	ymdhms := packed >> 24
	ymd := ymdhms >> 17
	day := int(ymd & (1<<5 - 1))
	ym := ymd >> 5
	month := int(ym % 13)
	year := int(ym / 13)
	hms := ymdhms & (1<<17 - 1)
	second := int(hms & (1<<6 - 1))
	minute := int((hms >> 6) & (1<<6 - 1))
	hour := int(hms >> 12)
	microsec := int(packed % (1 << 24))
	t.Time = FromDate(year, month, day, hour, minute, second, microsec)
	return nil
}
func (t *Time) check(sc *stmtctx.StatementContext) error {
	allowZeroInDate := false
	if sc != nil {
		allowZeroInDate = sc.IgnoreZeroInDate
	}
	var err error
	switch t.Type {
	case mysql.TypeTimestamp:
		err = checkTimestampType(sc, t.Time)
	case mysql.TypeDatetime:
		err = checkDatetimeType(t.Time, allowZeroInDate)
	case mysql.TypeDate:
		err = checkDateType(t.Time, allowZeroInDate)
	}
	return errors.Trace(err)
}
func (t *Time) Check(sc *stmtctx.StatementContext) error {
	return t.check(sc)
}
func (t *Time) Sub(sc *stmtctx.StatementContext, t1 *Time) Duration {
	var duration gotime.Duration
	if t.Type == mysql.TypeTimestamp && t1.Type == mysql.TypeTimestamp {
		a, err := t.Time.GoTime(sc.TimeZone)
		terror.Log(errors.Trace(err))
		b, err := t1.Time.GoTime(sc.TimeZone)
		terror.Log(errors.Trace(err))
		duration = a.Sub(b)
	} else {
		seconds, microseconds, neg := calcTimeDiff(t.Time, t1.Time, 1)
		duration = gotime.Duration(seconds*1e9 + microseconds*1e3)
		if neg {
			duration = -duration
		}
	}
	fsp := t.Fsp
	if fsp < t1.Fsp {
		fsp = t1.Fsp
	}
	return Duration{
		Duration: duration,
		Fsp:      fsp,
	}
}
func (t *Time) Add(sc *stmtctx.StatementContext, d Duration) (Time, error) {
	sign, hh, mm, ss, micro := splitDuration(d.Duration)
	seconds, microseconds, _ := calcTimeDiff(t.Time, FromDate(0, 0, 0, hh, mm, ss, micro), -sign)
	days := seconds / secondsIn24Hour
	year, month, day := getDateFromDaynr(uint(days))
	var tm MysqlTime
	tm.year, tm.month, tm.day = uint16(year), uint8(month), uint8(day)
	calcTimeFromSec(&tm, seconds%secondsIn24Hour, microseconds)
	if t.Type == mysql.TypeDate {
		tm.hour = 0
		tm.minute = 0
		tm.second = 0
		tm.microsecond = 0
	}
	fsp := t.Fsp
	if d.Fsp > fsp {
		fsp = d.Fsp
	}
	ret := Time{
		Time: tm,
		Type: t.Type,
		Fsp:  fsp,
	}
	return ret, ret.Check(sc)
}
func TimestampDiff(unit string, t1 Time, t2 Time) int64 {
	return timestampDiff(unit, t1.Time, t2.Time)
}
func ParseDateFormat(format string) []string {
	format = strings.TrimSpace(format)
	start := 0
	var seps = make([]string, 0)
	for i := 0; i < len(format); i++ {
		if i == 0 || i == len(format)-1 {
			if !unicode.IsNumber(rune(format[i])) {
				return nil
			}
			continue
		}
		if !unicode.IsNumber(rune(format[i])) {
			if !unicode.IsNumber(rune(format[i-1])) {
				return nil
			}
			seps = append(seps, format[start:i])
			start = i + 1
		}
	}
	seps = append(seps, format[start:])
	return seps
}
func splitDateTime(format string) (seps []string, fracStr string) {
	if i := strings.LastIndex(format, "."); i > 0 {
		fracStr = strings.TrimSpace(format[i+1:])
		format = format[:i]
	}
	seps = ParseDateFormat(format)
	return
}
func parseDatetime(sc *stmtctx.StatementContext, str string, fsp int, isFloat bool) (Time, error) {
	var (
		year, month, day, hour, minute, second int
		fracStr                                string
		hhmmss                                 bool
		err                                    error
	)
	seps, fracStr := splitDateTime(str)
	var truncatedOrIncorrect bool
	switch len(seps) {
	case 1:
		l := len(seps[0])
		switch l {
		case 14:  
			_, err = fmt.Sscanf(seps[0], "%4d%2d%2d%2d%2d%2d", &year, &month, &day, &hour, &minute, &second)
			hhmmss = true
		case 12:  
			_, err = fmt.Sscanf(seps[0], "%2d%2d%2d%2d%2d%2d", &year, &month, &day, &hour, &minute, &second)
			year = adjustYear(year)
			hhmmss = true
		case 11:  
			_, err = fmt.Sscanf(seps[0], "%2d%2d%2d%2d%2d%1d", &year, &month, &day, &hour, &minute, &second)
			year = adjustYear(year)
			hhmmss = true
		case 10:  
			_, err = fmt.Sscanf(seps[0], "%2d%2d%2d%2d%2d", &year, &month, &day, &hour, &minute)
			year = adjustYear(year)
		case 9:  
			_, err = fmt.Sscanf(seps[0], "%2d%2d%2d%2d%1d", &year, &month, &day, &hour, &minute)
			year = adjustYear(year)
		case 8:  
			_, err = fmt.Sscanf(seps[0], "%4d%2d%2d", &year, &month, &day)
		case 6, 5:
			_, err = fmt.Sscanf(seps[0], "%2d%2d%2d", &year, &month, &day)
			year = adjustYear(year)
		default:
			return ZeroDatetime, errors.Trace(ErrInvalidTimeFormat.GenWithStackByArgs(str))
		}
		if l == 5 || l == 6 || l == 8 {
			if isFloat {
			} else {
				switch len(fracStr) {
				case 0:
				case 1, 2:
					_, err = fmt.Sscanf(fracStr, "%2d ", &hour)
				case 3, 4:
					_, err = fmt.Sscanf(fracStr, "%2d%2d ", &hour, &minute)
				default:
					_, err = fmt.Sscanf(fracStr, "%2d%2d%2d ", &hour, &minute, &second)
				}
				truncatedOrIncorrect = err != nil
			}
		}
		if l == 9 || l == 10 {
			if len(fracStr) == 0 {
				second = 0
			} else {
				_, err = fmt.Sscanf(fracStr, "%2d ", &second)
			}
			truncatedOrIncorrect = err != nil
		}
		if truncatedOrIncorrect && sc != nil {
			sc.AppendWarning(ErrTruncatedWrongValue.GenWithStackByArgs("datetime", str))
			err = nil
		}
	case 3:
		err = scanTimeArgs(seps, &year, &month, &day)
	case 4:
		err = scanTimeArgs(seps, &year, &month, &day, &hour)
	case 5:
		err = scanTimeArgs(seps, &year, &month, &day, &hour, &minute)
	case 6:
		err = scanTimeArgs(seps, &year, &month, &day, &hour, &minute, &second)
		hhmmss = true
	default:
		return ZeroDatetime, errors.Trace(ErrIncorrectDatetimeValue.GenWithStackByArgs(str))
	}
	if err != nil {
		return ZeroDatetime, errors.Trace(err)
	}
	if len(seps[0]) == 2 {
		if year == 0 && month == 0 && day == 0 && hour == 0 && minute == 0 && second == 0 && fracStr == "" {
		} else {
			year = adjustYear(year)
		}
	}
	var microsecond int
	var overflow bool
	if hhmmss {
		microsecond, overflow, err = ParseFrac(fracStr, fsp)
		if err != nil {
			return ZeroDatetime, errors.Trace(err)
		}
	}
	tmp := FromDate(year, month, day, hour, minute, second, microsecond)
	if overflow {
		t1, err := tmp.GoTime(gotime.Local)
		if err != nil {
			return ZeroDatetime, errors.Trace(err)
		}
		tmp = FromGoTime(t1.Add(gotime.Second))
	}
	nt := Time{
		Time: tmp,
		Type: mysql.TypeDatetime,
		Fsp:  fsp}
	return nt, nil
}
func scanTimeArgs(seps []string, args ...*int) error {
	if len(seps) != len(args) {
		return errors.Trace(ErrInvalidTimeFormat.GenWithStackByArgs(seps))
	}
	var err error
	for i, s := range seps {
		*args[i], err = strconv.Atoi(s)
		if err != nil {
			return errors.Trace(err)
		}
	}
	return nil
}
func ParseYear(str string) (int16, error) {
	v, err := strconv.ParseInt(str, 10, 16)
	if err != nil {
		return 0, errors.Trace(err)
	}
	y := int16(v)
	if len(str) == 4 {
	} else if len(str) == 2 || len(str) == 1 {
		y = int16(adjustYear(int(y)))
	} else {
		return 0, errors.Trace(ErrInvalidYearFormat)
	}
	if y < MinYear || y > MaxYear {
		return 0, errors.Trace(ErrInvalidYearFormat)
	}
	return y, nil
}
func adjustYear(y int) int {
	if y >= 0 && y <= 69 {
		y = 2000 + y
	} else if y >= 70 && y <= 99 {
		y = 1900 + y
	}
	return y
}
func AdjustYear(y int64, fromStr bool) (int64, error) {
	if y == 0 && !fromStr {
		return y, nil
	}
	y = int64(adjustYear(int(y)))
	if y < int64(MinYear) || y > int64(MaxYear) {
		return 0, errors.Trace(ErrInvalidYear)
	}
	return y, nil
}
type Duration struct {
	gotime.Duration
	Fsp int
}
func (d Duration) Add(v Duration) (Duration, error) {
	if &v == nil {
		return d, nil
	}
	dsum, err := AddInt64(int64(d.Duration), int64(v.Duration))
	if err != nil {
		return Duration{}, errors.Trace(err)
	}
	if d.Fsp >= v.Fsp {
		return Duration{Duration: gotime.Duration(dsum), Fsp: d.Fsp}, nil
	}
	return Duration{Duration: gotime.Duration(dsum), Fsp: v.Fsp}, nil
}
func (d Duration) Sub(v Duration) (Duration, error) {
	if &v == nil {
		return d, nil
	}
	dsum, err := SubInt64(int64(d.Duration), int64(v.Duration))
	if err != nil {
		return Duration{}, errors.Trace(err)
	}
	if d.Fsp >= v.Fsp {
		return Duration{Duration: gotime.Duration(dsum), Fsp: d.Fsp}, nil
	}
	return Duration{Duration: gotime.Duration(dsum), Fsp: v.Fsp}, nil
}
func (d Duration) String() string {
	var buf bytes.Buffer
	sign, hours, minutes, seconds, fraction := splitDuration(d.Duration)
	if sign < 0 {
		buf.WriteByte('-')
	}
	fmt.Fprintf(&buf, "%02d:%02d:%02d", hours, minutes, seconds)
	if d.Fsp > 0 {
		buf.WriteString(".")
		buf.WriteString(d.formatFrac(fraction))
	}
	p := buf.String()
	return p
}
func (d Duration) formatFrac(frac int) string {
	s := fmt.Sprintf("%06d", frac)
	return s[0:d.Fsp]
}
func (d Duration) ToNumber() *MyDecimal {
	sign, hours, minutes, seconds, fraction := splitDuration(d.Duration)
	var (
		s       string
		signStr string
	)
	if sign < 0 {
		signStr = "-"
	}
	if d.Fsp == 0 {
		s = fmt.Sprintf("%s%02d%02d%02d", signStr, hours, minutes, seconds)
	} else {
		s = fmt.Sprintf("%s%02d%02d%02d.%s", signStr, hours, minutes, seconds, d.formatFrac(fraction))
	}
	dec := new(MyDecimal)
	err := dec.FromString([]byte(s))
	terror.Log(errors.Trace(err))
	return dec
}
func (d Duration) ConvertToTime(sc *stmtctx.StatementContext, tp uint8) (Time, error) {
	year, month, day := gotime.Now().In(sc.TimeZone).Date()
	sign, hour, minute, second, frac := splitDuration(d.Duration)
	datePart := FromDate(year, int(month), day, 0, 0, 0, 0)
	timePart := FromDate(0, 0, 0, hour, minute, second, frac)
	mixDateAndTime(&datePart, &timePart, sign < 0)
	t := Time{
		Time: datePart,
		Type: mysql.TypeDatetime,
		Fsp:  d.Fsp,
	}
	return t.Convert(sc, tp)
}
func (d Duration) RoundFrac(fsp int) (Duration, error) {
	fsp, err := CheckFsp(fsp)
	if err != nil {
		return d, errors.Trace(err)
	}
	if fsp == d.Fsp {
		return d, nil
	}
	n := gotime.Date(0, 0, 0, 0, 0, 0, 0, gotime.Local)
	nd := n.Add(d.Duration).Round(gotime.Duration(math.Pow10(9-fsp)) * gotime.Nanosecond).Sub(n)
	return Duration{Duration: nd, Fsp: fsp}, nil
}
func (d Duration) Compare(o Duration) int {
	if d.Duration > o.Duration {
		return 1
	} else if d.Duration == o.Duration {
		return 0
	} else {
		return -1
	}
}
func (d Duration) CompareString(sc *stmtctx.StatementContext, str string) (int, error) {
	o, err := ParseDuration(sc, str, MaxFsp)
	if err != nil {
		return 0, err
	}
	return d.Compare(o), nil
}
func (d Duration) Hour() int {
	_, hour, _, _, _ := splitDuration(d.Duration)
	return hour
}
func (d Duration) Minute() int {
	_, _, minute, _, _ := splitDuration(d.Duration)
	return minute
}
func (d Duration) Second() int {
	_, _, _, second, _ := splitDuration(d.Duration)
	return second
}
func (d Duration) MicroSecond() int {
	_, _, _, _, frac := splitDuration(d.Duration)
	return frac
}