mirror of https://github.com/coder/coder.git
56 lines
1.7 KiB
Go
56 lines
1.7 KiB
Go
// go:build windows
|
|
|
|
package tz
|
|
|
|
import (
|
|
"os/exec"
|
|
"strings"
|
|
"time"
|
|
|
|
"golang.org/x/xerrors"
|
|
)
|
|
|
|
// cmdTimezone is a Powershell incantation that will return the system
|
|
// time location in IANA format.
|
|
const cmdTimezone = "[Windows.Globalization.Calendar,Windows.Globalization,ContentType=WindowsRuntime]::New().GetTimeZone()"
|
|
|
|
// TimezoneIANA attempts to determine the local timezone in IANA format.
|
|
// If the TZ environment variable is set, this is used.
|
|
// Otherwise, /etc/localtime is used to determine the timezone.
|
|
// Reference: https://stackoverflow.com/a/63805394
|
|
// On Windows platforms, instead of reading /etc/localtime, powershell
|
|
// is used instead to get the current time location in IANA format.
|
|
// Reference: https://superuser.com/a/1584968
|
|
func TimezoneIANA() (*time.Location, error) {
|
|
loc, err := locationFromEnv()
|
|
if err == nil {
|
|
return loc, nil
|
|
}
|
|
if !xerrors.Is(err, errNoEnvSet) {
|
|
return nil, xerrors.Errorf("lookup timezone from env: %w", err)
|
|
}
|
|
|
|
// https://superuser.com/a/1584968
|
|
cmd := exec.Command("powershell.exe", "-NoLogo", "-NoProfile", "-NonInteractive")
|
|
// Powershell echoes its stdin so write a newline
|
|
cmd.Stdin = strings.NewReader(cmdTimezone + "\n")
|
|
|
|
outBytes, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
return nil, xerrors.Errorf("execute powershell command %q: %w", cmdTimezone, err)
|
|
}
|
|
|
|
outLines := strings.Split(string(outBytes), "\n")
|
|
if len(outLines) < 2 {
|
|
return nil, xerrors.Errorf("unexpected output from powershell command %q: %q", cmdTimezone, outLines)
|
|
}
|
|
// What we want is the second line of output
|
|
locStr := strings.TrimSpace(outLines[1])
|
|
loc, err = time.LoadLocation(locStr)
|
|
if err != nil {
|
|
return nil, xerrors.Errorf("invalid location %q from powershell: %w", locStr, err)
|
|
}
|
|
|
|
return loc, nil
|
|
}
|