Skip to content

Commit 034e7da

Browse files
Merge pull request #29 from merschformann/merschformann/request-external-tzs
Adds support for explicit TZ conversion requests
2 parents 504169b + 9d5ab7d commit 034e7da

File tree

8 files changed

+94
-21
lines changed

8 files changed

+94
-21
lines changed

README.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ Show arbitrary time:
3737
gotz 21
3838
```
3939

40-
![preview](material/screenshot/gotz-15.png)
40+
![preview](material/screenshot/gotz-15-1.png)
4141

4242
Show arbitrary time using different timezone (index based):
4343

@@ -47,6 +47,14 @@ gotz 15@2
4747

4848
![preview](material/screenshot/gotz-15-2.png)
4949

50+
Show arbitrary time using different timezone (explicit TZ code):
51+
52+
```bash
53+
gotz 15@Asia/Tokyo
54+
```
55+
56+
![preview](material/screenshot/gotz-15-3.png)
57+
5058
Time can be one of the following formats:
5159

5260
```txt

core/args.go

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ func ParseFlags(startConfig Config, appVersion string) (Config, time.Time, bool,
202202
// Handle direct flags
203203
if requestTime != "" {
204204
// Parse time
205-
rTime, err := parseRequestTime(startConfig, requestTime)
205+
rTime, err := ParseRequestTime(startConfig, requestTime)
206206
if err != nil {
207207
return startConfig, rt, changed, err
208208
}
@@ -216,7 +216,7 @@ func ParseFlags(startConfig Config, appVersion string) (Config, time.Time, bool,
216216
// If last argument is a time, parse it
217217
if len(lastArg) > 0 && lastArg[0] >= '0' && lastArg[0] <= '9' {
218218
// Parse time
219-
rTime, err := parseRequestTime(startConfig, lastArg)
219+
rTime, err := ParseRequestTime(startConfig, lastArg)
220220
if err != nil {
221221
return startConfig, rt, changed, err
222222
}
@@ -279,36 +279,46 @@ type inputTimeFormat struct {
279279
TZInfo bool
280280
}
281281

282-
// parseRequestTime parses a requested time in various formats. Furthermore, it
282+
// ParseRequestTime parses a requested time in various formats. Furthermore, it
283283
// reads an optional timezone index and uses its timezone instead of local.
284-
func parseRequestTime(config Config, t string) (time.Time, error) {
284+
func ParseRequestTime(config Config, t string) (time.Time, error) {
285285
tzSeparator := "@"
286286
tz := time.Local
287287
// Check whether a different time zone than the local one was specified.
288288
if strings.Contains(t, tzSeparator) {
289289
// Split time and timezone
290290
parts := strings.Split(t, tzSeparator)
291291
if len(parts) != 2 {
292-
return time.Time{}, fmt.Errorf("invalid time format: %s (should be <timezone-index>/<time>)", t)
292+
return time.Time{}, fmt.Errorf("invalid time format: %s (should be <time>@<timezone-index> or <time>@<timezone-identifier>)", t)
293293
}
294-
// Parse timezone index
295-
tzIndex, err := strconv.Atoi(parts[1])
296-
if err != nil {
297-
return time.Time{}, fmt.Errorf("invalid time format: %s (should be <timezone-index>/<time>)", t)
298-
}
299-
if tzIndex < 0 || tzIndex > len(config.Timezones) {
300-
return time.Time{}, fmt.Errorf("invalid time format: %s (timezone-index out of range)", t)
301-
}
302-
t = parts[0]
303-
// Get timezone at index (offset by one to account for 0 as local timezone)
304-
if tzIndex > 0 {
305-
tz, err = time.LoadLocation(config.Timezones[tzIndex-1].TZ)
294+
if checkTimezoneLocation(parts[1]) {
295+
// >>> Handle the explicitly given timezone
296+
explicitTZ, err := time.LoadLocation(parts[1])
297+
if err == nil {
298+
// Use explicit timezone
299+
tz = explicitTZ
300+
}
301+
} else {
302+
// >>> Handle the timezone index referring to the configured TZs
303+
tzIndex, err := strconv.Atoi(parts[1])
306304
if err != nil {
307-
return time.Time{}, fmt.Errorf("invalid timezone: %s (given index %d)",
308-
config.Timezones[tzIndex-1].TZ,
309-
tzIndex)
305+
return time.Time{}, fmt.Errorf("invalid time format: %s (should be <time>@<timezone-index> or <time>@<timezone-identifier>)", t)
306+
}
307+
if tzIndex < 0 || tzIndex > len(config.Timezones) {
308+
return time.Time{}, fmt.Errorf("invalid time format: %s (timezone-index out of range)", t)
309+
}
310+
// Get timezone at index (offset by one to account for 0 as local timezone)
311+
if tzIndex > 0 {
312+
tz, err = time.LoadLocation(config.Timezones[tzIndex-1].TZ)
313+
if err != nil {
314+
return time.Time{}, fmt.Errorf("invalid timezone: %s (given index %d)",
315+
config.Timezones[tzIndex-1].TZ,
316+
tzIndex)
317+
}
310318
}
311319
}
320+
// Keep time element
321+
t = parts[0]
312322
}
313323
// Parse time
314324
rt, err := parseTime(t, tz)

material/screenshot/gotz-15-1.png

37.2 KB
Loading

material/screenshot/gotz-15-2.png

6.76 KB
Loading

material/screenshot/gotz-15-3.png

38.6 KB
Loading

material/screenshot/gotz-15.png

-30.4 KB
Binary file not shown.

material/screenshot/gotz.png

6.57 KB
Loading

tests/request_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package core_test
2+
3+
import (
4+
"testing"
5+
"time"
6+
7+
"github.com/merschformann/gotz/core"
8+
)
9+
10+
func TestParseRequest(t *testing.T) {
11+
defaultConfig := core.DefaultConfig()
12+
londonTZ, _ := time.LoadLocation("Europe/London")
13+
berlinTZ, _ := time.LoadLocation("Europe/Berlin")
14+
// Define test cases
15+
tests := []struct {
16+
name string
17+
input string
18+
expected time.Time
19+
}{
20+
{
21+
name: "London",
22+
input: "1100@Europe/London",
23+
expected: time.Date(2023, 10, 1, 11, 0, 0, 0, londonTZ),
24+
},
25+
{
26+
name: "Berlin",
27+
input: "7pm@Europe/Berlin",
28+
expected: time.Date(2023, 10, 1, 19, 0, 0, 0, berlinTZ),
29+
},
30+
{
31+
name: "BerlinIndexed",
32+
input: "7pm@2",
33+
expected: time.Date(2023, 10, 1, 19, 0, 0, 0, berlinTZ),
34+
},
35+
}
36+
37+
for _, test := range tests {
38+
t.Run(test.name, func(t *testing.T) {
39+
// Parse the request
40+
parsedTime, err := core.ParseRequestTime(defaultConfig, test.input)
41+
if err != nil {
42+
t.Fatalf("Error parsing request: %v", err)
43+
}
44+
// Check if the parsed time matches the expected time (ignore the
45+
// date)
46+
if parsedTime.Hour() != test.expected.Hour() || parsedTime.Minute() != test.expected.Minute() {
47+
t.Errorf("Expected %v, got %v", test.expected, parsedTime)
48+
}
49+
// Check if the timezone matches the expected timezone
50+
if parsedTime.Location().String() != test.expected.Location().String() {
51+
t.Errorf("Expected timezone %v, got %v", test.expected.Location(), parsedTime.Location())
52+
}
53+
})
54+
}
55+
}

0 commit comments

Comments
 (0)