Passed
Push — v3.0.0 ( 5b9f70...671bfc )
by Serhii
01:19
created

timeago.generateTimeUnit   D

Complexity

Conditions 12

Size

Total Lines 27
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 12
eloc 22
nop 1
dl 0
loc 27
rs 4.8
c 0
b 0
f 0

How to fix   Complexity   

Complexity

Complex classes like timeago.generateTimeUnit often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

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