Skip to content

Commit 43bf69a

Browse files
Make absolute parser can detect if parsed time period is hour, minute, or second
1 parent f4f6952 commit 43bf69a

File tree

7 files changed

+71
-64
lines changed

7 files changed

+71
-64
lines changed

internal/parser/absolute/parser.go

+12-7
Original file line numberDiff line numberDiff line change
@@ -278,8 +278,9 @@ func (p *Parser) Parse(tz timezone.OffsetData) (date.Date, error) {
278278
}
279279

280280
// Parse time
281+
var parsedTimePeriod date.Period
281282
if timeToken, exist := p.ComponentTokens["time"]; exist {
282-
p.ParsedTime, err = common.ParseTime(timeToken.Text)
283+
p.ParsedTime, parsedTimePeriod, err = common.ParseTime(timeToken.Text)
283284
if err != nil {
284285
return date.Date{}, err
285286
}
@@ -311,9 +312,17 @@ func (p *Parser) Parse(tz timezone.OffsetData) (date.Date, error) {
311312
// Apply correction for preference of day: beginning, current, end
312313
dt = p.correctForDay(dt)
313314

315+
// Get the period of this date
316+
returnTimeAsPeriod := p.Config != nil && p.Config.ReturnTimeAsPeriod
317+
318+
datePeriod := p.getPeriod()
319+
if !p.ParsedTime.IsZero() && returnTimeAsPeriod {
320+
datePeriod = min(datePeriod, parsedTimePeriod)
321+
}
322+
314323
return date.Date{
315324
Time: dt,
316-
Period: p.getPeriod(),
325+
Period: datePeriod,
317326
}, nil
318327
}
319328

@@ -571,16 +580,12 @@ func (p *Parser) correctForMonth(t time.Time) time.Time {
571580
}
572581

573582
func (p *Parser) getPeriod() date.Period {
574-
timeExist := !p.ParsedTime.IsZero()
575583
_, dayExist := p.ComponentValues["day"]
576584
_, monthExist := p.ComponentValues["month"]
577585
_, yearExist := p.ComponentValues["year"]
578-
returnTimeAsPeriod := p.Config != nil && p.Config.ReturnTimeAsPeriod
579586

580587
switch {
581-
case returnTimeAsPeriod && timeExist:
582-
return date.Hour
583-
case timeExist || dayExist:
588+
case dayExist:
584589
return date.Day
585590
case monthExist:
586591
return date.Month

internal/parser/common/time.go

+18-13
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,37 @@ import (
44
"fmt"
55
"strings"
66
"time"
7+
8+
"github.com/markusmobius/go-dateparser/date"
79
)
810

911
// ParseTime parses the specified string using one of the common time formats.
10-
func ParseTime(s string) (time.Time, error) {
11-
timeFormats := []string{
12-
"15:4:5",
13-
"3:4:5 PM",
14-
"15:4",
15-
"3:4 PM",
16-
"3 PM",
17-
"15:4:5.999999",
18-
"3:4:5.999999 PM",
19-
"15:4 PM",
12+
func ParseTime(s string) (time.Time, date.Period, error) {
13+
timeFormats := []struct {
14+
Pattern string
15+
Period date.Period
16+
}{
17+
{"15:4:5", date.Second},
18+
{"3:4:5 PM", date.Second},
19+
{"15:4", date.Minute},
20+
{"3:4 PM", date.Minute},
21+
{"3 PM", date.Hour},
22+
{"15:4:5.999999", date.Second},
23+
{"3:4:5.999999 PM", date.Second},
24+
{"15:4 PM", date.Minute},
2025
}
2126

2227
tmp := strings.TrimSpace(s)
2328
tmp = strings.ToUpper(tmp)
2429
for _, format := range timeFormats {
25-
t, err := time.Parse(format, tmp)
30+
t, err := time.Parse(format.Pattern, tmp)
2631
if err != nil {
2732
continue
2833
}
2934

30-
return t, nil
35+
return t, format.Period, nil
3136
}
3237

3338
err := fmt.Errorf("%s doesn't seem to be a valid time", s)
34-
return time.Time{}, err
39+
return time.Time{}, date.None, err
3540
}

internal/parser/common/time_test.go

+22-17
Original file line numberDiff line numberDiff line change
@@ -4,35 +4,40 @@ import (
44
"testing"
55
"time"
66

7+
"github.com/markusmobius/go-dateparser/date"
78
"github.com/stretchr/testify/assert"
89
)
910

1011
func TestParseTime(t *testing.T) {
1112
// Helper function
12-
isEqual := func(s string, hour, min, sec, msec int) {
13-
expected := time.Date(0, 1, 1, hour, min, sec, msec*1_000, time.UTC)
14-
result, _ := ParseTime(s)
15-
assert.Equal(t, expected, result, s)
13+
isEqual := func(s string, hour, min, sec, msec int, expectedPeriod date.Period) {
14+
expectedTime := time.Date(0, 1, 1, hour, min, sec, msec*1_000, time.UTC)
15+
result, period, _ := ParseTime(s)
16+
assert.Equal(t, expectedTime, result, s)
17+
assert.Equal(t, expectedPeriod, period, s)
1618
}
1719

1820
isZero := func(s string) {
19-
result, _ := ParseTime(s)
21+
result, period, _ := ParseTime(s)
2022
assert.True(t, result.IsZero(), s)
23+
assert.Equal(t, date.None, period)
2124
}
2225

2326
// Time should be parsed
24-
isEqual("11:30:14", 11, 30, 14, 0)
25-
isEqual("11:30", 11, 30, 0, 0)
26-
isEqual("11:30 PM", 23, 30, 0, 0)
27-
isEqual("13:30 PM", 13, 30, 0, 0)
28-
isEqual("16:14 AM", 16, 14, 0, 0)
29-
isEqual("23:30 AM", 23, 30, 0, 0)
30-
isEqual("1:30 AM", 1, 30, 0, 0)
31-
isEqual("1:30:15.330 AM", 1, 30, 15, 330000)
32-
isEqual("1:30:15.330 PM", 13, 30, 15, 330000)
33-
isEqual("1:30:15.3301 PM", 13, 30, 15, 330100)
34-
isEqual("11:20:05 AM", 11, 20, 5, 0)
35-
isEqual("14:30:15.330100", 14, 30, 15, 330100)
27+
isEqual("11:30:14", 11, 30, 14, 0, date.Second)
28+
isEqual("11:30", 11, 30, 0, 0, date.Minute)
29+
isEqual("11:30 PM", 23, 30, 0, 0, date.Minute)
30+
isEqual("13:30 PM", 13, 30, 0, 0, date.Minute)
31+
isEqual("16:14 AM", 16, 14, 0, 0, date.Minute)
32+
isEqual("23:30 AM", 23, 30, 0, 0, date.Minute)
33+
isEqual("1:30 AM", 1, 30, 0, 0, date.Minute)
34+
isEqual("1:30:15.330 AM", 1, 30, 15, 330000, date.Second)
35+
isEqual("1:30:15.330 PM", 13, 30, 15, 330000, date.Second)
36+
isEqual("1:30:15.3301 PM", 13, 30, 15, 330100, date.Second)
37+
isEqual("11:20:05 AM", 11, 20, 5, 0, date.Second)
38+
isEqual("14:30:15.330100", 14, 30, 15, 330100, date.Second)
39+
isEqual("11 AM", 11, 0, 0, 0, date.Hour)
40+
isEqual("11 PM", 23, 0, 0, 0, date.Hour)
3641

3742
// Time is invalid
3843
isZero("11")

internal/parser/relative/parser.go

+3-5
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ func Parse(cfg *setting.Configuration, str string) date.Date {
3131
str, tzData := timezone.PopTzOffset(str)
3232

3333
// Parse time
34-
t, _ := parseTime(str)
34+
t, tPeriod, _ := parseTime(str)
3535

3636
// Find current time
3737
now := time.Now().UTC()
@@ -54,9 +54,7 @@ func Parse(cfg *setting.Configuration, str string) date.Date {
5454
dt = time.Date(dt.Year(), dt.Month(), dt.Day(),
5555
t.Hour(), t.Minute(), t.Second(), t.Nanosecond(),
5656
dt.Location())
57-
if period > date.Hour {
58-
period = date.Hour
59-
}
57+
period = min(period, tPeriod)
6058
}
6159

6260
if cfg != nil && !cfg.ReturnTimeAsPeriod && period.IsTime() {
@@ -67,7 +65,7 @@ func Parse(cfg *setting.Configuration, str string) date.Date {
6765
return date.Date{Time: dt, Period: period}
6866
}
6967

70-
func parseTime(s string) (time.Time, error) {
68+
func parseTime(s string) (time.Time, date.Period, error) {
7169
s = rxRelativePattern.ReplaceAllString(s, "")
7270
s = rxInAgo.ReplaceAllString(s, "")
7371
return common.ParseTime(s)

internal/parser/timestamp/parser.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ var (
1818
func Parse(cfg *setting.Configuration, str string, negative bool) date.Date {
1919
period := date.Day
2020
if cfg != nil && cfg.ReturnTimeAsPeriod {
21-
period = date.Hour
21+
period = date.Second
2222
}
2323

2424
var rx *regexp.Regexp

parser-relative_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ func TestParser_Parse_relative_pastAndFutureDates(t *testing.T) {
6666

6767
// English dates
6868
{"yesterday", pfpDiff{"day": -1}, Day},
69-
{"yesterday at 11:30", pfpDiff{"hour": -23}, Hour},
69+
{"yesterday at 11:30", pfpDiff{"hour": -23}, Minute},
7070
{"1 decade", pfpDiff{"year": -10}, Year},
7171
{"1 decade 2 years", pfpDiff{"year": -12}, Year},
7272
{"1 decade 12 months", pfpDiff{"year": -10, "month": -12}, Month},

parser_test.go

+14-20
Original file line numberDiff line numberDiff line change
@@ -521,40 +521,34 @@ func TestParser_Parse_returnTimeAsPeriod(t *testing.T) {
521521
ExpectedPeriod date.Period
522522
}
523523

524-
ts := func(text string, eTime time.Time, bTime ...time.Time) testScenario {
524+
ts := func(text string, ePeriod date.Period, eTime time.Time, bTime ...time.Time) testScenario {
525525
var baseTime time.Time
526526
if len(bTime) > 0 {
527527
baseTime = bTime[0]
528528
}
529-
return testScenario{text, baseTime, eTime, date.Hour}
530-
}
531-
532-
tsd := func(text string, eTime time.Time, bTime ...time.Time) testScenario {
533-
test := ts(text, eTime, bTime...)
534-
test.ExpectedPeriod = date.Day
535-
return test
529+
return testScenario{text, baseTime, eTime, ePeriod}
536530
}
537531

538532
tests := []testScenario{
539533
// Timestamp
540-
ts("1484823450", tt(2017, 1, 19, 10, 57, 30)),
541-
ts("1436745600000", tt(2015, 7, 13, 0, 0)),
542-
ts("1015673450", tt(2002, 3, 9, 11, 30, 50)),
543-
ts("2016-09-23T02:54:32.845Z", tt(2016, 9, 23, 2, 54, 32, 845000)),
534+
ts("1484823450", date.Second, tt(2017, 1, 19, 10, 57, 30)),
535+
ts("1436745600000", date.Second, tt(2015, 7, 13, 0, 0)),
536+
ts("1015673450", date.Second, tt(2002, 3, 9, 11, 30, 50)),
537+
ts("2016-09-23T02:54:32.845Z", date.Second, tt(2016, 9, 23, 2, 54, 32, 845000)),
544538

545539
// Basic text
546-
ts("12th December 2019 19:00", tt(2019, 12, 12, 19, 0)),
547-
ts("9 Jan 11 0:00", tt(2011, 1, 9, 0, 0)),
540+
ts("12th December 2019 19:00", date.Minute, tt(2019, 12, 12, 19, 0)),
541+
ts("9 Jan 11 0:00", date.Minute, tt(2011, 1, 9, 0, 0)),
548542

549543
// Basic text with base time
550-
ts("10:04am EDT", tt(2020, 7, 19, 14, 4), tt(2020, 7, 19)),
551-
ts("16:00", tt(2018, 12, 13, 16, 0), tt(2018, 12, 13, 15, 15)),
552-
ts("Monday 7:15 AM", tt(2018, 12, 10, 7, 15), tt(2018, 12, 13, 15, 15)),
553-
ts("Mon 19:43", tt(2018, 12, 10, 19, 43), tt(2018, 12, 13, 15, 15)),
544+
ts("10:04am EDT", date.Minute, tt(2020, 7, 19, 14, 4), tt(2020, 7, 19)),
545+
ts("16:00", date.Minute, tt(2018, 12, 13, 16, 0), tt(2018, 12, 13, 15, 15)),
546+
ts("Monday 7:15 AM", date.Minute, tt(2018, 12, 10, 7, 15), tt(2018, 12, 13, 15, 15)),
547+
ts("Mon 19:43", date.Minute, tt(2018, 12, 10, 19, 43), tt(2018, 12, 13, 15, 15)),
554548

555549
// Period is day when time is not present
556-
tsd("12th March 2010", tt(2010, 3, 12, 0, 0)),
557-
tsd("21-12-19", tt(2019, 12, 21, 0, 0)),
550+
ts("12th March 2010", date.Day, tt(2010, 3, 12, 0, 0)),
551+
ts("21-12-19", date.Day, tt(2019, 12, 21, 0, 0)),
558552
}
559553

560554
// Prepare config

0 commit comments

Comments
 (0)