Passed
Push — master ( 1f1bc8...d1f21b )
by Serhii
49s queued 12s
created

timeago.go   A

Size/Duplication

Total Lines 154
Duplicated Lines 0 %

Test Coverage

Coverage 92.73%

Importance

Changes 0
Metric Value
cc 33
eloc 93
dl 0
loc 154
ccs 51
cts 55
cp 0.9273
crap 33.4184
rs 9.76
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
C timeago.getWords 0 16 9
A timeago.getLastNumber 0 5 1
A timeago.trans 0 20 4
A timeago.getOption 0 10 2
A timeago.getTimeCalculations 0 9 1
C timeago.calculateTheResult 0 25 11
A timeago.Take 0 15 4
A timeago.getTimeTranslations 0 9 1
1
package timeago
2
3
import (
4
	"fmt"
5
	"log"
6
	"math"
7
	"os"
8
	"strconv"
9
	"strings"
10
	"time"
11
12
	"github.com/SerhiiCho/timeago/models"
13
	"github.com/SerhiiCho/timeago/utils"
14
)
15
16
// Take coverts given datetime into `x time ago` format.
17
// For displaying `Online` word if date interval within
18
// 60 seconds, add `|online` flag to the datetime string.
19
// Format must be [year-month-day hours:minutes:seconds}
20
func Take(datetime string) string {
21 1
	option, hasOption := getOption(&datetime)
22
23 1
	loc, _ := time.LoadLocation(location)
24 1
	parsedTime, _ := time.ParseInLocation("2006-01-02 15:04:05", datetime, loc)
25 1
	seconds := int(time.Now().In(loc).Sub(parsedTime).Seconds())
26
27 1
	switch {
28
	case seconds < 0 && option == "online":
29 1
		return trans().Online
30
	case seconds < 0:
31 1
		return getWords("seconds", 0)
32
	}
33
34 1
	return calculateTheResult(seconds, hasOption, option)
35
}
36
37
func calculateTheResult(seconds int, hasOption bool, option string) string {
38 1
	minutes, hours, days, weeks, months, years := getTimeCalculations(float64(seconds))
39
40 1
	switch {
41
	case hasOption && option == "online" && seconds < 60:
42 1
		return trans().Online
43
	case seconds < 60:
44 1
		return getWords("seconds", seconds)
45
	case minutes < 60:
46 1
		return getWords("minutes", minutes)
47
	case hours < 24:
48 1
		return getWords("hours", hours)
49
	case days < 7:
50 1
		return getWords("days", days)
51
	case weeks < 4:
52 1
		return getWords("weeks", weeks)
53
	case months < 12:
54 1
		if months == 0 {
55
			months = 1
56
		}
57
58 1
		return getWords("months", months)
59
	}
60
61 1
	return getWords("years", years)
62
}
63
64
func getTimeCalculations(seconds float64) (int, int, int, int, int, int) {
65 1
	minutes := math.Round(seconds / 60)
66 1
	hours := math.Round(seconds / 3600)
67 1
	days := math.Round(seconds / 86400)
68 1
	weeks := math.Round(seconds / 604800)
69 1
	months := math.Round(seconds / 2629440)
70 1
	years := math.Round(seconds / 31553280)
71
72 1
	return int(minutes), int(hours), int(days), int(weeks), int(months), int(years)
73
}
74
75
// get the last number of a given integer
76
func getLastNumber(num int) int {
77 1
	numStr := strconv.Itoa(num)
78 1
	result, _ := strconv.Atoi(numStr[len(numStr)-1:])
79
80 1
	return result
81
}
82
83
// getWords decides rather the word must be singular or plural,
84
// and depending on the result it adds the correct word after
85
// the time number
86
func getWords(timeKind string, num int) string {
87 1
	lastNum := getLastNumber(num)
88 1
	index := 2
89
90 1
	switch {
91
	case lastNum == 1 && num == 11:
92 1
		index = 2
93
	case lastNum == 1 && language == "ru" || num == 1 && language == "en":
94 1
		index = 0
95
	case lastNum > 1 && lastNum < 5:
96 1
		index = 1
97
	}
98
99 1
	timeTrans := getTimeTranslations()
100
101 1
	return strconv.Itoa(num) + " " + timeTrans[timeKind][index] + " " + trans().Ago
102
}
103
104
// getTimeTranslations returns array of translations for different
105
// cases. For example `1 second` must not have `s` at the end
106
// but `2 seconds` requires `s`. So this method keeps all
107
// possible options for the translated word.
108
func getTimeTranslations() map[string][]string {
109 1
	return map[string][]string{
110
		"seconds": {trans().Second, trans().Seconds, trans().Seconds2},
111
		"minutes": {trans().Minute, trans().Minutes, trans().Minutes2},
112
		"hours":   {trans().Hour, trans().Hours, trans().Hours2},
113
		"days":    {trans().Day, trans().Days, trans().Days2},
114
		"weeks":   {trans().Week, trans().Weeks, trans().Weeks2},
115
		"months":  {trans().Month, trans().Months, trans().Months2},
116
		"years":   {trans().Year, trans().Years, trans().Years2},
117
	}
118
}
119
120
// getOption check if datetime has option with time,
121
// if yes, it will return this option and remove it
122
// from datetime
123
func getOption(datetime *string) (string, bool) {
124 1
	date := *datetime
125 1
	spittedDateString := strings.Split(date, "|")
126
127 1
	if len(spittedDateString) > 1 {
128 1
		*datetime = spittedDateString[0]
129 1
		return spittedDateString[1], true
130
	}
131
132 1
	return "", false
133
}
134
135
func trans() models.Lang {
136 1
	path, err := os.Getwd()
137
138 1
	if err != nil {
139
		log.Println(err)
140
	}
141
142 1
	filePath := fmt.Sprintf(path+"/langs/%s.json", language)
143
144 1
	thereIsFile, err := utils.FileExists(filePath)
145
146 1
	if !thereIsFile {
147
		log.Fatalf("File with the path: %s, doesn't exist", filePath)
148
	}
149
150 1
	if err != nil {
151
		log.Fatalf("Error while trying to read file %s. Error: %v", filePath, err)
152
	}
153
154 1
	return parseNeededFile(filePath)
155
}
156