mirror of
https://github.com/stashapp/stash.git
synced 2025-12-06 08:26:00 +01:00
Add precision field to Date and handle parsing year/month-only dates
This commit is contained in:
parent
7bb437df67
commit
b4b1f4d7a1
2 changed files with 88 additions and 6 deletions
|
|
@ -1,31 +1,63 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/stashapp/stash/pkg/utils"
|
||||
)
|
||||
|
||||
type DatePrecision int
|
||||
|
||||
const (
|
||||
// default precision is day
|
||||
DatePrecisionDay DatePrecision = iota
|
||||
DatePrecisionMonth
|
||||
DatePrecisionYear
|
||||
)
|
||||
|
||||
// Date wraps a time.Time with a format of "YYYY-MM-DD"
|
||||
type Date struct {
|
||||
time.Time
|
||||
Precision DatePrecision
|
||||
}
|
||||
|
||||
const dateFormat = "2006-01-02"
|
||||
var dateFormatPrecision []string = []string{
|
||||
"2006-01-02",
|
||||
"2006-01",
|
||||
"2006",
|
||||
}
|
||||
|
||||
func (d Date) String() string {
|
||||
return d.Format(dateFormat)
|
||||
return d.Format(dateFormatPrecision[d.Precision])
|
||||
}
|
||||
|
||||
func (d Date) After(o Date) bool {
|
||||
return d.Time.After(o.Time)
|
||||
}
|
||||
|
||||
// ParseDate uses utils.ParseDateStringAsTime to parse a string into a date.
|
||||
// ParseDate tries to parse the input string into a date using utils.ParseDateStringAsTime.
|
||||
// If that fails, it attempts to parse the string with decreasing precision (month, then year).
|
||||
// It returns a Date struct with the appropriate precision set, or an error if all parsing attempts fail.
|
||||
func ParseDate(s string) (Date, error) {
|
||||
var errs []error
|
||||
|
||||
// default parse to day precision
|
||||
ret, err := utils.ParseDateStringAsTime(s)
|
||||
if err != nil {
|
||||
return Date{}, err
|
||||
if err == nil {
|
||||
return Date{Time: ret, Precision: DatePrecisionDay}, nil
|
||||
}
|
||||
return Date{Time: ret}, nil
|
||||
|
||||
errs = append(errs, err)
|
||||
|
||||
// try month and year precision
|
||||
for i, format := range dateFormatPrecision[1:] {
|
||||
ret, err := time.Parse(format, s)
|
||||
if err == nil {
|
||||
return Date{Time: ret, Precision: DatePrecision(i + 1)}, nil
|
||||
}
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
return Date{}, fmt.Errorf("failed to parse date %q: %v", s, errs)
|
||||
}
|
||||
|
|
|
|||
50
pkg/models/date_test.go
Normal file
50
pkg/models/date_test.go
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestParseDateStringAsTime(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
output Date
|
||||
expectError bool
|
||||
}{
|
||||
// Full date formats (existing support)
|
||||
{"RFC3339", "2014-01-02T15:04:05Z", Date{Time: time.Date(2014, 1, 2, 15, 4, 5, 0, time.UTC), Precision: DatePrecisionDay}, false},
|
||||
{"Date only", "2014-01-02", Date{Time: time.Date(2014, 1, 2, 0, 0, 0, 0, time.UTC), Precision: DatePrecisionDay}, false},
|
||||
{"Date with time", "2014-01-02 15:04:05", Date{Time: time.Date(2014, 1, 2, 15, 4, 5, 0, time.UTC), Precision: DatePrecisionDay}, false},
|
||||
|
||||
// Partial date formats (new support)
|
||||
{"Year-Month", "2006-08", Date{Time: time.Date(2006, 8, 1, 0, 0, 0, 0, time.UTC), Precision: DatePrecisionMonth}, false},
|
||||
{"Year only", "2014", Date{Time: time.Date(2014, 1, 1, 0, 0, 0, 0, time.UTC), Precision: DatePrecisionYear}, false},
|
||||
|
||||
// Invalid formats
|
||||
{"Invalid format", "not-a-date", Date{}, true},
|
||||
{"Empty string", "", Date{}, true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result, err := ParseDate(tt.input)
|
||||
|
||||
if tt.expectError {
|
||||
if err == nil {
|
||||
t.Errorf("Expected error for input %q, but got none", tt.input)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error for input %q: %v", tt.input, err)
|
||||
return
|
||||
}
|
||||
|
||||
if !result.Time.Equal(tt.output.Time) || result.Precision != tt.output.Precision {
|
||||
t.Errorf("For input %q, expected output %+v, got %+v", tt.input, tt.output, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue