Skip to content

Commit

Permalink
Make zone search a bit more useful
Browse files Browse the repository at this point in the history
Allow "-list" without a filter argument: this lists all the zones we
know of, and makes fuzzy searching with programs like fzf possible.

When -list *is* followed by another argument, tz will try to match on
the zone name, or abbreviated zone name in a case insensitive manner.

So far, -list results are sorted alphabetically. I think it could make
more sense to use the offset, but YMMV.
  • Loading branch information
oz committed Oct 19, 2022
1 parent bacd6cb commit d6c5408
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 29 deletions.
37 changes: 8 additions & 29 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import (

tea "github.com/charmbracelet/bubbletea"
"github.com/muesli/termenv"
"github.com/tkuchiki/go-timezone"
)

// CurrentVersion represents the current build version.
Expand Down Expand Up @@ -102,16 +101,21 @@ func main() {
exitQuick := flag.Bool("q", false, "exit immediately")
showVersion := flag.Bool("v", false, "show version")
when := flag.Int64("when", 0, "time in seconds since unix epoch")
search := flag.String("list", "", "find time zones by name")
doSearch := flag.Bool("list", false, "list zones by name")
flag.Parse()

if *showVersion == true {
fmt.Printf("tz %s\n", CurrentVersion)
os.Exit(0)
}

if *search != "" {
findZones(strings.ToLower(*search))
if *doSearch {
q := ""
if arg := flag.Arg(0); arg != "" {
q = arg
}
results := SearchZones(strings.ToLower(q))
results.Print(os.Stdout)
os.Exit(0)
}

Expand Down Expand Up @@ -143,28 +147,3 @@ func main() {
os.Exit(1)
}
}

func findZones(filter string) {
t := timezone.New()
matches := map[string]*timezone.TzInfo{}

for _, zones := range t.Timezones() {
for _, name := range zones {
if !strings.Contains(strings.ToLower(name), filter) {
continue
}

ti, err := t.GetTzInfo(name)
if err != nil {
panic(err)
}
matches[name] = ti
}
}
for name, ti := range matches {
fmt.Printf("%5s (%s) :: %s\n",
ti.ShortStandard(),
ti.StandardOffsetHHMM(),
name)
}
}
66 changes: 66 additions & 0 deletions search.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package main

import (
"fmt"
"io"
"sort"
"strings"

"github.com/tkuchiki/go-timezone"
)

// Zone search results
type ZoneSearchResults map[string]*timezone.TzInfo

// List of zones sorted alphabetically.
func (zsr ZoneSearchResults) SortedNames() []string {
sorted := make([]string, 0, len(zsr))
for name := range zsr {
sorted = append(sorted, name)
}
sort.Strings(sorted)

return sorted
}

// Print formatted ZoneSearchResults to the chosen Writer ; typically
// os.Stdout.
func (zsr ZoneSearchResults) Print(w io.Writer) {
sorted := zsr.SortedNames()
for i := range sorted {
name := sorted[i]
ti := zsr[name]
fmt.Fprintf(w, "%5s (%s) :: %s\n",
ti.ShortStandard(),
ti.StandardOffsetHHMM(),
name)
}
}

// Find zones matching a query. An empty query string returns all zones.
func SearchZones(q string) ZoneSearchResults {
// TODO Each call to timezone.New() allocs a fresh list of timezones:
// for now, avoid calling SearchZones too much.
t := timezone.New()
filter := q != ""
matches := map[string]*timezone.TzInfo{}

for abbr, zones := range t.Timezones() {
for _, name := range zones {
if filter &&
!strings.Contains(strings.ToLower(name), q) &&
!strings.Contains(strings.ToLower(abbr), q) {
continue
}

ti, err := t.GetTzInfo(name)
// That should not happen too often.
if err != nil {
panic(err)
}

matches[name] = ti
}
}
return matches
}

0 comments on commit d6c5408

Please sign in to comment.