数组时间切片按升序验证

huangapple go评论89阅读模式
英文:

Slice of array time.Time in Ascending order validation

问题

最近我一直在尝试创建一个函数,用于验证类型为[][2]time.Time的变量。数组的列表示一对time.Time,分别是输入日期和出站日期。但是我无法编写能够处理所有可能的无效组合的代码,同时又不会使实际上有效的组合变为无效。

无效的规则如下:

  • 日期不能超过当前日期和时间。

  • 时间不能相同。例如:[][2]time.Time{{time.Date(2020, 11, 23, 8, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 8, 0, 0, 0, time.UTC)}}[][2]time.Time{ {time.Date(2020, 11, 23, 8, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 9, 0, 0, 0, time.UTC)}, {time.Date(2020, 11, 23, 9, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 11, 0, 0, 0, time.UTC)}}

  • 如果没有输出,就不能有新的输入。例如:[][2]time.Time{ {time.Date(2020, 11, 23, 8, 0, 0, 0, time.UTC), time.Time{}//默认值}, {time.Date(2020, 11, 23, 10, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 11, 0, 0, 0, time.UTC)} }

  • 日期必须按升序排列,也就是说,第一个切片日期(表示入站)必须早于第二个日期,第二个日期早于第三个日期,依此类推。因此,以下是无效组合的示例:[][2]time.Time{ {time.Date(2020, 11, 23, 8, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 7, 0, 0, 0, time.UTC)}, {time.Date(2020, 11, 23, 10, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 11, 0, 0, 0, time.UTC)} }

给我造成最大问题的是默认值,因为它们是有效的Time对象,但应该被视为null,也就是说,输出日期没有报告。可以将其想象为工人的考勤表,如果有入站日期但输出是默认值,意味着工人已经进入但尚未离开,这是一个有效的情况。但如果工人还没有上一次入站的输出,就不能注册新的入站。

这是我目前能够编写的代码。是的,它还不完整,因为我修改了很多次,现在不知道如何继续了。

func validSliceArrayTime(slarti [][2]time.Time) bool {

	now_time := time.Now()
	var rtime, ltime time.Time
	var rt_is_def bool

	for _, v := slarti {

		rtime = v[1]
		rt_is_def = rtime.Year() <= 1

		switch {
		case v[0].Year() <= 1:
			return false
		case v[0].After(now_time):
			return false
		case (!v[0].Before(rtime) && !rt_is_def):
			return false
		case !v[0].After(ltime):
			return false
		// case !rtime.After(ltime):
		// 	return false
		// case rtime.After(now_time):
		// 	return false
		default:
			ltime = v[1]
		}
	}

	return true
}
英文:

For some time now I've been trying to create a function that validates a variable of the type [][2]time.Time. The columns of the array represet a pair of time.Time which are an input date and an outbound date respectively.but I can't produce code that addresses all possible invalid combinations and at the same time does not invalidate combinations that are actually valid.
The rules to invalidate are:

  • Dates cannot be longer than the current date and time.

  • Times can't be the same. E.g: [][2]time.Time{{time.Date(2020, 11, 23, 8, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 8, 0, 0, 0, time.UTC)}}. Or [][2]time.Time{ {time.Date(2020, 11, 23, 8, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 9, 0, 0, 0, time.UTC)}, {time.Date(2020, 11, 23, 9, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 11, 0, 0, 0, time.UTC)}}

  • There cannot be a new entry if there is no output before. E.g:
    [][2]time.Time{ {time.Date(2020, 11, 23, 8, 0, 0, 0, time.UTC), time.Time{}//Default}, {time.Date(2020, 11, 23, 10, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 11, 0, 0, 0, time.UTC)} }

  • The dates must be in ascending order, that is, the first slice date that in this case represents an entry must be older than the second, the second older than the third, and so on. Therefore, below would be examples of invalid combinations:
    [][2]time.Time{ {time.Date(2020, 11, 23, 8, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 7, 0, 0, 0, time.UTC)}, {time.Date(2020, 11, 23, 10, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 11, 0, 0, 0, time.UTC)} }.

What has caused me the biggest problem are the default values, because they are valid Time objects but they should be considered as null, that is, that the output date was not reported.
Imagine as if it were a point sheet of a worker, if there is an entry date but the output is default means that the worker entered but has not yet left, that is, it is a valid situation. But it would not be valid for a worker to register a new entry if there is not yet an output for their previous entry.
That's the code I've been able to produce so far. Yes, it's not complete because I've modified it so many times I don't know how to move forward anymore.

func validSliceArrayTime(slarti [][2]time.Time) bool {

	now_time := time.Now()
	var rtime, ltime time.Time
	var rt_is_def bool

	for _, v := slarti {

		rtime = v[1]
		rt_is_def = rtime.Year() &lt;= 1

		switch {
		case v[0].Year() &lt;= 1:
			return false
		case v[0].After(now_time):
			return false
		case (!v[0].Before(rtime) &amp;&amp; !rt_is_def):
			return false
		case !v[0].After(ltime):
			return false
		// case !rtime.After(ltime):
		// 	return false
		// case rtime.After(now_time):
		// 	return false
		default:
			ltime = v[1]
		}
	}

	return true
}

答案1

得分: 1

要检查一个time.Time是否为其零值,可以使用Time.IsZero()方法。

除此之外,只需逐个实现你的规则。这可能不是最高效的解决方案,但它将是简洁和简单的,一旦正确工作,你可以进行改进:

func isValid(slarti [][2]time.Time) bool {
	now := time.Now()

	for i, v := range slarti {
		v1, v2 := v[0], v[1]

		// 规则 #3
		if v1.IsZero() {
			return false
		}

		// 规则 #1:时间必须在过去
		if now.Before(v1) || now.Before(v2) {
			return false
		}

		// 规则 #2:时间不能相同
		if v1.Equal(v2) {
			return false
		}
		if i > 0 && v1.Equal(slarti[i-1][1]) {
			return false
		}

		// 规则 #3:如果之前没有输出,则无效条目
		if i > 0 && slarti[i-1][1].IsZero() {
			return false
		}

		// 规则 #4:时间必须按升序排列
		if !v2.IsZero() && v2.Before(v1) {
			return false
		}
		if i > 0 && v1.Before(slarti[i-1][1]) {
			return false
		}
	}

	return true // 到达这里:有效
}

这是一个测试代码,测试所有规则,以及有效的输入(可以在Go Playground上尝试):

cases := []struct {
	name  string
	input [][2]time.Time
	valid bool
}{
	{
		name:  "有效",
		input: [][2]time.Time{{time.Date(2020, 11, 23, 8, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 9, 0, 0, 0, time.UTC)}},
		valid: true,
	},
	{
		name:  "有效 (2)",
		input: [][2]time.Time{{time.Date(2020, 11, 23, 8, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 9, 0, 0, 0, time.UTC)}, {time.Date(2020, 11, 23, 10, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 11, 0, 0, 0, time.UTC)}},
		valid: true,
	},
	{
		name:  "有效 (3)",
		input: [][2]time.Time{{time.Date(2020, 11, 23, 8, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 9, 0, 0, 0, time.UTC)}, {time.Date(2020, 11, 23, 10, 0, 0, 0, time.UTC), time.Time{}}},
		valid: true,
	},
	{
		name:  "规则 #1",
		input: [][2]time.Time{{time.Date(2023, 11, 23, 8, 0, 0, 0, time.UTC), time.Date(2023, 11, 23, 9, 0, 0, 0, time.UTC)}},
	},
	{
		name:  "规则 #2",
		input: [][2]time.Time{{time.Date(2020, 11, 23, 8, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 8, 0, 0, 0, time.UTC)}},
	},
	{
		name:  "规则 #2 (2)",
		input: [][2]time.Time{{time.Date(2020, 11, 23, 8, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 9, 0, 0, 0, time.UTC)}, {time.Date(2020, 11, 23, 9, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 11, 0, 0, 0, time.UTC)}},
	},
	{
		name:  "规则 #3",
		input: [][2]time.Time{{time.Date(2020, 11, 23, 8, 0, 0, 0, time.UTC), time.Time{}}, {time.Date(2020, 11, 23, 10, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 11, 0, 0, 0, time.UTC)}},
	},
	{
		name:  "规则 #3 (2)",
		input: [][2]time.Time{{time.Time{}, time.Date(2020, 11, 23, 9, 0, 0, 0, time.UTC)}, {time.Date(2020, 11, 23, 10, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 11, 0, 0, 0, time.UTC)}},
	},
	{
		name:  "规则 #4",
		input: [][2]time.Time{{time.Date(2020, 11, 23, 8, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 7, 0, 0, 0, time.UTC)}, {time.Date(2020, 11, 23, 10, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 11, 0, 0, 0, time.UTC)}},
	},
}

for i, c := range cases {
	if valid := isValid(c.input); valid != c.valid {
		log.Printf("[%d] %q 期望结果为有效:%t,实际结果为:%t", i, c.name, c.valid, valid)
	}
}
英文:

To check if a time.Time is its zero value, use Time.IsZero().

Other than that, simply implement your rules one-by-one. It won't be the most efficient solution, but it will be clean and simple which you can improve once it works correctly:

func isValid(slarti [][2]time.Time) bool {
now := time.Now()
for i, v := range slarti {
v1, v2 := v[0], v[1]
// Rule #3
if v1.IsZero() {
return false
}
// Rule #1: times must be in the past
if now.Before(v1) || now.Before(v2) {
return false
}
// Rule #2: times can&#39;t be the same
if v1.Equal(v2) {
return false
}
if i &gt; 0 &amp;&amp; v1.Equal(slarti[i-1][1]) {
return false
}
// Rule #3: invalid entry if no output before:
if i &gt; 0 &amp;&amp; slarti[i-1][1].IsZero() {
return false
}
// Rule #4: times must be in ascending order:
if !v2.IsZero() &amp;&amp; v2.Before(v1) {
return false
}
if i &gt; 0 &amp;&amp; v1.Before(slarti[i-1][1]) {
return false
}
}
return true // Got this far: valid
}

Here's a test code that tests all rules, and also valid inputs (try it on the Go Playground):

cases := []struct {
name  string
input [][2]time.Time
valid bool
}{
{
name:  &quot;Valid&quot;,
input: [][2]time.Time{{time.Date(2020, 11, 23, 8, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 9, 0, 0, 0, time.UTC)}},
valid: true,
},
{
name:  &quot;Valid (2)&quot;,
input: [][2]time.Time{{time.Date(2020, 11, 23, 8, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 9, 0, 0, 0, time.UTC)}, {time.Date(2020, 11, 23, 10, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 11, 0, 0, 0, time.UTC)}},
valid: true,
},
{
name:  &quot;Valid (3)&quot;,
input: [][2]time.Time{{time.Date(2020, 11, 23, 8, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 9, 0, 0, 0, time.UTC)}, {time.Date(2020, 11, 23, 10, 0, 0, 0, time.UTC), time.Time{}}},
valid: true,
},
{
name:  &quot;Rule #1&quot;,
input: [][2]time.Time{{time.Date(2023, 11, 23, 8, 0, 0, 0, time.UTC), time.Date(2023, 11, 23, 9, 0, 0, 0, time.UTC)}},
},
{
name:  &quot;Rule #2&quot;,
input: [][2]time.Time{{time.Date(2020, 11, 23, 8, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 8, 0, 0, 0, time.UTC)}},
},
{
name:  &quot;Rule #2 (2)&quot;,
input: [][2]time.Time{{time.Date(2020, 11, 23, 8, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 9, 0, 0, 0, time.UTC)}, {time.Date(2020, 11, 23, 9, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 11, 0, 0, 0, time.UTC)}},
},
{
name:  &quot;Rule #3&quot;,
input: [][2]time.Time{{time.Date(2020, 11, 23, 8, 0, 0, 0, time.UTC), time.Time{}}, {time.Date(2020, 11, 23, 10, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 11, 0, 0, 0, time.UTC)}},
},
{
name:  &quot;Rule #3 (2)&quot;,
input: [][2]time.Time{{time.Time{}, time.Date(2020, 11, 23, 9, 0, 0, 0, time.UTC)}, {time.Date(2020, 11, 23, 10, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 11, 0, 0, 0, time.UTC)}},
},
{
name:  &quot;Rule #4&quot;,
input: [][2]time.Time{{time.Date(2020, 11, 23, 8, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 7, 0, 0, 0, time.UTC)}, {time.Date(2020, 11, 23, 10, 0, 0, 0, time.UTC), time.Date(2020, 11, 23, 11, 0, 0, 0, time.UTC)}},
},
}
for i, c := range cases {
if valid := isValid(c.input); valid != c.valid {
log.Printf(&quot;[%d] %q expected valid: %t, got: %t&quot;, i, c.name, c.valid, valid)
}
}

huangapple
  • 本文由 发表于 2022年9月12日 23:24:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/73691600.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定