golib/database/csvx/date.go

113 lines
1.9 KiB
Go

package csvx
import (
"database/sql/driver"
"encoding/json"
"fmt"
"time"
)
// Date is a nullable date that implements CSV, JSON, and driver interfaces.
type Date struct {
Time time.Time
Valid bool
}
const dateFormat = "2006-01-02"
func (d Date) IsNil() bool { return !d.Valid }
func (d Date) Value() (driver.Value, error) {
if !d.Valid {
return nil, nil
}
return d.Time, nil
}
func (d *Date) Scan(value any) error {
if value == nil {
d.Valid = false
d.Time = time.Time{}
return nil
}
switch v := value.(type) {
case time.Time:
d.Time = v
d.Valid = true
case string:
parsed, err := time.Parse(dateFormat, v)
if err != nil {
d.Valid = false
d.Time = time.Time{}
return nil
}
d.Time = parsed
d.Valid = true
case []byte:
return d.Scan(string(v))
case Date:
*d = v
default:
return fmt.Errorf("csvx.Date: cannot scan %T", value)
}
return nil
}
func (d Date) MarshalCSV() ([]byte, error) {
if !d.Valid {
return nil, nil
}
return []byte(d.Time.Format(dateFormat)), nil
}
func (d *Date) UnmarshalCSV(data []byte) error {
s := string(data)
if s == "" {
d.Valid = false
d.Time = time.Time{}
return nil
}
parsed, err := time.Parse(dateFormat, s)
if err != nil {
d.Valid = false
d.Time = time.Time{}
return nil
}
d.Time = parsed
d.Valid = true
return nil
}
func (d Date) MarshalJSON() ([]byte, error) {
if !d.Valid {
return []byte("null"), nil
}
return json.Marshal(d.Time.Format(dateFormat))
}
func (d *Date) UnmarshalJSON(data []byte) error {
if string(data) == "null" {
d.Valid = false
d.Time = time.Time{}
return nil
}
var s string
if err := json.Unmarshal(data, &s); err != nil {
return err
}
if s == "" {
d.Valid = false
d.Time = time.Time{}
return nil
}
parsed, err := time.Parse(dateFormat, s)
if err != nil {
d.Valid = false
d.Time = time.Time{}
return nil
}
d.Time = parsed
d.Valid = true
return nil
}