mirror of https://github.com/jackc/pgx.git
Fix text decoding of dates with 5 digit years
parent
071d1c9467
commit
871f14e43b
|
@ -5,6 +5,7 @@ import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -267,6 +268,8 @@ func (scanPlanBinaryDateToDateScanner) Scan(src []byte, dst any) error {
|
||||||
|
|
||||||
type scanPlanTextAnyToDateScanner struct{}
|
type scanPlanTextAnyToDateScanner struct{}
|
||||||
|
|
||||||
|
var dateRegexp = regexp.MustCompile(`^(\d{4,})-(\d\d)-(\d\d)( BC)?$`)
|
||||||
|
|
||||||
func (scanPlanTextAnyToDateScanner) Scan(src []byte, dst any) error {
|
func (scanPlanTextAnyToDateScanner) Scan(src []byte, dst any) error {
|
||||||
scanner := (dst).(DateScanner)
|
scanner := (dst).(DateScanner)
|
||||||
|
|
||||||
|
@ -275,36 +278,40 @@ func (scanPlanTextAnyToDateScanner) Scan(src []byte, dst any) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
sbuf := string(src)
|
sbuf := string(src)
|
||||||
|
match := dateRegexp.FindStringSubmatch(sbuf)
|
||||||
|
if match != nil {
|
||||||
|
year, err := strconv.ParseInt(match[1], 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("BUG: cannot parse date that regexp matched (year): %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
month, err := strconv.ParseInt(match[2], 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("BUG: cannot parse date that regexp matched (month): %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
day, err := strconv.ParseInt(match[3], 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("BUG: cannot parse date that regexp matched (month): %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BC matched
|
||||||
|
if len(match[4]) > 0 {
|
||||||
|
year = -year + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
t := time.Date(int(year), time.Month(month), int(day), 0, 0, 0, 0, time.UTC)
|
||||||
|
return scanner.ScanDate(Date{Time: t, Valid: true})
|
||||||
|
}
|
||||||
|
|
||||||
switch sbuf {
|
switch sbuf {
|
||||||
case "infinity":
|
case "infinity":
|
||||||
return scanner.ScanDate(Date{InfinityModifier: Infinity, Valid: true})
|
return scanner.ScanDate(Date{InfinityModifier: Infinity, Valid: true})
|
||||||
case "-infinity":
|
case "-infinity":
|
||||||
return scanner.ScanDate(Date{InfinityModifier: -Infinity, Valid: true})
|
return scanner.ScanDate(Date{InfinityModifier: -Infinity, Valid: true})
|
||||||
default:
|
default:
|
||||||
if len(sbuf) >= 10 {
|
|
||||||
year, err := strconv.ParseInt(sbuf[0:4], 10, 32)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("cannot parse year: %v", err)
|
|
||||||
}
|
|
||||||
month, err := strconv.ParseInt(sbuf[5:7], 10, 32)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("cannot parse month: %v", err)
|
|
||||||
}
|
|
||||||
day, err := strconv.ParseInt(sbuf[8:10], 10, 32)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("cannot parse day: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(sbuf) == 13 && sbuf[11:] == "BC" {
|
|
||||||
year = -year + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
t := time.Date(int(year), time.Month(month), int(day), 0, 0, 0, 0, time.UTC)
|
|
||||||
return scanner.ScanDate(Date{Time: t, Valid: true})
|
|
||||||
} else {
|
|
||||||
return fmt.Errorf("date too short")
|
return fmt.Errorf("date too short")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c DateCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
|
func (c DateCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
|
||||||
|
|
|
@ -31,6 +31,7 @@ func TestDateCodec(t *testing.T) {
|
||||||
{time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), new(time.Time), isExpectedEqTime(time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC))},
|
{time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), new(time.Time), isExpectedEqTime(time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC))},
|
||||||
{time.Date(2000, 1, 2, 0, 0, 0, 0, time.UTC), new(time.Time), isExpectedEqTime(time.Date(2000, 1, 2, 0, 0, 0, 0, time.UTC))},
|
{time.Date(2000, 1, 2, 0, 0, 0, 0, time.UTC), new(time.Time), isExpectedEqTime(time.Date(2000, 1, 2, 0, 0, 0, 0, time.UTC))},
|
||||||
{time.Date(2200, 1, 1, 0, 0, 0, 0, time.UTC), new(time.Time), isExpectedEqTime(time.Date(2200, 1, 1, 0, 0, 0, 0, time.UTC))},
|
{time.Date(2200, 1, 1, 0, 0, 0, 0, time.UTC), new(time.Time), isExpectedEqTime(time.Date(2200, 1, 1, 0, 0, 0, 0, time.UTC))},
|
||||||
|
{time.Date(12200, 1, 2, 0, 0, 0, 0, time.UTC), new(time.Time), isExpectedEqTime(time.Date(12200, 1, 2, 0, 0, 0, 0, time.UTC))},
|
||||||
{pgtype.Date{InfinityModifier: pgtype.Infinity, Valid: true}, new(pgtype.Date), isExpectedEq(pgtype.Date{InfinityModifier: pgtype.Infinity, Valid: true})},
|
{pgtype.Date{InfinityModifier: pgtype.Infinity, Valid: true}, new(pgtype.Date), isExpectedEq(pgtype.Date{InfinityModifier: pgtype.Infinity, Valid: true})},
|
||||||
{pgtype.Date{InfinityModifier: pgtype.NegativeInfinity, Valid: true}, new(pgtype.Date), isExpectedEq(pgtype.Date{InfinityModifier: pgtype.NegativeInfinity, Valid: true})},
|
{pgtype.Date{InfinityModifier: pgtype.NegativeInfinity, Valid: true}, new(pgtype.Date), isExpectedEq(pgtype.Date{InfinityModifier: pgtype.NegativeInfinity, Valid: true})},
|
||||||
{pgtype.Date{}, new(pgtype.Date), isExpectedEq(pgtype.Date{})},
|
{pgtype.Date{}, new(pgtype.Date), isExpectedEq(pgtype.Date{})},
|
||||||
|
@ -51,6 +52,7 @@ func TestDateCodecTextEncode(t *testing.T) {
|
||||||
{source: pgtype.Date{Time: time.Date(789, 1, 2, 0, 0, 0, 0, time.UTC), Valid: true}, result: "0789-01-02"},
|
{source: pgtype.Date{Time: time.Date(789, 1, 2, 0, 0, 0, 0, time.UTC), Valid: true}, result: "0789-01-02"},
|
||||||
{source: pgtype.Date{Time: time.Date(89, 1, 2, 0, 0, 0, 0, time.UTC), Valid: true}, result: "0089-01-02"},
|
{source: pgtype.Date{Time: time.Date(89, 1, 2, 0, 0, 0, 0, time.UTC), Valid: true}, result: "0089-01-02"},
|
||||||
{source: pgtype.Date{Time: time.Date(9, 1, 2, 0, 0, 0, 0, time.UTC), Valid: true}, result: "0009-01-02"},
|
{source: pgtype.Date{Time: time.Date(9, 1, 2, 0, 0, 0, 0, time.UTC), Valid: true}, result: "0009-01-02"},
|
||||||
|
{source: pgtype.Date{Time: time.Date(12200, 1, 2, 0, 0, 0, 0, time.UTC), Valid: true}, result: "12200-01-02"},
|
||||||
{source: pgtype.Date{InfinityModifier: pgtype.Infinity, Valid: true}, result: "infinity"},
|
{source: pgtype.Date{InfinityModifier: pgtype.Infinity, Valid: true}, result: "infinity"},
|
||||||
{source: pgtype.Date{InfinityModifier: pgtype.NegativeInfinity, Valid: true}, result: "-infinity"},
|
{source: pgtype.Date{InfinityModifier: pgtype.NegativeInfinity, Valid: true}, result: "-infinity"},
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue