Passed
Push — v3.0.0 ( 4fda89...e47893 )
by Serhii
01:18
created

timeago.identifyLocaleForm   B

Complexity

Conditions 6

Size

Total Lines 17
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 14
nop 1
dl 0
loc 17
rs 8.6666
c 0
b 0
f 0
1
package timeago
2
3
import (
4
	"log"
5
	"math"
6
	"strconv"
7
	"time"
8
9
	"github.com/SerhiiCho/timeago/v3/config"
10
	"github.com/SerhiiCho/timeago/v3/ctx"
11
	locale "github.com/SerhiiCho/timeago/v3/langset"
12
	"github.com/SerhiiCho/timeago/v3/option"
13
)
14
15
var cachedJsonResults = map[string]locale.LocaleSet{}
16
var options = []option.Option{}
17
var localeSet *locale.LocaleSet
18
19
var conf = &config.Config{
20
	Language:     "en",
21
	Location:     "",
22
	Translations: []config.Translation{},
23
}
24
25
// Parse coverts given datetime into `x time ago` format.
26
// First argument can have 3 types:
27
// 1. int (Unix timestamp)
28
// 2. time.Time (Type from Go time package)
29
// 3. string (Datetime string in format 'YYYY-MM-DD HH:MM:SS')
30
func Parse(datetime interface{}, opts ...option.Option) string {
31
	var input time.Time
32
33
	switch date := datetime.(type) {
34
	case int:
35
		input = parseTimestampIntoTime(date)
36
	case string:
37
		input = parseStrIntoTime(date)
38
	default:
39
		input = datetime.(time.Time)
40
	}
41
42
	enableOptions(opts)
43
44
	return calculateTimeAgo(input)
45
}
46
47
func Configure(c *config.Config) {
48
	if c.Language != "" {
49
		conf.Language = c.Language
50
	}
51
52
	if c.Location != "" {
53
		conf.Location = c.Location
54
	}
55
56
	if len(c.Translations) > 0 {
57
		conf.Translations = c.Translations
58
	}
59
}
60
61
func parseStrIntoTime(datetime string) time.Time {
62
	if !conf.LocationIsSet() {
63
		parsedTime, _ := time.Parse("2006-01-02 15:04:05", datetime)
64
		return parsedTime
65
	}
66
67
	location, err := time.LoadLocation(conf.Location)
68
69
	if err != nil {
70
		log.Fatalf("Error in timeago package: %v", err)
71
	}
72
73
	parsedTime, _ := time.ParseInLocation("2006-01-02 15:04:05", datetime, location)
74
75
	return parsedTime
76
}
77
78
func calculateTimeAgo(datetime time.Time) string {
79
	now := time.Now()
80
81
	if conf.LocationIsSet() {
82
		now = applyLocationToTime(now)
83
	}
84
85
	seconds := now.Sub(datetime).Seconds()
86
87
	if seconds < 0 {
88
		enableOption(option.Upcoming)
89
		seconds = math.Abs(seconds)
90
	}
91
92
	context := ctx.New(conf, options)
93
	localeSet = locale.New(context)
94
95
	switch {
96
	case seconds < 60 && optionIsEnabled("online"):
97
		return localeSet.Online
98
	case seconds < 0:
99
		return getWords(localeSet.Second, 0)
100
	}
101
102
	timeUnit := generateTimeUnit(int(seconds))
103
104
	return timeUnit
105
}
106
107
func generateTimeUnit(seconds int) string {
108
	minutes, hours, days, weeks, months, years := getTimeCalculations(float64(seconds))
109
110
	switch {
111
	case optionIsEnabled("online") && seconds < 60:
112
		return localeSet.Online
113
	case optionIsEnabled("justNow") && seconds < 60:
114
		return localeSet.JustNow
115
	case seconds < 60:
116
		return getWords(localeSet.Second, seconds)
117
	case minutes < 60:
118
		return getWords(localeSet.Minute, minutes)
119
	case hours < 24:
120
		return getWords(localeSet.Hour, hours)
121
	case days < 7:
122
		return getWords(localeSet.Day, days)
123
	case weeks < 4:
124
		return getWords(localeSet.Week, weeks)
125
	case months < 12:
126
		if months == 0 {
127
			months = 1
128
		}
129
130
		return getWords(localeSet.Month, months)
131
	}
132
133
	return getWords(localeSet.Year, years)
134
}
135
136
// getWords decides rather the word must be singular or plural,
137
// and depending on the result it adds the correct word after
138
// the time number
139
func getWords(final locale.LocaleForms, num int) string {
140
	form := identifyLocaleForm(num)
141
	time := getTimeTranslations()
142
143
	translation := time[timeUnit][form]
144
	result := strconv.Itoa(num) + " " + translation
145
146
	if optionIsEnabled("noSuffix") || optionIsEnabled("upcoming") {
147
		return result
148
	}
149
150
	return result
151
}
152
153
func identifyLocaleForm(num int) string {
154
	rule := identifyGrammarRules(num)[conf.Language]
155
156
	switch {
157
	case rule.Zero:
158
		return "zero"
159
	case rule.One:
160
		return "one"
161
	case rule.Few:
162
		return "few"
163
	case rule.Two:
164
		return "two"
165
	case rule.Many:
166
		return "many"
167
	}
168
169
	return "other"
170
}
171
172
func applyLocationToTime(datetime time.Time) time.Time {
173
	location, err := time.LoadLocation(conf.Location)
174
175
	if err != nil {
176
		log.Fatalf("Location error in timeago package: %v\n", err)
177
	}
178
179
	return datetime.In(location)
180
}
181
182
func getTimeCalculations(seconds float64) (int, int, int, int, int, int) {
183
	minutes := math.Round(seconds / 60)
184
	hours := math.Round(seconds / 3600)
185
	days := math.Round(seconds / 86400)
186
	weeks := math.Round(seconds / 604800)
187
	months := math.Round(seconds / 2629440)
188
	years := math.Round(seconds / 31553280)
189
190
	return int(minutes), int(hours), int(days), int(weeks), int(months), int(years)
191
}
192