A Go library that parses human-readable date/time strings into time.Time objects, inspired by PHP's strtotime() function.
- Parses natural language date/time expressions
- Supports relative dates ("tomorrow", "next Friday", "+2 days")
- Handles various date formats (ISO, US, European)
- Custom base time reference support
- Timezone specification (3-letter codes and IANA timezone names)
- Extensible architecture
go get github.com/KarpelesLab/strtotimepackage main
import (
"fmt"
"time"
"github.com/KarpelesLab/strtotime"
)
func main() {
// Parse a simple date string
t, err := strtotime.StrToTime("2023-05-15")
if err != nil {
fmt.Printf("Error: %s\n", err)
return
}
fmt.Printf("Date: %s\n", t.Format("2006-01-02 15:04:05"))
// Parse a relative date using the current time as reference
t, err = strtotime.StrToTime("tomorrow")
if err != nil {
fmt.Printf("Error: %s\n", err)
return
}
fmt.Printf("Tomorrow: %s\n", t.Format("2006-01-02"))
// Parse a more complex expression
t, err = strtotime.StrToTime("next Friday +2 weeks")
if err != nil {
fmt.Printf("Error: %s\n", err)
return
}
fmt.Printf("Next Friday +2 weeks: %s\n", t.Format("2006-01-02"))
}You can customize parsing behavior with options:
package main
import (
"fmt"
"time"
"github.com/KarpelesLab/strtotime"
)
func main() {
// Set a specific base time for relative calculations
baseTime := time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC)
t, err := strtotime.StrToTime("next month", strtotime.Rel(baseTime))
if err != nil {
fmt.Printf("Error: %s\n", err)
return
}
fmt.Printf("Next month from 2023-01-01: %s\n", t.Format("2006-01-02"))
// Specify a timezone as an option
loc, _ := time.LoadLocation("America/New_York")
t, err = strtotime.StrToTime("today", strtotime.InTZ(loc))
if err != nil {
fmt.Printf("Error: %s\n", err)
return
}
fmt.Printf("Today in New York: %s\n", t.Format("2006-01-02 15:04:05 MST"))
// Or specify timezone in the string
t, err = strtotime.StrToTime("January 1 2023 EST")
if err != nil {
fmt.Printf("Error: %s\n", err)
return
}
fmt.Printf("Date with timezone: %s\n", t.Format("2006-01-02 15:04:05 MST"))
// Combine multiple options
t, err = strtotime.StrToTime("tomorrow", strtotime.Rel(baseTime), strtotime.InTZ(loc))
if err != nil {
fmt.Printf("Error: %s\n", err)
return
}
fmt.Printf("Tomorrow from 2023-01-01 in New York: %s\n", t.Format("2006-01-02 15:04:05 MST"))
}DateParse(str) returns a *ParsedDate describing exactly which components
were present in the input — equivalent to PHP's date_parse(). Unlike
StrToTime, it does not fold relative offsets into a time.Time; it
reports them in a nested relative block.
pd := strtotime.DateParse("2006-12-12T10:00:00.5+01:00")
b, _ := json.Marshal(pd)
fmt.Println(string(b))
// {"year":2006,"month":12,"day":12,"hour":10,"minute":0,"second":0,
// "fraction":0.5,"warning_count":0,"warnings":[],"error_count":0,
// "errors":[],"is_localtime":true,"zone_type":1,"zone":3600,
// "is_dst":false}Unset scalar fields marshal as false, matching PHP. Timezone metadata
follows PHP's zone_type: 1 for UTC offsets, 2 for abbreviations, 3
for IANA identifiers. The relative block is included only when the input
contained relative offsets (+3 days, next monday, …). You can
materialize a ParsedDate back into a time.Time with pd.Time(loc) or
pd.Materialize(now, loc).
The library can understand many different formats and expressions, including:
now- current timetoday- current date at midnighttomorrow- tomorrow at midnightyesterday- yesterday at midnight
next Monday,last Friday- next/last occurrence of a weekdaynext week,last week- next/last Mondaynext month,last month- same day next/last monthnext year,last year- same day next/last year
+1 day,-2 days- add/subtract specific time units+1 week,-3 weeks- with various time units (day, week, month, year, hour, minute, second)4 days- implicit positive adjustment (same as +4 days)
- ISO format:
2023-05-15 - Slash format:
2023/05/15 - US format:
05/15/2023 - European format:
15.05.2023 - With timezone:
January 1 2023 EST,June 1 1985 16:30:00 Europe/Paris
- Full names:
January 15 2023 - Abbreviated:
Jan 15, 2023 - With/without commas:
Jan 15 2023 - With ordinal suffixes:
April 4th - Month only:
January(first day of the month in current year)
next year + 4 daysnext month - 1 weeknext week + 3 daystomorrow + 12 hours- Complex combinations:
next year + 1 month + 1 week
The library recognizes various formats for time units:
- Standard forms: day, week, month, year, hour, minute, second
- Plural forms: days, weeks, months, years, hours, minutes, seconds
- Abbreviations: d, w, wk, m, y, yr, h, hr, min, sec
- Common variations: hrs, mon, mins, secs
The library supports multiple timezone formats:
- 3-letter abbreviations:
EST,PST,GMT,UTC, etc. - IANA timezone names:
America/New_York,Europe/Paris,Asia/Tokyo, etc. - Timezone can be specified in the string:
January 1 2023 EST,June 1 1985 16:30:00 Europe/Paris - Timezone can also be provided as an option:
strtotime.InTZ(loc)
The library returns detailed error messages when it fails to parse a string:
t, err := strtotime.StrToTime("invalid date format")
if err != nil {
fmt.Printf("Error: %s\n", err)
// Handle the error
}This library is available under the LICENSE included in the repository.
Contributions are welcome! Please feel free to submit a Pull Request.