226 lines
4.2 KiB
Go
226 lines
4.2 KiB
Go
package mysql
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// For MySQL DATE type
|
|
type Date struct {
|
|
Year int16
|
|
Month, Day byte
|
|
}
|
|
|
|
func (dd Date) String() string {
|
|
return fmt.Sprintf("%04d-%02d-%02d", dd.Year, dd.Month, dd.Day)
|
|
}
|
|
|
|
// True if date is 0000-00-00
|
|
func (dd Date) IsZero() bool {
|
|
return dd.Day == 0 && dd.Month == 0 && dd.Year == 0
|
|
}
|
|
|
|
// Converts Date to time.Time using loc location.
|
|
// Converts MySQL zero to time.Time zero.
|
|
func (dd Date) Time(loc *time.Location) (t time.Time) {
|
|
if !dd.IsZero() {
|
|
t = time.Date(
|
|
int(dd.Year), time.Month(dd.Month), int(dd.Day),
|
|
0, 0, 0, 0,
|
|
loc,
|
|
)
|
|
}
|
|
return
|
|
}
|
|
|
|
// Converts Date to time.Time using Local location.
|
|
// Converts MySQL zero to time.Time zero.
|
|
func (dd Date) Localtime() time.Time {
|
|
return dd.Time(time.Local)
|
|
}
|
|
|
|
// Convert string date in format YYYY-MM-DD to Date.
|
|
// Leading and trailing spaces are ignored.
|
|
func ParseDate(str string) (dd Date, err error) {
|
|
str = strings.TrimSpace(str)
|
|
if str == "0000-00-00" {
|
|
return
|
|
}
|
|
var (
|
|
y, m, d int
|
|
)
|
|
if len(str) != 10 || str[4] != '-' || str[7] != '-' {
|
|
goto invalid
|
|
}
|
|
if y, err = strconv.Atoi(str[0:4]); err != nil {
|
|
return
|
|
}
|
|
if m, err = strconv.Atoi(str[5:7]); err != nil {
|
|
return
|
|
}
|
|
if m < 0 || m > 12 { // MySQL permits month == 0
|
|
goto invalid
|
|
}
|
|
if d, err = strconv.Atoi(str[8:10]); err != nil {
|
|
return
|
|
}
|
|
if d < 0 { // MySQL permits day == 0
|
|
goto invalid
|
|
}
|
|
switch m {
|
|
case 1, 3, 5, 7, 8, 10, 12:
|
|
if d > 31 {
|
|
goto invalid
|
|
}
|
|
case 4, 6, 9, 11:
|
|
if d > 30 {
|
|
goto invalid
|
|
}
|
|
case 2:
|
|
if d > 29 {
|
|
goto invalid
|
|
}
|
|
}
|
|
dd.Year = int16(y)
|
|
dd.Month = byte(m)
|
|
dd.Day = byte(d)
|
|
return
|
|
|
|
invalid:
|
|
err = errors.New("Invalid MySQL DATE string: " + str)
|
|
return
|
|
}
|
|
|
|
// Sandard MySQL datetime format
|
|
const TimeFormat = "2006-01-02 15:04:05.000000000"
|
|
|
|
// Returns t as string in MySQL format Converts time.Time zero to MySQL zero.
|
|
func TimeString(t time.Time) string {
|
|
if t.IsZero() {
|
|
return "0000-00-00 00:00:00"
|
|
}
|
|
if t.Nanosecond() == 0 {
|
|
return t.Format(TimeFormat[:19])
|
|
}
|
|
return t.Format(TimeFormat)
|
|
}
|
|
|
|
// Parses string datetime in TimeFormat using loc location.
|
|
// Converts MySQL zero to time.Time zero.
|
|
func ParseTime(str string, loc *time.Location) (t time.Time, err error) {
|
|
str = strings.TrimSpace(str)
|
|
format := TimeFormat[:19]
|
|
switch len(str) {
|
|
case 10:
|
|
if str == "0000-00-00" {
|
|
return
|
|
}
|
|
format = format[:10]
|
|
case 19:
|
|
if str == "0000-00-00 00:00:00" {
|
|
return
|
|
}
|
|
}
|
|
// Don't expect 0000-00-00 00:00:00.0+
|
|
t, err = time.ParseInLocation(format, str, loc)
|
|
return
|
|
}
|
|
|
|
// Convert time.Duration to string representation of mysql.TIME
|
|
func DurationString(d time.Duration) string {
|
|
sign := 1
|
|
if d < 0 {
|
|
sign = -1
|
|
d = -d
|
|
}
|
|
ns := int(d % 1e9)
|
|
d /= 1e9
|
|
sec := int(d % 60)
|
|
d /= 60
|
|
min := int(d % 60)
|
|
hour := int(d/60) * sign
|
|
if ns == 0 {
|
|
return fmt.Sprintf("%d:%02d:%02d", hour, min, sec)
|
|
}
|
|
return fmt.Sprintf("%d:%02d:%02d.%09d", hour, min, sec, ns)
|
|
}
|
|
|
|
// Parse duration from MySQL string format [+-]H+:MM:SS[.UUUUUUUUU].
|
|
// Leading and trailing spaces are ignored. If format is invalid returns nil.
|
|
func ParseDuration(str string) (dur time.Duration, err error) {
|
|
str = strings.TrimSpace(str)
|
|
orig := str
|
|
// Check sign
|
|
sign := int64(1)
|
|
switch str[0] {
|
|
case '-':
|
|
sign = -1
|
|
fallthrough
|
|
case '+':
|
|
str = str[1:]
|
|
}
|
|
var i, d int64
|
|
// Find houre
|
|
if nn := strings.IndexRune(str, ':'); nn != -1 {
|
|
if i, err = strconv.ParseInt(str[0:nn], 10, 64); err != nil {
|
|
return
|
|
}
|
|
d = i * 3600
|
|
str = str[nn+1:]
|
|
} else {
|
|
goto invalid
|
|
}
|
|
if len(str) != 5 && len(str) != 15 || str[2] != ':' {
|
|
goto invalid
|
|
}
|
|
if i, err = strconv.ParseInt(str[0:2], 10, 64); err != nil {
|
|
return
|
|
}
|
|
if i < 0 || i > 59 {
|
|
goto invalid
|
|
}
|
|
d += i * 60
|
|
if i, err = strconv.ParseInt(str[3:5], 10, 64); err != nil {
|
|
return
|
|
}
|
|
if i < 0 || i > 59 {
|
|
goto invalid
|
|
}
|
|
d += i
|
|
d *= 1e9
|
|
if len(str) == 15 {
|
|
if str[5] != '.' {
|
|
goto invalid
|
|
}
|
|
if i, err = strconv.ParseInt(str[6:15], 10, 64); err != nil {
|
|
return
|
|
}
|
|
d += i
|
|
}
|
|
dur = time.Duration(d * sign)
|
|
return
|
|
|
|
invalid:
|
|
err = errors.New("invalid MySQL TIME string: " + orig)
|
|
return
|
|
|
|
}
|
|
|
|
type Blob []byte
|
|
|
|
type Raw struct {
|
|
Typ uint16
|
|
Val *[]byte
|
|
}
|
|
|
|
type Timestamp struct {
|
|
time.Time
|
|
}
|
|
|
|
func (t Timestamp) String() string {
|
|
return TimeString(t.Time)
|
|
}
|