Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion date/date.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,17 @@ type Date struct {
DateTime time.Time
}

func Now() *Date {
now := time.Now()

return &Date{
Year: now.Year(),
Month: int(now.Month()),
Day: now.Day(),
DateTime: now,
}
}

func New(year, month, day int) (datetime.Interface, error) {
errs := validator.Validate(year, constraints.GreaterOrEqual{Value: 0})

Expand Down Expand Up @@ -95,5 +106,13 @@ func (d *Date) Equal(u datetime.Interface) bool {
}

func (d *Date) Between(start, end datetime.Interface) bool {
return d.Time().Before(end.Time()) && d.Time().After(start.Time())
return d.Before(end) && d.After(start)
}

func (d *Date) Before(u datetime.Interface) bool {
return d.Time().Before(u.Time())
}

func (d *Date) After(u datetime.Interface) bool {
return d.Time().After(u.Time())
}
71 changes: 60 additions & 11 deletions date/range.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import (
)

const (
RangeRegexp = `^([\[\(])(\d{4}-\d{2}-\d{2})?,(\d{4}-\d{2}-\d{2})?([\]\)])$`
RangeDateRegexp = `(` + datetime.YearRegexp + `-` + datetime.MonthRegexp + `-` + datetime.DayRegexp + `)`
RangeRegexp = `^([\[\(])` + RangeDateRegexp + `?\s*,\s*` + RangeDateRegexp + `?([\]\)])$`
)

type Range struct {
Expand All @@ -21,13 +22,46 @@ type Range struct {
end datetime.RangeEnd
}

func NewDateRange(from, to string, start datetime.RangeStart, end datetime.RangeEnd) *Range {
func NewRange(from, to string, start datetime.RangeStart, end datetime.RangeEnd) (*Range, error) {

_, err := FromString(from)

if from != "" && err != nil {
return nil, err
}

_, err = FromString(to)

if to != "" && err != nil {
return nil, err
}

if to == "" && from == "" {
return nil, errors.New("from and to can not be both empty")
}

return &Range{
from: Value(from),
to: Value(to),
start: start,
end: end,
}
}, nil
}

func NewRangeOptional(from, to string) (*Range, error) {
return NewRange(from, to, datetime.RangeStartOptional, datetime.RangeEndOptional)
}

func NewRangeStrict(from, to string) (*Range, error) {
return NewRange(from, to, datetime.RangeStartStrict, datetime.RangeEndStrict)
}

func NewRangeStartStrict(from, to string) (*Range, error) {
return NewRange(from, to, datetime.RangeStartStrict, datetime.RangeEndOptional)
}

func NewRangeStartOptional(from, to string) (*Range, error) {
return NewRange(from, to, datetime.RangeStartOptional, datetime.RangeEndStrict)
}

func RangeFromString(dateRange string) (*Range, error) {
Expand All @@ -39,9 +73,9 @@ func RangeFromString(dateRange string) (*Range, error) {

re := regexp.MustCompile(RangeRegexp)
match := re.FindStringSubmatch(dateRange)
openBracket, date1, date2, closeBracket := match[1], match[2], match[3], match[4]
openBracket, date1, date2, closeBracket := match[1], match[2], match[6], match[10]

return NewDateRange(date1, date2, datetime.RangeStart(openBracket), datetime.RangeEnd(closeBracket)), nil
return NewRange(date1, date2, datetime.RangeStart(openBracket), datetime.RangeEnd(closeBracket))
}

func (d *Range) Start() datetime.RangeStart {
Expand All @@ -52,8 +86,16 @@ func (d *Range) End() datetime.RangeEnd {
return d.end
}

func (d *Range) From() Value {
return d.from
}

func (d *Range) To() Value {
return d.to
}

func (d *Range) String() string {
return fmt.Sprintf("%s%s,%s%s", d.start, d.from, d.to, d.end)
return fmt.Sprintf("%s%s, %s%s", d.Start(), d.From(), d.To(), d.End())
}

func (d *Range) Is(value any) bool {
Expand All @@ -63,9 +105,18 @@ func (d *Range) Is(value any) bool {
return false
}

start, _ := FromString(string(d.start))
end, _ := FromString(string(d.end))
return date.Between(start, end)
from, _ := FromString(string(d.From()))
to, _ := FromString(string(d.To()))

if from == nil {
return date.Before(to)
}

if to == nil {
return date.After(from)
}

return date.Between(from, to)
}

func (d *Range) format(date any) (datetime.Interface, error) {
Expand All @@ -74,8 +125,6 @@ func (d *Range) format(date any) (datetime.Interface, error) {
return New(i.Year(), int(i.Month()), i.Day())
case *Date:
return i, nil
case Date:
return &i, nil
case string:
return FromString(i)
default:
Expand Down
2 changes: 2 additions & 0 deletions dateTimeInterface.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,7 @@ type Interface interface {
Time() time.Time
Equal(u Interface) bool
Between(start, end Interface) bool
Before(u Interface) bool
After(u Interface) bool
Compare(u Interface) int
}
33 changes: 18 additions & 15 deletions datetime.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
)

const (
Regexp = `^(\d{4})-(\d{2})-(\d{2})( (\d{2}):(\d{2}):(\d{2}))?$`
Regexp = `^((\d+)-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01]))\s(0[0-9]|1[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$`
)

type DateTime struct {
Expand Down Expand Up @@ -96,19 +96,14 @@ func FromString(value string) (Interface, error) {

re := regexp.MustCompile(Regexp)
match := re.FindStringSubmatch(value)
year, _ := strconv.Atoi(match[1])
month, _ := strconv.Atoi(match[2])
day, _ := strconv.Atoi(match[3])

if match[4] != "" {
hour, _ := strconv.Atoi(match[5])
minute, _ := strconv.Atoi(match[6])
second, _ := strconv.Atoi(match[7])

return New(year, month, day, hour, minute, second)
}

return nil, errors.New(fmt.Sprintf("unsupported format of datetime \"%s\". time is missing.", value))
year, _ := strconv.Atoi(match[2])
month, _ := strconv.Atoi(match[3])
day, _ := strconv.Atoi(match[4])
hour, _ := strconv.Atoi(match[5])
minute, _ := strconv.Atoi(match[6])
second, _ := strconv.Atoi(match[7])

return New(year, month, day, hour, minute, second)
}

func (d *DateTime) FromString(value string) (Interface, error) {
Expand Down Expand Up @@ -143,7 +138,15 @@ func (d *DateTime) Equal(u Interface) bool {
}

func (d *DateTime) Between(start, end Interface) bool {
return d.Time().Before(end.Time()) && d.Time().After(start.Time())
return d.Before(end) && d.After(start)
}

func (d *DateTime) Before(u Interface) bool {
return d.Time().Before(u.Time())
}

func (d *DateTime) After(u Interface) bool {
return d.Time().After(u.Time())
}

func DaysInMonthList(year int, month int) []int {
Expand Down
129 changes: 108 additions & 21 deletions range.go
Original file line number Diff line number Diff line change
@@ -1,43 +1,130 @@
package datetime

type RangeStart string
type RangeEnd string

var (
// RangeStartStrict can not be equal
RangeStartStrict RangeStart = "["
// RangeStartOptional can be equal
RangeStartOptional RangeStart = "("
// RangeEndStrict can not be equal
RangeEndStrict RangeEnd = "]"
// RangeEndOptional can be equal
RangeEndOptional RangeEnd = ")"
import (
"errors"
"fmt"
"github.com/gouef/validator"
"github.com/gouef/validator/constraints"
"regexp"
"time"
)

type Range struct {
from Value
to Value
start RangeStart
end RangeEnd
}

func NewRange(start RangeStart, end RangeEnd) *Range {
func NewRange(from, to string, start RangeStart, end RangeEnd) (*Range, error) {

_, err := FromString(from)

if from != "" && err != nil {
return nil, err
}

_, err = FromString(to)

if to != "" && err != nil {
return nil, err
}

return &Range{
from: Value(from),
to: Value(to),
start: start,
end: end,
}, nil
}

func NewRangeOptional(from, to string) (*Range, error) {
return NewRange(from, to, RangeStartOptional, RangeEndOptional)
}

func NewRangeStrict(from, to string) (*Range, error) {
return NewRange(from, to, RangeStartStrict, RangeEndStrict)
}

func NewRangeStartStrict(from, to string) (*Range, error) {
return NewRange(from, to, RangeStartStrict, RangeEndOptional)
}

func NewRangeStartOptional(from, to string) (*Range, error) {
return NewRange(from, to, RangeStartOptional, RangeEndStrict)
}

func RangeFromString(value string) (*Range, error) {
errs := validator.Validate(value, constraints.RegularExpression{Regexp: RangeRegexp})

if len(errs) != 0 {
return nil, errors.New(fmt.Sprintf("unsupported format of datetime range \"%s\"", value))
}

re := regexp.MustCompile(RangeRegexp)
match := re.FindStringSubmatch(value)
start := match[1]
from := match[2]
to := match[12]
end := match[22]

return NewRange(from, to, RangeStart(start), RangeEnd(end))
}

func (r *Range) Start() RangeStart {
return r.start
}

func (r *Range) End() RangeEnd {
return r.end
}

func NewRangeOptional() *Range {
return NewRange(RangeStartOptional, RangeEndOptional)
func (r *Range) From() ValueInterface {
return r.from
}

func NewRangeStrict() *Range {
return NewRange(RangeStartStrict, RangeEndStrict)
func (r *Range) To() ValueInterface {
return r.to
}

func NewRangeStartStrict() *Range {
return NewRange(RangeStartStrict, RangeEndOptional)
func (r *Range) String() string {
return fmt.Sprintf("%s%s, %s%s", r.Start(), r.From(), r.To(), r.End())
}

func (r *Range) Is(value any) bool {
date, err := r.format(value)

if err != nil {
return false
}

from, _ := FromString(string(r.from))
to, _ := FromString(string(r.to))

if from == nil && to == nil {
return false
}

if from == nil {
return date.Before(to)
}

if to == nil {
return date.After(from)
}

return date.Between(from, to)
}

func NewRangeStartOptional() *Range {
return NewRange(RangeStartOptional, RangeEndStrict)
func (r *Range) format(date any) (Interface, error) {
switch i := date.(type) {
case time.Time:
return New(i.Year(), int(i.Month()), i.Day(), i.Hour(), i.Minute(), i.Second())
case *DateTime:
return i, nil
case string:
return FromString(i)
default:
return nil, errors.New("unsupported format of datetime")
}
}
Loading