在Golang中实现类似定时器的闹钟功能

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

Alarm like timer functionality in Golang

问题

有没有一种在Golang中设计一个在特定未来时间到期的定时器的方法?我的意思是一个在凌晨2点到期的定时器(假设当前时间是凌晨12点)。我知道一种方法是使用

 timer(target_future_time - current_time)   

但这似乎不是一个准确的方法(在考虑执行时间时可能不准确)。有人可以帮忙吗?

英文:

Is there any way for designing a timer that expires on a specific future time in Golang ? I mean a timer that expires on 2AM (let the current time be 12AM). I know one way is to use,

 timer(target_future_time - current_time)   

but doesn't seem to be an exact way of doing it (may not be accurate on considering the execution time). Can anyone help please?

答案1

得分: 2

在golang中,可能有两种方法创建ticker,就像下面的代码一样:

package main

import (
    "fmt"
    "time"
)

func main() {
    //第一种实现方式 
    ticker1 := time.NewTicker(1 * time.Second)
    i := 1
    for c := range ticker1.C {
        i++
        fmt.Println(c.Format("2006/01/02 15:04:05.999999999"))
        if i > 5 {
            ticker1.Stop()
            break
        }
    }
    fmt.Println(time.Now().Format("2006/01/02 15:04:05.999999999"), " 1 Finished.")

    //第二种实现方式 
    i = 1
    ticker2 := time.AfterFunc(1*time.Second, func() {
        i++
        fmt.Println(time.Now().Format("2006/01/02 15:04:05.999999999"))
    })

    for {
        select {
        case <-ticker2.C:
            fmt.Println("nsmei")
        case <-time.After(3 * time.Second):
            if i <= 5 {
                ticker2.Reset(1 * time.Second)
                continue
            }
            goto BRK
        }
    BRK:
        ticker2.Stop()
        break
    }
    fmt.Println(time.Now().Format("2006/01/02 15:04:05.999999999"), " 2 Finished.")
}

输出结果:

2016/01/26 16:46:34.261248567
2016/01/26 16:46:35.256381743
2016/01/26 16:46:36.259717152
2016/01/26 16:46:37.260320837
2016/01/26 16:46:38.259312704
2016/01/26 16:46:38.259410752  1 Finished.
2016/01/26 16:46:39.260604274
2016/01/26 16:46:42.261091322
2016/01/26 16:46:45.263136257
2016/01/26 16:46:48.264193517
2016/01/26 16:46:51.265655137
2016/01/26 16:46:53.265722632  2 Finished.

根据执行结果,第一种方法比第二种方法更精确。

在你的情况下,你可以使用`time.Time.Sub()`来计算持续时间,并使用第二种方法执行一次,其余使用第一种方法。

希望这些对你有帮助!

<details>
<summary>英文:</summary>

&lt;p&gt;In golang,maybe there are two way create ticker,just like the following:&lt;/p&gt;    
    package main
    
    import (
        &quot;fmt&quot;
        &quot;time&quot;
    )
    
    func main() {
        //第一种实现方式 
        ticker1 := time.NewTicker(1 * time.Second)
        i := 1
        for c := range ticker1.C {
            i++
            fmt.Println(c.Format(&quot;2006/01/02 15:04:05.999999999&quot;))
            if i &gt; 5 {
                ticker1.Stop()
                break
            }
        }
        fmt.Println(time.Now().Format(&quot;2006/01/02 15:04:05.999999999&quot;), &quot; 1 Finished.&quot;)
    
        //第二种实现方式 
        i = 1
        ticker2 := time.AfterFunc(1*time.Second, func() {
            i++
            fmt.Println(time.Now().Format(&quot;2006/01/02 15:04:05.999999999&quot;))
        })
    
        for {
            select {
            case &lt;-ticker2.C:
                fmt.Println(&quot;nsmei&quot;)
            case &lt;-time.After(3 * time.Second):
                if i &lt;= 5 {
                    ticker2.Reset(1 * time.Second)
                    continue
                }
                goto BRK
            }
        BRK:
            ticker2.Stop()
            break
        }
        fmt.Println(time.Now().Format(&quot;2006/01/02 15:04:05.999999999&quot;), &quot; 2 Finished.&quot;)
    }
Output:

    2016/01/26 16:46:34.261248567
    2016/01/26 16:46:35.256381743
    2016/01/26 16:46:36.259717152
    2016/01/26 16:46:37.260320837
    2016/01/26 16:46:38.259312704
    2016/01/26 16:46:38.259410752  1 Finished.
    2016/01/26 16:46:39.260604274
    2016/01/26 16:46:42.261091322
    2016/01/26 16:46:45.263136257
    2016/01/26 16:46:48.264193517
    2016/01/26 16:46:51.265655137
    2016/01/26 16:46:53.265722632  2 Finished.

**According to the execution,the first is more precise than the second.**&lt;p&gt;In your case,you can use &lt;code&gt;time.Time.Sub()&lt;/code&gt; to calculate the duration,and execute once using the second method,the rest using the first method.&lt;/p&gt;
&lt;p&gt;I hope these help you!&lt;/p&gt;

</details>



# 答案2
**得分**: 0

以下是实现你的目的的代码。你只需要按照下面 main() 函数中所示的方式调用 ScheduleAlarm()。

```go
package main

import (
	"strings"
	"strconv"
	"fmt"
	"time"
)

// 表示时间的结构体。
type Time struct {
	Hh int // 小时。
	Mm int // 分钟。
	Ss int // 秒。
}

func main() {
	/*
	按照下面所示的方式设置闹钟。
	时间必须以24小时制格式指定。
	同时,传递在闹钟触发后要调用的回调函数。
	*/
	alarm := ScheduleAlarm(Time{23, 28, 0}, func() {
		fmt.Println("收到闹钟")
	})

	// 做你的事情。
	for i := 0; i < 10; i++ {
		fmt.Println(i)
		time.Sleep(2 * time.Second)
	}

	// 不要忘记在需要阻塞的时候调用下面的代码。
	<-alarm
}

// 调用此函数来设置闹钟。在闹钟触发后,将调用回调函数。
func ScheduleAlarm(alarmTime Time, callback func() ()) (endRecSignal chan string) {
	endRecSignal = make(chan string)
	go func() {
		timeSplice := strings.Split(time.Now().Format("15:04:05"), ":")
		hh, _ := strconv.Atoi(timeSplice[0])
		mm, _ := strconv.Atoi(timeSplice[1])
		ss, _ := strconv.Atoi(timeSplice[2])

		startAlarm := GetDiffSeconds(Time{hh, mm, ss}, alarmTime)

		// 设置闹钟。
		time.AfterFunc(time.Duration(startAlarm) * time.Second, func() {
			callback()
			endRecSignal <- "录音完成"
			close(endRecSignal)
		})
	}()
	return
}

func GetDiffSeconds(fromTime, toTime Time) int {
	fromSec := GetSeconds(fromTime)
	toSec := GetSeconds(toTime)
	diff := toSec - fromSec

	if diff < 0 {
		return diff + 24 * 60 * 60
	} else {
		return diff
	}
}

func GetSeconds(time Time) int {
	return time.Hh * 60 * 60 + time.Mm * 60 + time.Ss
}

希望对你有所帮助。

英文:

The following code achieves your purpose. All you've to do is call ScheduleAlarm() in the manner shown in the main() function below.

package main

import (
	&quot;strings&quot;
	&quot;strconv&quot;
	&quot;fmt&quot;
	&quot;time&quot;
)

// A struct for representing time.
type Time struct {
	Hh int // Hours.
	Mm int // Minutes.
	Ss int // Seconds.
}

func main() {
	/*
	Set the alarm as shown below.
	Time must be specified in 24 hour clock format.
	Also, pass the callback to be called after the alarm is triggered.
	*/
	alarm := ScheduleAlarm(Time{23, 28, 0}, func() {
		fmt.Println(&quot;alarm received&quot;)
	})

	// Do your stuff.
	for i := 0; i &lt; 10; i++ {
		fmt.Println(i)
		time.Sleep(2 * time.Second)
	}

	// Don&#39;t forget to call the below line whenever you want to block.
	&lt;-alarm
}

// Call this function to schedule the alarm. The callback will be called after the alarm is triggered.
func ScheduleAlarm(alarmTime Time, callback func() ()) (endRecSignal chan string) {
	endRecSignal = make(chan string)
	go func() {
		timeSplice := strings.Split(time.Now().Format(&quot;15:04:05&quot;), &quot;:&quot;)
		hh, _ := strconv.Atoi(timeSplice[0])
		mm, _ := strconv.Atoi(timeSplice[1])
		ss, _ := strconv.Atoi(timeSplice[2])

		startAlarm := GetDiffSeconds(Time{hh, mm, ss}, alarmTime)

		// Setting alarm.
		time.AfterFunc(time.Duration(startAlarm) * time.Second, func() {
			callback()
			endRecSignal &lt;- &quot;finished recording&quot;
			close(endRecSignal)
		})
	}()
	return
}

func GetDiffSeconds(fromTime, toTime Time) int {
	fromSec := GetSeconds(fromTime)
	toSec := GetSeconds(toTime)
	diff := toSec - fromSec

	if diff &lt; 0 {
		return diff + 24 * 60 * 60
	} else {
		return diff
	}
}

func GetSeconds(time Time) int {
	return time.Hh * 60 * 60 + time.Mm * 60 + time.Ss
}

Hope this helps.

huangapple
  • 本文由 发表于 2016年1月26日 15:51:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/35009070.html
匿名

发表评论

匿名网友

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

确定