62 lines
1.5 KiB
Go
62 lines
1.5 KiB
Go
// Package timezone 提供随计划冻结的时区快照,禁止读取宿主机或 ZONEINFO 环境配置。
|
||
package timezone
|
||
|
||
import (
|
||
"archive/zip"
|
||
"bytes"
|
||
_ "embed"
|
||
"errors"
|
||
"io"
|
||
"sync"
|
||
"time"
|
||
)
|
||
|
||
// Version 标识 Go 1.27.1 附带的 IANA 快照及文件摘要;升级时须保留旧版本可读能力。
|
||
const Version = "go1.27.1-b2d18a7c8fa8"
|
||
|
||
//go:embed zoneinfo.zip
|
||
var data []byte
|
||
var zones sync.Map
|
||
var archive = sync.OnceValues(func() (*zip.Reader, error) { return zip.NewReader(bytes.NewReader(data), int64(len(data))) })
|
||
|
||
// Load 仅接受精确的内置名称,返回只读 Location;不接受 Local 或文件系统路径。
|
||
func Load(name, version string) (*time.Location, error) {
|
||
if version != Version || name == "" || name == "Local" || len(name) > 64 {
|
||
return nil, errors.New("unsupported frozen timezone version or name")
|
||
}
|
||
if name == "UTC" {
|
||
return time.UTC, nil
|
||
}
|
||
if v, ok := zones.Load(name); ok {
|
||
return v.(*time.Location), nil
|
||
}
|
||
a, err := archive()
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
for _, entry := range a.File {
|
||
if entry.Name != name {
|
||
continue
|
||
}
|
||
r, err := entry.Open()
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
b, err := io.ReadAll(io.LimitReader(r, 1<<20))
|
||
closeErr := r.Close()
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if closeErr != nil {
|
||
return nil, closeErr
|
||
}
|
||
loc, err := time.LoadLocationFromTZData(name, b)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
actual, _ := zones.LoadOrStore(name, loc)
|
||
return actual.(*time.Location), nil
|
||
}
|
||
return nil, errors.New("unknown IANA timezone")
|
||
}
|