package db
import (
"database/sql/driver"
"fmt"
"time"
"github.com/relvacode/iso8601"
"google.golang.org/protobuf/types/known/timestamppb"
)
func NewVarCharTime(t time.Time) VarcharTime {
return VarcharTime{
t: t.UTC(),
valid: true,
}
}
func NewVarCharTimeFromStr(s string) (VarcharTime, error) {
var vt VarcharTime
err := vt.Scan(s)
return vt, err
}
type VarcharTime struct {
t time.Time
valid bool
}
func (n *VarcharTime) Scan(value interface{}) error {
if value == nil {
n.valid = false
return nil
}
switch s := value.(type) {
case []uint8:
return n.parseString(string(s))
case string:
return n.parseString(s)
}
return fmt.Errorf("unknown scan value for VarcharTime with value: %v", value)
}
func (n *VarcharTime) parseString(s string) error {
if len(s) == 0 {
n.valid = false
return nil
}
parsed, err := iso8601.ParseString(s)
if err != nil {
return fmt.Errorf("failed to parse %v into ISO8601: %w", s, err)
}
if parsed.UTC().IsZero() {
n.t = time.Time{}.UTC()
n.valid = false
return nil
}
n.valid = true
n.t = parsed.UTC()
return nil
}
func (n VarcharTime) Time() time.Time {
return n.t
}
func (n VarcharTime) IsSet() bool {
return n.valid
}
func (n VarcharTime) Value() (driver.Value, error) {
if n.IsSet() {
return TimeToISO8601(n.t), nil
}
return "", nil
}
func (n VarcharTime) String() string {
if n.IsSet() {
return TimeToISO8601(n.t)
}
return ""
}
var null = "null"
func (n VarcharTime) MarshalJSON() ([]byte, error) {
if !n.IsSet() {
return []byte(null), nil
}
return n.Time().UTC().MarshalJSON()
}
func (n *VarcharTime) UnmarshalJSON(data []byte) error {
if string(data) == null {
n.valid = false
return nil
}
t := time.Time{}
if err := t.UnmarshalJSON(data); err != nil {
return fmt.Errorf("failed to unmarshal VarcharTime %s: %w", string(data), err)
}
if t.IsZero() {
return nil
}
n.valid = true
n.t = t.UTC()
return nil
}
const ISO8601Format = "2006-01-02T15:04:05.000Z"
func TimeToISO8601(t time.Time) string {
return t.UTC().Format(ISO8601Format)
}
func VarcharTimeToTimestamppb(t VarcharTime) *timestamppb.Timestamp {
if !t.IsSet() {
return nil
}
return timestamppb.New(t.Time())
}