Add prefer-day-first flag and relatedto example program

Support --prefer-day-first and --retry-ambiguous flags for example
program. Also provide an example where parsing would fail without it.
This commit is contained in:
Klondike Dragon 2025-04-12 12:27:56 -06:00
parent eeb01af691
commit fe33a563db
4 changed files with 77 additions and 9 deletions

3
.gitignore vendored
View File

@ -1,4 +1,5 @@
*.pprof
*.test
dist
vendor
vendor
dateparse/dateparse

View File

@ -6,7 +6,7 @@ Go Date Parser
Parse date/time strings without knowing the format in advance. Supports 100+ formats. Validates comprehensively to avoid false positives. Very fast (~single-pass state-machine based approach). See [bench_test.go](https://github.com/itlightning/dateparse/blob/main/bench_test.go) for performance comparison. See the critical note below about timezones.
⚡ Maintained by [IT Lightning](https://itlightning.com/), a cloud-first logging platform that's uniquely powerful, super-easy (schemaless, point-and-shoot ingestion), and affordable. It automatically extracts and classifies structured data out of your unstructured log messages. Enjoy visual pattern-analysis and robust SQL-like search. It's unique architecture means you can log more and pay less. Check it out and give us feedback! ⚡
⚡ Maintained by [SparkLogs](https://sparklogs.com/), a cloud-first logging platform that's uniquely powerful, super-easy (schemaless, point-and-shoot ingestion), and affordable. It automatically extracts and classifies structured data out of your unstructured log messages. Enjoy visual pattern-analysis and robust SQL-like search. It's unique architecture means you can log more and pay less. Check it out and give us feedback! SparkLogs is developed by [IT Lightning](https://itlightning.com/).
🐛💡 Find a bug or have an idea with this package? [Issues](https://github.com/itlightning/dateparse/issues) and pull requests are welcome.
@ -75,6 +75,14 @@ cli tool for testing dateformats
[Date Parse CLI](https://github.com/itlightning/dateparse/tree/main/dateparse)
Running the tests
----------------------------------
Make sure for your Linux distribution you've installed the relevant package that includes older timezone name links (e.g., `US/Pacific`). For example, on Ubuntu:
```bash
sudo apt install tzdata-legacy
```
Extended example
-------------------

View File

@ -169,4 +169,44 @@ Your Using time.Local set to location=America/New_York EDT
| ParseAny | time.Local = time.UTC | 2017-03-03 00:00:00 +0000 UTC | 2017-03-03 00:00:00 +0000 UTC day=5 |
+-------------+---------------------------+----------------------------------------------------+----------------------------------------------------+
# Automatically retry date formats that are ambiguous mm/dd vs dd/mm
$ ./dateparse --retry-ambiguous "28.09.2024"
Your Current time.Local zone is MDT
Layout String: dateparse.ParseFormat() => 02.01.2006
+-------------+-----------------------+----------------------------------------------------+----------------------------------------------------+
| method | Zone Source | Parsed | Parsed: t.In(time.UTC) |
+-------------+-----------------------+----------------------------------------------------+----------------------------------------------------+
| ParseIn | time.Local = nil | 2024-09-28 00:00:00 +0000 UTC | 2024-09-28 00:00:00 +0000 UTC |
| ParseIn | time.Local = time.UTC | 2024-09-28 00:00:00 +0000 UTC | 2024-09-28 00:00:00 +0000 UTC |
| ParseLocal | time.Local = nil | 2024-09-28 00:00:00 +0000 UTC | 2024-09-28 00:00:00 +0000 UTC |
| ParseLocal | time.Local = time.UTC | 2024-09-28 00:00:00 +0000 UTC | 2024-09-28 00:00:00 +0000 UTC |
| ParseStrict | time.Local = nil | this date has ambiguous mm/dd vs dd/mm type format | this date has ambiguous mm/dd vs dd/mm type format |
| ParseStrict | time.Local = time.UTC | this date has ambiguous mm/dd vs dd/mm type format | this date has ambiguous mm/dd vs dd/mm type format |
| ParseAny | time.Local = nil | 2024-09-28 00:00:00 +0000 UTC | 2024-09-28 00:00:00 +0000 UTC day=6 |
| ParseAny | time.Local = time.UTC | 2024-09-28 00:00:00 +0000 UTC | 2024-09-28 00:00:00 +0000 UTC day=6 |
+-------------+-----------------------+----------------------------------------------------+----------------------------------------------------+
# Force dates to be interpreted as day-first instead of month-first
$ ./dateparse --prefer-day-first "28.09.2024"
Your Current time.Local zone is MDT
Layout String: dateparse.ParseFormat() => 02.01.2006
+-------------+-----------------------+----------------------------------------------------+----------------------------------------------------+
| method | Zone Source | Parsed | Parsed: t.In(time.UTC) |
+-------------+-----------------------+----------------------------------------------------+----------------------------------------------------+
| ParseAny | time.Local = nil | 2024-09-28 00:00:00 +0000 UTC | 2024-09-28 00:00:00 +0000 UTC day=6 |
| ParseAny | time.Local = time.UTC | 2024-09-28 00:00:00 +0000 UTC | 2024-09-28 00:00:00 +0000 UTC day=6 |
| ParseIn | time.Local = nil | 2024-09-28 00:00:00 +0000 UTC | 2024-09-28 00:00:00 +0000 UTC |
| ParseIn | time.Local = time.UTC | 2024-09-28 00:00:00 +0000 UTC | 2024-09-28 00:00:00 +0000 UTC |
| ParseLocal | time.Local = nil | 2024-09-28 00:00:00 +0000 UTC | 2024-09-28 00:00:00 +0000 UTC |
| ParseLocal | time.Local = time.UTC | 2024-09-28 00:00:00 +0000 UTC | 2024-09-28 00:00:00 +0000 UTC |
| ParseStrict | time.Local = nil | this date has ambiguous mm/dd vs dd/mm type format | this date has ambiguous mm/dd vs dd/mm type format |
| ParseStrict | time.Local = time.UTC | this date has ambiguous mm/dd vs dd/mm type format | this date has ambiguous mm/dd vs dd/mm type format |
+-------------+-----------------------+----------------------------------------------------+----------------------------------------------------+
```

View File

@ -11,12 +11,27 @@ import (
)
var (
timezone = ""
datestr = ""
timezone = ""
datestr = ""
retryAmbiguousDateWithSwap = false
preferDayFirst = false
parserOptions = []dateparse.ParserOption{}
)
func buildParserOptions() {
parserOptions = []dateparse.ParserOption{}
if retryAmbiguousDateWithSwap {
parserOptions = append(parserOptions, dateparse.RetryAmbiguousDateWithSwap(true))
}
if preferDayFirst {
parserOptions = append(parserOptions, dateparse.PreferMonthFirst(false))
}
}
func main() {
flag.StringVar(&timezone, "timezone", "", "Timezone aka `America/Los_Angeles` formatted time-zone")
flag.BoolVar(&retryAmbiguousDateWithSwap, "retry-ambiguous", false, "Retry ambiguous date/time formats (day-first vs month-first)")
flag.BoolVar(&preferDayFirst, "prefer-day-first", false, "Prefer day-first date format")
flag.Parse()
if len(flag.Args()) == 0 {
@ -25,13 +40,17 @@ func main() {
./dateparse "2009-08-12T22:15:09.99Z"
./dateparse --timezone="America/Denver" "2017-07-19 03:21:51+00:00"
./dateparse --prefer-day-first "28.09.2024"
./dateparse --retry-ambiguous "28.09.2024"
`)
return
}
buildParserOptions()
datestr = flag.Args()[0]
layout, err := dateparse.ParseFormat(datestr)
layout, err := dateparse.ParseFormat(datestr, parserOptions...)
if err != nil {
fatal(err)
}
@ -82,7 +101,7 @@ type parser func(datestr string, loc *time.Location, utc bool) string
func parseLocal(datestr string, loc *time.Location, utc bool) string {
time.Local = loc
t, err := dateparse.ParseLocal(datestr)
t, err := dateparse.ParseLocal(datestr, parserOptions...)
if err != nil {
return err.Error()
}
@ -93,7 +112,7 @@ func parseLocal(datestr string, loc *time.Location, utc bool) string {
}
func parseIn(datestr string, loc *time.Location, utc bool) string {
t, err := dateparse.ParseIn(datestr, loc)
t, err := dateparse.ParseIn(datestr, loc, parserOptions...)
if err != nil {
return err.Error()
}
@ -104,7 +123,7 @@ func parseIn(datestr string, loc *time.Location, utc bool) string {
}
func parseAny(datestr string, loc *time.Location, utc bool) string {
t, err := dateparse.ParseAny(datestr)
t, err := dateparse.ParseAny(datestr, parserOptions...)
if err != nil {
return err.Error()
}
@ -115,7 +134,7 @@ func parseAny(datestr string, loc *time.Location, utc bool) string {
}
func parseStrict(datestr string, loc *time.Location, utc bool) string {
t, err := dateparse.ParseStrict(datestr)
t, err := dateparse.ParseStrict(datestr, parserOptions...)
if err != nil {
return err.Error()
}