Fix timesatmp

This commit is contained in:
Lunny Xiao 2021-08-03 13:45:41 +08:00
parent 983e5fdf99
commit 54606d5bfd
10 changed files with 93 additions and 65 deletions

View File

@ -5,50 +5,53 @@
package dialects
import (
"strings"
"time"
"xorm.io/xorm/schemas"
)
// FormatTime format time as column type
func FormatTime(dialect Dialect, sqlTypeName string, t time.Time) (v interface{}) {
switch sqlTypeName {
case schemas.Time:
s := t.Format("2006-01-02 15:04:05") // time.RFC3339
v = s[11:19]
case schemas.Date:
v = t.Format("2006-01-02")
case schemas.DateTime, schemas.TimeStamp, schemas.Varchar: // !DarthPestilane! format time when sqlTypeName is schemas.Varchar.
if dialect.URI().DBType == schemas.ORACLE {
v = t
} else {
v = t.Format("2006-01-02 15:04:05")
}
case schemas.TimeStampz:
if dialect.URI().DBType == schemas.MSSQL {
v = t.Format("2006-01-02T15:04:05.9999999Z07:00")
} else {
v = t.Format(time.RFC3339Nano)
}
case schemas.BigInt, schemas.Int:
v = t.Unix()
default:
v = t
}
return
}
// FormatColumnTime format column time
func FormatColumnTime(dialect Dialect, defaultTimeZone *time.Location, col *schemas.Column, t time.Time) (v interface{}) {
func FormatColumnTime(dialect Dialect, dbLocation *time.Location, col *schemas.Column, t time.Time) (interface{}, error) {
if t.IsZero() {
if col.Nullable {
return nil
}
return ""
return nil, nil
}
if col.TimeZone != nil {
return FormatTime(dialect, col.SQLType.Name, t.In(col.TimeZone))
if col.SQLType.IsNumeric() {
return 0, nil
}
}
var tmZone = dbLocation
if col.TimeZone != nil {
tmZone = col.TimeZone
}
t = t.In(tmZone)
switch col.SQLType.Name {
case schemas.Time:
s := t.Format("2006-01-02 15:04:05") // time.RFC3339
return s[11:19], nil
case schemas.Date:
return t.Format("2006-01-02"), nil
case schemas.DateTime, schemas.TimeStamp:
if col.Length > 0 {
return t.Format("2006-01-02 15:04:05." + strings.Repeat("0", col.Length)), nil
}
return t.Format("2006-01-02 15:04:05"), nil
case schemas.Varchar:
return t.Format("2006-01-02 15:04:05"), nil
case schemas.TimeStampz:
if dialect.URI().DBType == schemas.MSSQL {
return t.Format("2006-01-02T15:04:05.9999999Z07:00"), nil
} else {
return t.Format(time.RFC3339Nano), nil
}
case schemas.BigInt, schemas.Int:
return t.Unix(), nil
default:
return t, nil
}
return FormatTime(dialect, col.SQLType.Name, t.In(defaultTimeZone))
}

View File

@ -1226,13 +1226,13 @@ func (engine *Engine) Import(r io.Reader) ([]sql.Result, error) {
}
// nowTime return current time
func (engine *Engine) nowTime(col *schemas.Column) (interface{}, time.Time) {
func (engine *Engine) nowTime(col *schemas.Column) (interface{}, time.Time, error) {
t := time.Now()
var tz = engine.DatabaseTZ
if !col.DisableTimeZone && col.TimeZone != nil {
tz = col.TimeZone
result, err := dialects.FormatColumnTime(engine.dialect, engine.DatabaseTZ, col, t)
if err != nil {
return nil, time.Time{}, err
}
return dialects.FormatTime(engine.dialect, col.SQLType.Name, t.In(tz)), t.In(engine.TZLocation)
return result, t.In(engine.TZLocation), nil
}
// GetColumnMapper returns the column name mapper

View File

@ -575,7 +575,7 @@ func TestTimestamp(t *testing.T) {
type TimestampStruct struct {
Id int64
InsertTime time.Time `xorm:"timestamp"`
InsertTime time.Time `xorm:"DATETIME(6)"`
}
assertSync(t, new(TimestampStruct))

View File

@ -8,6 +8,7 @@ import (
"database/sql"
"fmt"
"strconv"
"strings"
"time"
"xorm.io/xorm/internal/utils"
@ -39,6 +40,14 @@ func String2Time(s string, originalLocation *time.Location, convertedLocation *t
}
dt = dt.In(convertedLocation)
return &dt, nil
} else if len(s) >= 21 && s[19] == '.' {
var layout = "2006-01-02 15:04:05." + strings.Repeat("0", len(s)-20)
dt, err := time.ParseInLocation(layout, s, originalLocation)
if err != nil {
return nil, err
}
dt = dt.In(convertedLocation)
return &dt, nil
} else {
i, err := strconv.ParseInt(s, 10, 64)
if err == nil {

View File

@ -734,7 +734,11 @@ func (statement *Statement) asDBCond(fieldValue reflect.Value, fieldType reflect
if !requiredField && (t.IsZero() || !fieldValue.IsValid()) {
return nil, false, nil
}
return dialects.FormatColumnTime(statement.dialect, statement.defaultTimeZone, col, t), true, nil
res, err := dialects.FormatColumnTime(statement.dialect, statement.defaultTimeZone, col, t)
if err != nil {
return nil, false, err
}
return res, true, nil
} else if fieldType.ConvertibleTo(schemas.BigFloatType) {
t := fieldValue.Convert(schemas.BigFloatType).Interface().(big.Float)
v := t.String()

View File

@ -208,7 +208,10 @@ func (statement *Statement) BuildUpdates(tableValue reflect.Value,
if !requiredField && (t.IsZero() || !fieldValue.IsValid()) {
continue
}
val = dialects.FormatColumnTime(statement.dialect, statement.defaultTimeZone, col, t)
val, err = dialects.FormatColumnTime(statement.dialect, statement.defaultTimeZone, col, t)
if err != nil {
return nil, nil, err
}
} else if nulType, ok := fieldValue.Interface().(driver.Valuer); ok {
val, _ = nulType.Value()
if val == nil && !requiredField {

View File

@ -87,8 +87,8 @@ func (statement *Statement) Value2Interface(col *schemas.Column, fieldValue refl
case reflect.Struct:
if fieldType.ConvertibleTo(schemas.TimeType) {
t := fieldValue.Convert(schemas.TimeType).Interface().(time.Time)
tf := dialects.FormatColumnTime(statement.dialect, statement.defaultTimeZone, col, t)
return tf, nil
tf, err := dialects.FormatColumnTime(statement.dialect, statement.defaultTimeZone, col, t)
return tf, err
} else if fieldType.ConvertibleTo(nullFloatType) {
t := fieldValue.Convert(nullFloatType).Interface().(sql.NullFloat64)
if !t.Valid {

View File

@ -212,7 +212,10 @@ func (session *Session) Delete(beans ...interface{}) (int64, error) {
paramsLen := len(condArgs)
copy(condArgs[1:paramsLen], condArgs[0:paramsLen-1])
val, t := session.engine.nowTime(deletedColumn)
val, t, err := session.engine.nowTime(deletedColumn)
if err != nil {
return 0, err
}
condArgs[0] = val
var colName = deletedColumn.Name

View File

@ -12,6 +12,7 @@ import (
"strings"
"time"
"xorm.io/xorm/dialects"
"xorm.io/xorm/internal/convert"
"xorm.io/xorm/internal/utils"
"xorm.io/xorm/schemas"
@ -137,7 +138,10 @@ func (session *Session) insertMultipleStruct(rowsSlicePtr interface{}) (int64, e
continue
}
if (col.IsCreated || col.IsUpdated) && session.statement.UseAutoTime {
val, t := session.engine.nowTime(col)
val, t, err := session.engine.nowTime(col)
if err != nil {
return 0, err
}
args = append(args, val)
var colName = col.Name
@ -427,29 +431,12 @@ func (session *Session) genInsertColumns(bean interface{}) ([]string, []interfac
if col.MapType == schemas.ONLYFROMDB {
continue
}
if col.IsDeleted {
colNames = append(colNames, col.Name)
if !col.Nullable {
if col.SQLType.IsNumeric() {
args = append(args, 0)
} else {
args = append(args, time.Time{}.Format("2006-01-02 15:04:05"))
}
} else {
args = append(args, nil)
}
continue
}
if session.statement.OmitColumnMap.Contain(col.Name) {
continue
}
if len(session.statement.ColumnMap) > 0 && !session.statement.ColumnMap.Contain(col.Name) {
continue
}
if session.statement.IncrColumns.IsColExist(col.Name) {
continue
} else if session.statement.DecrColumns.IsColExist(col.Name) {
@ -458,6 +445,16 @@ func (session *Session) genInsertColumns(bean interface{}) ([]string, []interfac
continue
}
if col.IsDeleted {
arg, err := dialects.FormatColumnTime(session.engine.dialect, session.engine.DatabaseTZ, col, time.Time{})
if err != nil {
return nil, nil, err
}
args = append(args, arg)
colNames = append(colNames, col.Name)
continue
}
fieldValuePtr, err := col.ValueOf(bean)
if err != nil {
return nil, nil, err
@ -478,7 +475,10 @@ func (session *Session) genInsertColumns(bean interface{}) ([]string, []interfac
if (col.IsCreated || col.IsUpdated) && session.statement.UseAutoTime /*&& isZero(fieldValue.Interface())*/ {
// if time is non-empty, then set to auto time
val, t := session.engine.nowTime(col)
val, t, err := session.engine.nowTime(col)
if err != nil {
return nil, nil, err
}
args = append(args, val)
var colName = col.Name

View File

@ -215,7 +215,10 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
!session.statement.OmitColumnMap.Contain(table.Updated) {
colNames = append(colNames, session.engine.Quote(table.Updated)+" = ?")
col := table.UpdatedColumn()
val, t := session.engine.nowTime(col)
val, t, err := session.engine.nowTime(col)
if err != nil {
return 0, err
}
if session.engine.dialect.URI().DBType == schemas.ORACLE {
args = append(args, t)
} else {
@ -521,7 +524,10 @@ func (session *Session) genUpdateColumns(bean interface{}) ([]string, []interfac
if col.IsUpdated && session.statement.UseAutoTime /*&& isZero(fieldValue.Interface())*/ {
// if time is non-empty, then set to auto time
val, t := session.engine.nowTime(col)
val, t, err := session.engine.nowTime(col)
if err != nil {
return nil, nil, err
}
args = append(args, val)
var colName = col.Name