package sqlite3
import (
"math"
"strconv"
"strings"
"time"
"github.com/ncruces/go-sqlite3/internal/util"
"github.com/ncruces/julianday"
)
type TimeFormat string
const (
TimeFormatDefault TimeFormat = ""
TimeFormat1 TimeFormat = "2006-01-02"
TimeFormat2 TimeFormat = "2006-01-02 15:04"
TimeFormat3 TimeFormat = "2006-01-02 15:04:05"
TimeFormat4 TimeFormat = "2006-01-02 15:04:05.000"
TimeFormat5 TimeFormat = "2006-01-02T15:04"
TimeFormat6 TimeFormat = "2006-01-02T15:04:05"
TimeFormat7 TimeFormat = "2006-01-02T15:04:05.000"
TimeFormat8 TimeFormat = "15:04"
TimeFormat9 TimeFormat = "15:04:05"
TimeFormat10 TimeFormat = "15:04:05.000"
TimeFormat2TZ = TimeFormat2 + "Z07:00"
TimeFormat3TZ = TimeFormat3 + "Z07:00"
TimeFormat4TZ = TimeFormat4 + "Z07:00"
TimeFormat5TZ = TimeFormat5 + "Z07:00"
TimeFormat6TZ = TimeFormat6 + "Z07:00"
TimeFormat7TZ = TimeFormat7 + "Z07:00"
TimeFormat8TZ = TimeFormat8 + "Z07:00"
TimeFormat9TZ = TimeFormat9 + "Z07:00"
TimeFormat10TZ = TimeFormat10 + "Z07:00"
TimeFormatJulianDay TimeFormat = "julianday"
TimeFormatUnix TimeFormat = "unixepoch"
TimeFormatUnixFrac TimeFormat = "unixepoch_frac"
TimeFormatUnixMilli TimeFormat = "unixepoch_milli"
TimeFormatUnixMicro TimeFormat = "unixepoch_micro"
TimeFormatUnixNano TimeFormat = "unixepoch_nano"
TimeFormatAuto TimeFormat = "auto"
)
func (f TimeFormat ) Encode (t time .Time ) any {
switch f {
case TimeFormatJulianDay :
return julianday .Float (t )
case TimeFormatUnix :
return t .Unix ()
case TimeFormatUnixFrac :
return math .FMA (1e-9 , float64 (t .Nanosecond ()), float64 (t .Unix ()))
case TimeFormatUnixMilli :
return t .UnixMilli ()
case TimeFormatUnixMicro :
return t .UnixMicro ()
case TimeFormatUnixNano :
return t .UnixNano ()
case TimeFormatDefault , TimeFormatAuto :
f = time .RFC3339Nano
case
TimeFormat1 , TimeFormat2 ,
TimeFormat3 , TimeFormat4 ,
TimeFormat5 , TimeFormat6 ,
TimeFormat7 , TimeFormat8 ,
TimeFormat9 , TimeFormat10 :
t = t .UTC ()
}
return t .Format (string (f ))
}
func (f TimeFormat ) Decode (v any ) (time .Time , error ) {
if t , ok := v .(time .Time ); ok {
return t , nil
}
switch f {
case TimeFormatJulianDay :
switch v := v .(type ) {
case string :
return julianday .Parse (v )
case float64 :
return julianday .FloatTime (v ), nil
case int64 :
return julianday .Time (v , 0 ), nil
default :
return time .Time {}, util .TimeErr
}
case TimeFormatUnix , TimeFormatUnixFrac :
if s , ok := v .(string ); ok {
f , err := strconv .ParseFloat (s , 64 )
if err != nil {
return time .Time {}, err
}
v = f
}
switch v := v .(type ) {
case float64 :
sec , frac := math .Modf (v )
nsec := math .Floor (frac * 1e9 )
return time .Unix (int64 (sec ), int64 (nsec )).UTC (), nil
case int64 :
return time .Unix (v , 0 ).UTC (), nil
default :
return time .Time {}, util .TimeErr
}
case TimeFormatUnixMilli :
if s , ok := v .(string ); ok {
i , err := strconv .ParseInt (s , 10 , 64 )
if err != nil {
return time .Time {}, err
}
v = i
}
switch v := v .(type ) {
case float64 :
return time .UnixMilli (int64 (math .Floor (v ))).UTC (), nil
case int64 :
return time .UnixMilli (v ).UTC (), nil
default :
return time .Time {}, util .TimeErr
}
case TimeFormatUnixMicro :
if s , ok := v .(string ); ok {
i , err := strconv .ParseInt (s , 10 , 64 )
if err != nil {
return time .Time {}, err
}
v = i
}
switch v := v .(type ) {
case float64 :
return time .UnixMicro (int64 (math .Floor (v ))).UTC (), nil
case int64 :
return time .UnixMicro (v ).UTC (), nil
default :
return time .Time {}, util .TimeErr
}
case TimeFormatUnixNano :
if s , ok := v .(string ); ok {
i , err := strconv .ParseInt (s , 10 , 64 )
if err != nil {
return time .Time {}, util .TimeErr
}
v = i
}
switch v := v .(type ) {
case float64 :
return time .Unix (0 , int64 (math .Floor (v ))).UTC (), nil
case int64 :
return time .Unix (0 , v ).UTC (), nil
default :
return time .Time {}, util .TimeErr
}
case TimeFormatAuto :
switch s := v .(type ) {
case string :
i , err := strconv .ParseInt (s , 10 , 64 )
if err == nil {
v = i
break
}
f , err := strconv .ParseFloat (s , 64 )
if err == nil {
v = f
break
}
dates := []TimeFormat {
TimeFormat9 , TimeFormat8 ,
TimeFormat6 , TimeFormat5 ,
TimeFormat3 , TimeFormat2 , TimeFormat1 ,
}
for _ , f := range dates {
t , err := f .Decode (s )
if err == nil {
return t , nil
}
}
}
switch v := v .(type ) {
case float64 :
if 0 <= v && v < 5373484.5 {
return TimeFormatJulianDay .Decode (v )
}
if v < 253402300800 {
return TimeFormatUnixFrac .Decode (v )
}
if v < 253402300800_000 {
return TimeFormatUnixMilli .Decode (v )
}
if v < 253402300800_000000 {
return TimeFormatUnixMicro .Decode (v )
}
return TimeFormatUnixNano .Decode (v )
case int64 :
if 0 <= v && v < 5373485 {
return TimeFormatJulianDay .Decode (v )
}
if v < 253402300800 {
return TimeFormatUnixFrac .Decode (v )
}
if v < 253402300800_000 {
return TimeFormatUnixMilli .Decode (v )
}
if v < 253402300800_000000 {
return TimeFormatUnixMicro .Decode (v )
}
return TimeFormatUnixNano .Decode (v )
default :
return time .Time {}, util .TimeErr
}
case
TimeFormat2 , TimeFormat2TZ ,
TimeFormat3 , TimeFormat3TZ ,
TimeFormat4 , TimeFormat4TZ ,
TimeFormat5 , TimeFormat5TZ ,
TimeFormat6 , TimeFormat6TZ ,
TimeFormat7 , TimeFormat7TZ :
s , ok := v .(string )
if !ok {
return time .Time {}, util .TimeErr
}
return f .parseRelaxed (s )
case
TimeFormat8 , TimeFormat8TZ ,
TimeFormat9 , TimeFormat9TZ ,
TimeFormat10 , TimeFormat10TZ :
s , ok := v .(string )
if !ok {
return time .Time {}, util .TimeErr
}
t , err := f .parseRelaxed (s )
if err != nil {
return time .Time {}, err
}
return t .AddDate (2000 , 0 , 0 ), nil
default :
s , ok := v .(string )
if !ok {
return time .Time {}, util .TimeErr
}
if f == "" {
f = time .RFC3339Nano
}
return time .Parse (string (f ), s )
}
}
func (f TimeFormat ) parseRelaxed (s string ) (time .Time , error ) {
fs := string (f )
fs = strings .TrimSuffix (fs , "Z07:00" )
fs = strings .TrimSuffix (fs , ".000" )
t , err := time .Parse (fs +"Z07:00" , s )
if err != nil {
return time .Parse (fs , s )
}
return t , nil
}
func (f TimeFormat ) Scanner (dest *time .Time ) interface { Scan (any ) error } {
return timeScanner {dest , f }
}
type timeScanner struct {
*time .Time
TimeFormat
}
func (s timeScanner ) Scan (src any ) error {
var ok bool
var err error
if *s .Time , ok = src .(time .Time ); !ok {
*s .Time , err = s .Decode (src )
}
return err
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .