Skip to content

Commit df7d70e

Browse files
authored
Merge pull request #46 from SerhiiCho/v3.3.0
V3.3.0
2 parents dde30f4 + 1d88095 commit df7d70e

9 files changed

Lines changed: 200 additions & 119 deletions

File tree

.github/workflows/go.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
runs-on: ubuntu-latest
1313
strategy:
1414
matrix:
15-
go_version: ['1.16', '1.17', '1.18', '1.19', '1.20', '1.21', '1.22', '1.23']
15+
go_version: ['1.16', '1.17', '1.18', '1.19', '1.20', '1.21', '1.22', '1.23', '1.24']
1616

1717
steps:
1818
- name: Check out code into the Go module directory

.vscode/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"cSpell.words": [
33
"datetime",
44
"justnow",
5+
"nums",
56
"timeago"
67
]
78
}

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# Release Notes v3
22

3+
## v3.3.0 (2025-06-16)
4+
- Now you can parse different times of timestamps, such as `string`, `int64`, `uint`, `uint64`, `int32`, `uint32`
5+
36
## v3.2.2 (2025-06-04)
47
- Change so that all JSON files are included in the final binary by using `go:embed` functionality
58
- Remove support for go version 1.13, 1.14, 1.15 because they do not have `go:embed`

internal/utils/duration.go

Lines changed: 0 additions & 57 deletions
This file was deleted.

internal/utils/utils.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,68 @@ import (
55
"time"
66
)
77

8+
const (
9+
second time.Duration = time.Second
10+
minute time.Duration = time.Minute
11+
hour time.Duration = time.Hour
12+
day time.Duration = hour * 24
13+
week time.Duration = day * 7
14+
month time.Duration = day * 30
15+
year time.Duration = day * 365
16+
)
17+
818
func UnixFromPastDate(subDuration time.Duration) int {
919
return int(SubTime(subDuration).UnixNano() / 1000000000)
1020
}
1121

22+
func UnixFromFutureDate(duration time.Duration) int {
23+
return int(AddTime(duration).UnixNano() / 1000000000)
24+
}
25+
1226
func Errorf(msg string, a ...interface{}) error {
1327
return fmt.Errorf("[Timeago]: "+msg, a...)
1428
}
29+
30+
func SubTime(duration time.Duration) time.Time {
31+
return time.Now().Add(-duration)
32+
}
33+
34+
func AddTime(duration time.Duration) time.Time {
35+
return time.Now().Add(duration)
36+
}
37+
38+
func SubSeconds(duration time.Duration) time.Time {
39+
return SubTime(second * duration)
40+
}
41+
42+
func SubMinutes(duration time.Duration) time.Time {
43+
return SubTime(minute * duration)
44+
}
45+
46+
func AddMinutes(duration time.Duration) time.Time {
47+
return AddTime(minute * duration)
48+
}
49+
50+
func SubHours(duration time.Duration) time.Time {
51+
return SubTime(hour * duration)
52+
}
53+
54+
func AddHours(duration time.Duration) time.Time {
55+
return AddTime(hour * duration)
56+
}
57+
58+
func SubDays(duration time.Duration) time.Time {
59+
return SubTime(day * duration)
60+
}
61+
62+
func SubWeeks(duration time.Duration) time.Time {
63+
return SubTime(week * duration)
64+
}
65+
66+
func SubMonths(duration time.Duration) time.Time {
67+
return SubTime(month * duration)
68+
}
69+
70+
func SubYears(duration time.Duration) time.Time {
71+
return SubTime(year * duration)
72+
}

timeago.go

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,11 @@ type timeNumbers struct {
3636
Years int
3737
}
3838

39-
// Parse coverts privided datetime into `x time ago` format.
40-
// The first argument can have 3 types:
41-
// 1. int (Unix timestamp)
42-
// 2. time.Time (Type from Go time package)
43-
// 3. string (Datetime string in format 'YYYY-MM-DD HH:MM:SS')
39+
// Parse coverts provided datetime into `x time ago` format.
40+
// The first argument can different types of inputs:
41+
// 1. Unix timestamp: int, int32, int64, unit, uint32, uint64, string
42+
// 2. Type from Go time package: time.Time
43+
// 3. Datetime string in format 'YYYY-MM-DD HH:MM:SS': string
4444
func Parse(date interface{}, opts ...opt) (string, error) {
4545
options = []opt{}
4646
langSet = nil
@@ -51,8 +51,22 @@ func Parse(date interface{}, opts ...opt) (string, error) {
5151
switch userDate := date.(type) {
5252
case int:
5353
t = unixToTime(userDate)
54+
case int32:
55+
t = unixToTime(int(userDate))
56+
case int64:
57+
t = unixToTime(int(userDate))
58+
case uint:
59+
t = unixToTime(int(userDate))
60+
case uint32:
61+
t = unixToTime(int(userDate))
62+
case uint64:
63+
t = unixToTime(int(userDate))
5464
case string:
55-
t, err = strToTime(userDate)
65+
if isUnsignedInteger(userDate) {
66+
t, err = strTimestampToTime(userDate)
67+
} else {
68+
t, err = strToTime(userDate)
69+
}
5670
default:
5771
t = date.(time.Time)
5872
}
@@ -104,6 +118,15 @@ func defaultConfig() *Config {
104118
return NewConfig("en", "UTC", []LangSet{}, 60, 60)
105119
}
106120

121+
func strTimestampToTime(userDate string) (time.Time, error) {
122+
sec, err := strconv.Atoi(userDate)
123+
if err != nil {
124+
return time.Time{}, err
125+
}
126+
127+
return unixToTime(sec), nil
128+
}
129+
107130
func strToTime(userDate string) (time.Time, error) {
108131
if !conf.isLocationProvided() {
109132
parsedTime, _ := time.Parse(time.DateTime, userDate)

timeago_test.go

Lines changed: 92 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
package timeago
22

33
import (
4+
"strconv"
45
"testing"
56
"time"
67

78
"github.com/SerhiiCho/timeago/v3/internal/utils"
89
)
910

10-
func TestParseFunctionCanExceptTimestamp(t *testing.T) {
11+
func TestParse(t *testing.T) {
1112
cases := []struct {
12-
date int
13+
date interface{}
1314
res string
1415
}{
15-
{utils.UnixFromPastDate(time.Minute), "1 minute ago"},
16+
// Integer timestamp input parsing
1617
{utils.UnixFromPastDate(time.Minute * 5), "5 minutes ago"},
1718
{utils.UnixFromPastDate(time.Hour), "1 hour ago"},
1819
{utils.UnixFromPastDate(time.Hour * 3), "3 hours ago"},
@@ -24,31 +25,79 @@ func TestParseFunctionCanExceptTimestamp(t *testing.T) {
2425
{utils.UnixFromPastDate(time.Hour * 24 * 5), "5 days ago"},
2526
{utils.UnixFromPastDate(time.Hour * 24 * 6), "6 days ago"},
2627
{utils.UnixFromPastDate(time.Hour * 24 * 7), "1 week ago"},
27-
}
28-
29-
Reconfigure(Config{Language: LangEn})
30-
31-
for _, tc := range cases {
32-
t.Run(tc.res, func(t *testing.T) {
33-
res, err := Parse(tc.date)
34-
35-
if err != nil {
36-
t.Errorf("Error must be nil, but got %q instead", err)
37-
}
38-
39-
if res != tc.res {
40-
t.Errorf("Result must be %q, but got %q instead", tc.res, res)
41-
}
42-
})
43-
}
44-
}
45-
46-
func TestParseFunctionCanExceptTimePackage(t *testing.T) {
47-
cases := []struct {
48-
date time.Time
49-
res string
50-
}{
51-
{utils.SubMinutes(1), "1 minute ago"},
28+
// Integer 64 timestamp input parsing
29+
{int64(utils.UnixFromPastDate(time.Minute * 5)), "5 minutes ago"},
30+
{int64(utils.UnixFromPastDate(time.Hour)), "1 hour ago"},
31+
{int64(utils.UnixFromPastDate(time.Hour * 3)), "3 hours ago"},
32+
{int64(utils.UnixFromPastDate(time.Hour * 5)), "5 hours ago"},
33+
{int64(utils.UnixFromPastDate(time.Hour * 24)), "1 day ago"},
34+
{int64(utils.UnixFromPastDate(time.Hour * 24 * 2)), "2 days ago"},
35+
{int64(utils.UnixFromPastDate(time.Hour * 24 * 3)), "3 days ago"},
36+
{int64(utils.UnixFromPastDate(time.Hour * 24 * 4)), "4 days ago"},
37+
{int64(utils.UnixFromPastDate(time.Hour * 24 * 5)), "5 days ago"},
38+
{int64(utils.UnixFromPastDate(time.Hour * 24 * 6)), "6 days ago"},
39+
{int64(utils.UnixFromPastDate(time.Hour * 24 * 7)), "1 week ago"},
40+
// Unsigned Integer timestamp input parsing
41+
{uint(utils.UnixFromPastDate(time.Minute * 5)), "5 minutes ago"},
42+
{uint(utils.UnixFromPastDate(time.Hour)), "1 hour ago"},
43+
{uint(utils.UnixFromPastDate(time.Hour * 3)), "3 hours ago"},
44+
{uint(utils.UnixFromPastDate(time.Hour * 5)), "5 hours ago"},
45+
{uint(utils.UnixFromPastDate(time.Hour * 24)), "1 day ago"},
46+
{uint(utils.UnixFromPastDate(time.Hour * 24 * 2)), "2 days ago"},
47+
{uint(utils.UnixFromPastDate(time.Hour * 24 * 3)), "3 days ago"},
48+
{uint(utils.UnixFromPastDate(time.Hour * 24 * 4)), "4 days ago"},
49+
{uint(utils.UnixFromPastDate(time.Hour * 24 * 5)), "5 days ago"},
50+
{uint(utils.UnixFromPastDate(time.Hour * 24 * 6)), "6 days ago"},
51+
{uint(utils.UnixFromPastDate(time.Hour * 24 * 7)), "1 week ago"},
52+
// Unsigned Integer 32 timestamp input parsing
53+
{uint32(utils.UnixFromPastDate(time.Minute * 5)), "5 minutes ago"},
54+
{uint32(utils.UnixFromPastDate(time.Hour)), "1 hour ago"},
55+
{uint32(utils.UnixFromPastDate(time.Hour * 3)), "3 hours ago"},
56+
{uint32(utils.UnixFromPastDate(time.Hour * 5)), "5 hours ago"},
57+
{uint32(utils.UnixFromPastDate(time.Hour * 24)), "1 day ago"},
58+
{uint32(utils.UnixFromPastDate(time.Hour * 24 * 2)), "2 days ago"},
59+
{uint32(utils.UnixFromPastDate(time.Hour * 24 * 3)), "3 days ago"},
60+
{uint32(utils.UnixFromPastDate(time.Hour * 24 * 4)), "4 days ago"},
61+
{uint32(utils.UnixFromPastDate(time.Hour * 24 * 5)), "5 days ago"},
62+
{uint32(utils.UnixFromPastDate(time.Hour * 24 * 6)), "6 days ago"},
63+
{uint32(utils.UnixFromPastDate(time.Hour * 24 * 7)), "1 week ago"},
64+
// Unsigned Integer 64 timestamp input parsing
65+
{uint64(utils.UnixFromPastDate(time.Minute * 5)), "5 minutes ago"},
66+
{uint64(utils.UnixFromPastDate(time.Hour)), "1 hour ago"},
67+
{uint64(utils.UnixFromPastDate(time.Hour * 3)), "3 hours ago"},
68+
{uint64(utils.UnixFromPastDate(time.Hour * 5)), "5 hours ago"},
69+
{uint64(utils.UnixFromPastDate(time.Hour * 24)), "1 day ago"},
70+
{uint64(utils.UnixFromPastDate(time.Hour * 24 * 2)), "2 days ago"},
71+
{uint64(utils.UnixFromPastDate(time.Hour * 24 * 3)), "3 days ago"},
72+
{uint64(utils.UnixFromPastDate(time.Hour * 24 * 4)), "4 days ago"},
73+
{uint64(utils.UnixFromPastDate(time.Hour * 24 * 5)), "5 days ago"},
74+
{uint64(utils.UnixFromPastDate(time.Hour * 24 * 6)), "6 days ago"},
75+
{uint64(utils.UnixFromPastDate(time.Hour * 24 * 7)), "1 week ago"},
76+
// Integer 32 timestamp input parsing
77+
{int32(utils.UnixFromPastDate(time.Minute * 5)), "5 minutes ago"},
78+
{int32(utils.UnixFromPastDate(time.Hour)), "1 hour ago"},
79+
{int32(utils.UnixFromPastDate(time.Hour * 3)), "3 hours ago"},
80+
{int32(utils.UnixFromPastDate(time.Hour * 5)), "5 hours ago"},
81+
{int32(utils.UnixFromPastDate(time.Hour * 24)), "1 day ago"},
82+
{int32(utils.UnixFromPastDate(time.Hour * 24 * 2)), "2 days ago"},
83+
{int32(utils.UnixFromPastDate(time.Hour * 24 * 3)), "3 days ago"},
84+
{int32(utils.UnixFromPastDate(time.Hour * 24 * 4)), "4 days ago"},
85+
{int32(utils.UnixFromPastDate(time.Hour * 24 * 5)), "5 days ago"},
86+
{int32(utils.UnixFromPastDate(time.Hour * 24 * 6)), "6 days ago"},
87+
{int32(utils.UnixFromPastDate(time.Hour * 24 * 7)), "1 week ago"},
88+
// Negative integer timestamp input parsing
89+
{utils.UnixFromFutureDate(time.Minute * 5), "5 minutes"},
90+
{utils.UnixFromFutureDate(time.Hour), "1 hour"},
91+
{utils.UnixFromFutureDate(time.Hour * 3), "3 hours"},
92+
{utils.UnixFromFutureDate(time.Hour * 5), "5 hours"},
93+
{utils.UnixFromFutureDate(time.Hour * 24), "1 day"},
94+
{utils.UnixFromFutureDate(time.Hour * 24 * 2), "2 days"},
95+
{utils.UnixFromFutureDate(time.Hour * 24 * 3), "3 days"},
96+
{utils.UnixFromFutureDate(time.Hour * 24 * 4), "4 days"},
97+
{utils.UnixFromFutureDate(time.Hour * 24 * 5), "5 days"},
98+
{utils.UnixFromFutureDate(time.Hour * 24 * 6), "6 days"},
99+
{utils.UnixFromFutureDate(time.Hour * 24 * 7), "1 week"},
100+
// time.Time input parsing
52101
{utils.SubMinutes(2), "2 minutes ago"},
53102
{utils.SubMinutes(3), "3 minutes ago"},
54103
{utils.SubMinutes(4), "4 minutes ago"},
@@ -59,42 +108,31 @@ func TestParseFunctionCanExceptTimePackage(t *testing.T) {
59108
{utils.SubHours(9), "9 hours ago"},
60109
{utils.SubHours(10), "10 hours ago"},
61110
{utils.SubHours(11), "11 hours ago"},
62-
}
63-
64-
Reconfigure(Config{Language: LangEn})
65-
66-
for _, tc := range cases {
67-
t.Run("Test for date "+tc.date.String(), func(t *testing.T) {
68-
res, err := Parse(tc.date)
69-
70-
if err != nil {
71-
t.Errorf("Error must be nil, but got %q instead", err)
72-
}
73-
74-
if res != tc.res {
75-
t.Errorf("Result must be %q, but got %q instead", tc.res, res)
76-
}
77-
})
78-
}
79-
}
80-
81-
func TestParseFuncWillCalculateIntervalToFutureDate(t *testing.T) {
82-
testCases := []struct {
83-
date time.Time
84-
res string
85-
}{
111+
// time.Time future date parsing
86112
{utils.AddMinutes(2), "2 minutes"},
87113
{utils.AddMinutes(5), "5 minutes"},
88114
{utils.AddMinutes(10), "10 minutes"},
89115
{utils.AddHours(1), "1 hour"},
90116
{utils.AddHours(24), "1 day"},
91117
{utils.AddHours(48), "2 days"},
118+
// Timestamp string input parsing
119+
{strconv.Itoa(utils.UnixFromPastDate(time.Minute * 5)), "5 minutes ago"},
120+
{strconv.Itoa(utils.UnixFromPastDate(time.Hour)), "1 hour ago"},
121+
{strconv.Itoa(utils.UnixFromPastDate(time.Hour * 3)), "3 hours ago"},
122+
{strconv.Itoa(utils.UnixFromPastDate(time.Hour * 5)), "5 hours ago"},
123+
{strconv.Itoa(utils.UnixFromPastDate(time.Hour * 24)), "1 day ago"},
124+
{strconv.Itoa(utils.UnixFromPastDate(time.Hour * 24 * 2)), "2 days ago"},
125+
{strconv.Itoa(utils.UnixFromPastDate(time.Hour * 24 * 3)), "3 days ago"},
126+
{strconv.Itoa(utils.UnixFromPastDate(time.Hour * 24 * 4)), "4 days ago"},
127+
{strconv.Itoa(utils.UnixFromPastDate(time.Hour * 24 * 5)), "5 days ago"},
128+
{strconv.Itoa(utils.UnixFromPastDate(time.Hour * 24 * 6)), "6 days ago"},
129+
{strconv.Itoa(utils.UnixFromPastDate(time.Hour * 24 * 7)), "1 week ago"},
92130
}
93131

94132
Reconfigure(Config{Language: LangEn})
95133

96-
for _, tc := range testCases {
97-
t.Run("Test for date: "+tc.date.String(), func(t *testing.T) {
134+
for _, tc := range cases {
135+
t.Run(tc.res, func(t *testing.T) {
98136
res, err := Parse(tc.date)
99137

100138
if err != nil {

0 commit comments

Comments
 (0)