// Package config 提供环境变量读取辅助与全局时区常量。 // // 密钥纪律(service-secret-protocol §2): // - MustEnv:密钥类配置缺省即 panic(fail-closed),禁止任何字面量默认值; // - EnvDefault:仅允许用于非密钥配置(端口、阈值、路径等)。 package config import ( "fmt" "os" "strconv" "time" ) // Timezone 组织规范东八区(development-standards §7)。 const Timezone = "Asia/Shanghai" // TZ 全局 Location;包加载时初始化,失败 panic(时区数据属基础环境,不可降级)。 var TZ = mustLoadTZ() func mustLoadTZ() *time.Location { loc, err := time.LoadLocation(Timezone) if err != nil { panic(fmt.Sprintf("config: 加载时区 %s 失败: %v", Timezone, err)) } return loc } // Now 返回东八区当前时间。全项目时间字段统一经此取值。 func Now() time.Time { return time.Now().In(TZ) } // FormatTime 东八区 RFC3339(落库时间字段)。 func FormatTime(t time.Time) string { return t.In(TZ).Format(time.RFC3339) } // ParseRFC3339 解析 RFC3339 并归一东八区。 func ParseRFC3339(s string) (time.Time, error) { t, err := time.Parse(time.RFC3339, s) if err != nil { return time.Time{}, err } return t.In(TZ), nil } // MustEnv 读取必填环境变量;缺失或空串直接 panic(fail-closed,无默认值兜底)。 // 仅用于密钥/凭据类配置。 func MustEnv(name string) string { v := os.Getenv(name) if v == "" { panic(fmt.Sprintf("config: 必填环境变量 %s 未设置(fail-closed,禁默认值)", name)) } return v } // EnvDefault 读取非密钥环境变量,缺省给默认值。 // 禁止传入任何密钥名(密钥必须走 MustEnv)。 func EnvDefault(name, def string) string { if v := os.Getenv(name); v != "" { return v } return def } // EnvDefaultInt 读取非密钥整型环境变量,解析失败给默认值。 func EnvDefaultInt(name string, def int) int { v := os.Getenv(name) if v == "" { return def } n, err := strconv.Atoi(v) if err != nil { return def } return n }