Preflight Checklist
- [x] I have searched the issue tracker for an issue that matches the one I want to file, without success.
- [x] I am not looking for support or already pursued the available support channels without success.
- [x] I have checked the troubleshooting guide for my problem, without success.
Viper Version
1.19.1
Go Version
1.24
Config Source
Flags
Format
YAML
Repl.it link
No response
Code reproducing the issue
package main
import (
"fmt"
"os"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var cfgFile string
var rootCmd = &cobra.Command{
Use: "myapp",
Short: "Example application showing Viper configuration",
Run: func(cmd *cobra.Command, args []string) {
cfg, err := getConfig()
if err != nil {
fmt.Printf("Error: %v\n", err)
os.Exit(1)
}
fmt.Printf("Configuration loaded: %+v\n", cfg)
},
}
type Config struct {
ClusterID string `mapstructure:"clusterID"`
ServerPort int `mapstructure:"server.port"`
BackendMode []string `mapstructure:"server.backendMode"`
}
func init() {
cobra.OnInitialize(initConfig)
// Define flags
rootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "", "Load configuration from `filename`")
rootCmd.PersistentFlags().StringP(
"cluster-id",
"i",
"",
"Specify the cluster ID",
)
viper.BindPFlag("clusterID", rootCmd.PersistentFlags().Lookup("cluster-id"))
viper.BindEnv("clusterID", "MY_CLUSTER_ID")
rootCmd.PersistentFlags().IntP(
"port",
"p",
8080,
"Server port",
)
viper.BindPFlag("server.port", rootCmd.PersistentFlags().Lookup("port"))
}
func initConfig() {
if cfgFile != "" {
// Use config file from the flag
viper.SetConfigFile(cfgFile)
} else {
// Search config in working directory with name "config" (without extension)
viper.AddConfigPath(".")
viper.SetConfigName("config")
}
// Read the config file
if err := viper.ReadInConfig(); err != nil {
fmt.Printf("Can't read configuration file: %v\n", err)
os.Exit(1)
}
fmt.Println("Using config file:", viper.ConfigFileUsed())
}
func getConfig() (Config, error) {
var cfg Config
// Read configuration into struct
cfg = Config{
ClusterID: viper.GetString("clusterID"),
ServerPort: viper.GetInt("server.port"),
BackendMode: viper.GetStringSlice("server.backendMode"),
}
// Validate configuration
if cfg.ClusterID == "" {
return cfg, fmt.Errorf("cluster ID cannot be empty")
}
return cfg, nil
}
func main() {
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
Expected Behavior
while parsing below configuration file
conf.yaml
clusterID: 2024-03-03
server:
port: 9090
backendMode:
- "mode1"
- "mode2"
we expect string with -
is parsed as string
Configuration loaded: {ClusterID:2022-03-04 ServerPort:9090 BackendMode:[mode1 mode2]}
Actual Behavior
while parsing below configuration file
conf.yaml
clusterID: 2024-03-03
server:
port: 9090
backendMode:
- "mode1"
- "mode2"
we see string with -
is parsed as datetime in UTC
Configuration loaded: {ClusterID:2022-03-04 00:00:00 +0000 UTC ServerPort:9090 BackendMode:[mode1 mode2]}
Steps To Reproduce
mkdir my app
go mod init myapp
vi myapp.go [insert source code]
vi conf.yaml [insert config]
go mod tidy
go build -o myapp myapp.go
./myapp --config config.yaml
Additional Information
For the same configuration file viper 1.7.0 and 1.19.0 are parsing values differently.
with viper v1.7.0 we see it is parsed as string
Configuration loaded: {ClusterID:2022-03-04 ServerPort:9090 BackendMode:[mode1 mode2]}
with viper v1.19.0 we see it is parsed as datetime in UTC
Configuration loaded: {ClusterID:2022-03-04 00:00:00 +0000 UTC ServerPort:9090 BackendMode:[mode1 mode2]}