Repository: spf13/viper
Pull request #1498 (2023-01-24 17:12:14)

fix: time.Duration slice type conversion
this fixes: https://github.com/spf13/viper/issues/1497


CLAassistant: [![CLA assistant check](https://cla-assistant.io/pull/badge/not_signed)](https://cla-assistant.io/spf13/viper?pullRequest=1498) <br/>Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our [Contributor License Agreement](https://cla-assistant.io/spf13/viper?pullRequest=1498) before we can accept your contribution.<br/><sub>You have signed the CLA already but the status is still pending? Let us [recheck](https://cla-assistant.io/check/spf13/viper?pullRequest=1498) it.</sub>
github-actions[bot]: 👋 Thanks for contributing to Viper! You are awesome! 🎉

A maintainer will take a look at your pull request shortly. 👀

In the meantime: We are working on **Viper v2** and we would love to hear your thoughts about what you like or don't like about Viper, so we can improve or fix those issues.

⏰ If you have a couple minutes, please take some time and share your thoughts: https://forms.gle/R6faU74qPRPAzchZ9

📣 If you've already given us your feedback, you can still help by spreading the news,
either by sharing the above link or telling people about this on Twitter:

https://twitter.com/sagikazarmark/status/1306904078967074816

**Thank you!** ❤️

UrbanskiDawid: I see that 'PR Checks / Release note label' CI job has failed, is this something I should do for it to be green?
sagikazarmark: Nope, it's already green. It just checks that a release note label is added to the issue before merging.

Patch:
diff --git a/viper.go b/viper.go
index 06610fc..45a2d5c 100644
--- a/viper.go
+++ b/viper.go
@@ -928,6 +928,8 @@ func (v *Viper) Get(key string) interface{} {
 			return cast.ToStringSlice(val)
 		case []int:
 			return cast.ToIntSlice(val)
+		case []time.Duration:
+			return cast.ToDurationSlice(val)
 		}
 	}
 
@@ -1274,8 +1276,14 @@ func (v *Viper) find(lcaseKey string, flagDefault bool) interface{} {
 			s = strings.TrimSuffix(s, "]")
 			res, _ := readAsCSV(s)
 			return cast.ToIntSlice(res)
+		case "durationSlice":
+			s := strings.TrimPrefix(flag.ValueString(), "[")
+			s = strings.TrimSuffix(s, "]")
+			slice := strings.Split(s, ",")
+			return cast.ToDurationSlice(slice)
 		case "stringToString":
 			return stringToStringConv(flag.ValueString())
+
 		default:
 			return flag.ValueString()
 		}
@@ -1355,6 +1363,11 @@ func (v *Viper) find(lcaseKey string, flagDefault bool) interface{} {
 				return cast.ToIntSlice(res)
 			case "stringToString":
 				return stringToStringConv(flag.ValueString())
+			case "durationSlice":
+				s := strings.TrimPrefix(flag.ValueString(), "[")
+				s = strings.TrimSuffix(s, "]")
+				slice := strings.Split(s, ",")
+				return cast.ToDurationSlice(slice)
 			default:
 				return flag.ValueString()
 			}


Test patch:
diff --git a/viper_test.go b/viper_test.go
index 926ffc2..9363da8 100644
--- a/viper_test.go
+++ b/viper_test.go
@@ -1094,6 +1094,28 @@ func TestBindPFlagsStringArray(t *testing.T) {
 	}
 }
 
+func TestSliceFlagsReturnCorrectType(t *testing.T) {
+	flagSet := pflag.NewFlagSet("test", pflag.ContinueOnError)
+	flagSet.IntSlice("int", []int{1, 2}, "")
+	flagSet.StringSlice("str", []string{"3", "4"}, "")
+	flagSet.DurationSlice("duration", []time.Duration{5 * time.Second}, "")
+
+	v := New()
+	v.BindPFlags(flagSet)
+
+	all := v.AllSettings()
+
+	if _, ok := all["int"].([]int); !ok {
+		t.Errorf("unexpected type %T expected []int", all["int"])
+	}
+	if _, ok := all["str"].([]string); !ok {
+		t.Errorf("unexpected type %T expected []string", all["str"])
+	}
+	if _, ok := all["duration"].([]time.Duration); !ok {
+		t.Errorf("unexpected type %T expected []time.Duration", all["duration"])
+	}
+}
+
 //nolint:dupl
 func TestBindPFlagsIntSlice(t *testing.T) {
 	tests := []struct {