Go语言便捷的时间命令行工具
学习:便捷的时间工具 | Go 语言编程之旅 (eddycjy.com)
代码参考:go-programming-tour-book/tour: 《Go 语言编程之旅:一起用 Go 做项目》第一章:命令行程序(Command) (github.com)
先搭好架子,再具体实现!
接口的应用中也有这种思想,接口相当于先制定标准再具体实现;
搭好架子/制定标准:全局架构清晰;具体实现。
先看Go语言单词格式转换命令行工具 - KpHang - 博客园 (cnblogs.com),此篇是以上篇文章架构为基础的。
搭好架子
$ tree
.
├── cmd
│ ├── root.go
│ ├── time.go
│ └── word.go
├── internal
│ ├── timer
│ │ └── time.go
│ └── word
│ └── word.go
├── main.go
cmd/time.go
,用于单词格式转换的子命令 time 的简单设置:
var timeCmd = &cobra.Command{
Use: "time",
Short: "时间格式处理",
Long: "时间格式处理",
Run: func(cmd *cobra.Command, args []string) {},
}
cmd/time.go
在给time子命令,再设置两个子命令(对于root而言,就是子命令的子命令;)
time now
time calc
// time now 子命令
var nowTimeCmd = &cobra.Command{
Use: "now",
Short: "获取当前时间",
Long: "获取当前时间",
Run: func(cmd *cobra.Command, args []string) {},
}
// time calc 子命令
var calculateTimeCmd = &cobra.Command{
Use: "calc",
Short: "计算所需的时间",
Long: "计算所需的时间",
Run: func(cmd *cobra.Command, args []string) {},
}
func init() {
timeCmd.AddCommand(nowTimeCmd) // 把nowTimeCmd加入root的子命令timeCmd中;
timeCmd.AddCommand(calculateTimeCmd) // time cal 子命令注册
}
cmd/root.go
,用于创建根命令,将子命令加入根命令中:
func init() {
...
rootCmd.AddCommand(timeCmd) // 将创建的time子命令加入rootcmd
}
- 关于init函数:
main包中导入cmd并使用cmd包:
import (
"log"
"github.com/KpiHang/tour/cmd"
)
var name string
func main() {
err := cmd.Execute()
if err != nil {
log.Fatalf("cmd.Execute err : %v", err)
}
}
详细设置time子命令
time子命令本身并没有设置参数,只需要对time now
,time calc
子命令进行设置。
cmd/time.go
,time now
:
// time now 子命令
var nowTimeCmd = &cobra.Command{
Use: "now",
Short: "获取当前时间",
Long: "获取当前时间",
Run: func(cmd *cobra.Command, args []string) {
nowTime := timer.GetNowTime()
// 第一个格式:通过调用 Format 方法设定约定的 2006-01-02 15:04:05 格式来进行时间的标准格式化。
// 第二个格式:通过调用 Unix 方法返回 Unix 时间,就是我们通俗说的时间戳,其值为自 UTC 1970 年 1 月 1 日起经过的秒数。
log.Printf("输出结果:%s, %d", nowTime.Format("2006-01-02 15:04:05"), nowTime.Unix())
},
}
log.Printf(...)
- 第一个格式:通过调用 Format 方法设定约定的 2006-01-02 15:04:05 格式来进行时间的标准格式化。
- 第二个格式:通过调用 Unix 方法返回 Unix 时间,就是我们通俗说的时间戳,其值为自 UTC 1970 年 1 月 1 日起经过的秒数。
cmd/time.go
,time calc
:
// time calc 子命令
var calculateTimeCmd = &cobra.Command{
Use: "calc",
Short: "计算所需的时间",
Long: "计算所需的时间",
Run: func(cmd *cobra.Command, args []string) {
var currentTimer time.Time
var layout = "2006-01-02 15:04:05"
if calculateTime == "" {
currentTimer = timer.GetNowTime()
} else {
var err error
space := strings.Count(calculateTime, " ")
if space == 0 {
layout = "2006-01-02"
}
if space == 1 {
layout = "2006-01-02 15:04:05"
}
// 使用了 time.Local,会根据系统配置来设置时区,中国是UTC+8
currentTimer, err = time.ParseInLocation(layout, calculateTime, time.Local)
if err != nil {
t, _ := strconv.Atoi(calculateTime)
currentTimer = time.Unix(int64(t), 0)
}
}
t, err := timer.GetCalulateTime(currentTimer, duration)
if err != nil {
log.Fatalf("timer.GetCalculateTime err: %v", err)
}
log.Printf("输出结果: %s, %d", t.Format(layout), t.Unix())
},
}
-
第21行,最开始使用的是
time.Parse()
,但是默认时区是UTC+0,而中国在东八区;currentTimer, err = time.ParseInLocation(layout, calculateTime, time.Local)
- 使用了 time.Local,会根据系统配置来设置时区,中国是UTC+8。
- Golang 小坑之 time.Parse 的默认时区 - 掘金 (juejin.cn)
功能入口
上面两个子命令,涉及到两个函数的具体实现:
timer.GetNowTime()
timer.GetCalulateTime(currentTimer, duration)
timer
包放在internal
包中。
internal包,Go中命名为internal的package或者目录,两点需要注意:
- 只有直接父级package,以及父级package的子孙package可以访问,其他的都不行,再往上的祖先package也不行。
- 父级package也只能访问internal package使用大写暴露出的内容,小写的不行。
在项目中不被复用,也不能被其他项目导入,仅被本项目内部使用的代码包即私有的代码包都应该放在
internal
文件夹下。该文件夹下的所有包及相应文件都有一个项目保护级别,即其他项目是不能导入这些包的,仅仅是该项目内部使用。
功能具体实现
$ tree
.
├── cmd
│ ├── root.go
│ ├── time.go
│ └── word.go
├── internal
│ ├── timer
│ │ └── time.go
│ └── word
│ └── word.go
├── main.go
internal/timer/time.go
,功能的具体实现:
func GetNowTime() time.Time {
return time.Now()
}
// 时间推算,计算当前时间+间隔时间;
func GetCalulateTime(currentTimer time.Time, d string) (time.Time, error) {
duration, err := time.ParseDuration(d)
// ParseDuration 方法用于在字符串中解析出 duration(持续时间),其支持的有效单位有"ns”, “us” (or “µ s”), “ms”, “s”, “m”, “h”,例如:“300ms”, “-1.5h” or “2h45m”。而在 Add 方法中,我们可以将其返回的 duration 传入,就可以得到当前 timer 时间加上 duration 后所得到的最终时间。
if err != nil {
return time.Time{}, err
}
return currentTimer.Add(duration), nil
}