golang积累-时间、时区、格式的使用

本文介绍Go语言中时间处理的基本概念,包括时间初始化、时区转换和格式化等操作,并提供代码示例。

前几天,因为需要实现海外服务端定时停机,涉及到时区的概念。网上搜索了一下,大部分都是谈time.Format中的Layout,非常不成体系,这里就简单总结一下其中的时间初始化、时区转化及格式转换。
开发中,我们对时间的使用是比较多的,其应用场景,按照使用概率,从大到小,通常是:

  1. 获取当前或数据库中存储的时间
  2. 比较两个时间点的先后
  3. 显示打印时间
  4. 时区转换

对应到go,也就是几个基本定义:

  1. 时间点与时间段:Time,Duration。好比MVC中的M。
  2. 时 区:Location,在时间转换上,好比是MVC中的C。
  3. 格式化:Format的layout定义,好比MVC中的V。

单独就Duration没什么好谈的,使用非常简单。Time实例中的Add、Sub与其相关,非常容易上手,就不再多说。

时区

时区是时间运算非常重要的概念,特别强调与layout是两个完全不同的概念。go语言通过Location来作为时区的运行实例,同一时刻转换成为不同的时区,就需要通过不同的Location来进行。默认情况下,采用UTC(unix标准时间),而不是过去式的GMT(格林尼治标准时间)。
以下代码展示了UTC标准、北京、美国洛杉矶在同一时刻的转换:

    now := time.Now()
    local1, err1 := time.LoadLocation("") //等同于"UTC"
    if err1 != nil {
        fmt.Println(err1)
    }
    local2, err2 := time.LoadLocation("Local")//服务器设置的时区
    if err2 != nil {
        fmt.Println(err2)
    }
    local3, err3 := time.LoadLocation("America/Los_Angeles")
    if err3 != nil {
        fmt.Println(err3)
    }

    fmt.Println(now.In(local1))
    fmt.Println(now.In(local2))
    fmt.Println(now.In(local3))
    //output:
    //2016-12-04 07:39:06.270473069 +0000 UTC
    //2016-12-04 15:39:06.270473069 +0800 CST
    //2016-12-03 23:39:06.270473069 -0800 PST

代码中,LoadLocation的输入参数的取值,除了该函数的源代码中可看到的”UTC”、”Local”,其余的值其实是遵照“IANA Time Zone”的规则,可以解压$GOROOT/lib/time/zoneinfo.zip 这个文件打开查看。在Asia这个目录,我看到了Chongqing,Hong_Kong,但没Beijing。在国外获取中国北京时间,要用”PRC”,当然”Asia/Chongqing”也是个方法:

    loc, _:= time.LoadLocation("Asia/Chongqing")   //参数就是解压文件的“目录”+“/”+“文件名”。
    fmt.Println(time.Now().In(loc))

值得强调的是,Location仅用于时区转化,而不对time内部的数据产生影响(内部其实是unix标准时),因此,当几个time实例进行Add、Sub的时候,不用关注Location是否相同。

时间格式化

前面例子中,打印结果非常丑陋,通常没人关心秒之后的ns;明确时区后,很少需要与UTC的时差。这时候,就需要定义我们的layout了。
网上好多都说,“2006-01-02 15:04:05是go的诞生时间,所以这么设计Format的Layout”,应该不是真的。请看下表:

01/Jan0203/15040506-07[00][:00]PMMon
时差上下午星期几

也就是1234567,分别对应:月日时分秒年 时差,很好记忆。只是稍微注意一下:

  • 月:01或Jan都可以
  • 小时:03表示12小时制,15表示24小时制。
  • 时差:是 -07 ,不是 07,后边可以增加“00”或“:00”,表示更进一步的分秒时差。
  • 上下午:使用PM,不是AM。
  • 摆放顺序:随意,甚至重复都可以。源代码包也有定义的常用格式供使用。

也许是因为06对应的“年”与go的项目启动时间差不多,也就有了网上的误传。在源代码time/time.go中,有非常明确的描述,粘贴一下,就不翻译了:

// These are predefined layouts for use in Time.Format and Time.Parse.
// The reference time used in the layouts is the specific time:
// Mon Jan 2 15:04:05 MST 2006
// which is Unix time 1136239445. Since MST is GMT-0700,
// the reference time can be thought of as
// 01/02 03:04:05PM ‘06 -0700

虽然go已经提供了10多个常用格式:

const (
    ANSIC       = "Mon Jan _2 15:04:05 2006"
    UnixDate    = "Mon Jan _2 15:04:05 MST 2006"
    RubyDate    = "Mon Jan 02 15:04:05 -0700 2006"
    RFC822      = "02 Jan 06 15:04 MST"
    RFC822Z     = "02 Jan 06 15:04 -0700" // RFC822 with numeric zone
    RFC850      = "Monday, 02-Jan-06 15:04:05 MST"
    RFC1123     = "Mon, 02 Jan 2006 15:04:05 MST"
    RFC1123Z    = "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 with numeric zone
    RFC3339     = "2006-01-02T15:04:05Z07:00"
    RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
    Kitchen     = "3:04PM"
    // Handy time stamps.
    Stamp      = "Jan _2 15:04:05"
    StampMilli = "Jan _2 15:04:05.000"
    StampMicro = "Jan _2 15:04:05.000000"
    StampNano  = "Jan _2 15:04:05.000000000"
)

但个人习惯还是“2006-01-02 15:04:05 Mon”,之前代码稍加修改,就是这样:

    formate:="2006-01-02 15:04:05 Mon"
    now := time.Now()
    local1, err1 := time.LoadLocation("UTC") //输入参数"UTC",等同于""
    if err1 != nil {
        fmt.Println(err1)
    }
    local2, err2 := time.LoadLocation("Local")
    if err2 != nil {
        fmt.Println(err2)
    }
    local3, err3 := time.LoadLocation("America/Los_Angeles")
    if err3 != nil {
        fmt.Println(err3)
    }

    fmt.Println(now.In(local1).Format(formate))
    fmt.Println(now.In(local2).Format(formate))
    fmt.Println(now.In(local3).Format(formate))
    //output:
    //2016-12-04 08:06:39 Sun
    //2016-12-04 16:06:39 Sun
    //2016-12-04 00:06:39 Sun

时间初始化

除了最常用的time.Now,go还提供了通过unix标准时间、字符串两种方式来初始化:

//通过字符串,默认UTC时区初始化Time
func Parse(layout, value string) (Time, error) 
//通过字符串,指定时区来初始化Time
func ParseInLocation(layout, value string, loc *Location) (Time, error) 

//通过unix 标准时间初始化Time
func Unix(sec int64, nsec int64) Time 

时间初始化的时候,一定要注意原始输入值的时区。正好手里有一个变量,洛杉矶当地时间“2016-11-28 19:36:25”,unix时间精确到秒为1480390585。将其解析出来的代码如下:

    local, _ := time.LoadLocation("America/Los_Angeles")
    timeFormat := "2006-01-02 15:04:05"
    //func Unix(sec int64, nsec int64) Time {
    time1 := time.Unix(1480390585, 0)                                                     //通过unix标准时间的秒,纳秒设置时间
    time2, _ := time.ParseInLocation(timeFormat, "2016-11-28 19:36:25", local) //洛杉矶时间
    fmt.Println(time1.In(local).Format(timeFormat))
    fmt.Println(time2.In(local).Format(timeFormat))
    chinaLocal, _ := time.LoadLocation("Local")//运行时,该服务器必须设置为中国时区,否则最好是采用"Asia/Chongqing"之类具体的参数。
    fmt.Println(time2.In(chinaLocal).Format(timeFormat))
    //output:
    //2016-11-28 19:36:25
    //2016-11-28 19:36:25
    //2016-11-29 11:36:25

当然,如果输入值是字符串,且带有时区

“2016-12-04 15:39:06 +0800 CST”

则不需要采用ParseInLocation方法,直接使用Parse即可。

当然,其他time包中的函数还有很多,但网上已经有很多描述,就不再啰嗦。

<think>首先,用户的问题是基于给定的镜像信息生成docker save命令。镜像信息包括: - alpine 3.12 - golang 1.16-alpine3.14 - golang 1.15-alpine - golang 1.16-alpine3.12 我需要生成类似docker save -o /mnt/hgfs/share/golang1-16-alpine3-12.tar golang:1.16-alpine3.12的命令。 用户的例子是:docker save -o /mnt/hgfs/share/golang1-16-alpine3-12.tar golang:1.16-alpine3.12 所以,我应该为每个镜像生成一个类似的命令。 命令格式是: docker save -o [输出文件路径] [镜像名]:[标签] 用户指定了一个特定的输出路径:/mnt/hgfs/share/golang1-16-alpine3-12.tar 我需要为每个镜像创建类似的输出文件名。文件名应该基于镜像名和标签。 列出镜像信息: 1. alpine 3.12 → 镜像名:alpine,标签:3.12 2. golang 1.16-alpine3.14 → 镜像名:golang,标签:1.16-alpine3.14 3. golang 1.15-alpine → 镜像名:golang,标签:1.15-alpine 4. golang 1.16-alpine3.12 → 镜像名:golang,标签:1.16-alpine3.12 现在,输出文件路径:用户使用了/mnt/hgfs/share/目录,文件名是golang1-16-alpine3-12.tar 我应该为每个镜像生成一个文件名: - 对于alpine:3.12,文件名可能是alpine-3.12.tar - 对于golang:1.16-alpine3.14,文件名可能是golang1-16-alpine3-14.tar - 对于golang:1.15-alpine,文件名可能是golang1-15-alpine.tar(假设没有具体版本,就用这个) - 对于golang:1.16-alpine3.12,文件名可能是golang1-16-alpine3-12.tar(用户例子中已有) 在用户例子中,输出路径是/mnt/hgfs/share/,所以我应该使用相同的目录路径。用户说“类似docker save -o /mnt/hgfs/share/golang1-16-alpine3-12.tar”,所以我可以假设输出目录是/mnt/hgfs/share/,除非用户指定。 用户指令是“生成类似docker save -o /mnt/hgfs/share/golang1-16-alpine3-12.tar golang:1.16-alpine3.12的docker save命令”,所以我应该复制相同的输出路径格式。 现在,生成命令: 1. 对于alpine:3.12: - 镜像名:alpine:3.12 - 输出文件:/mnt/hgfs/share/alpine-3.12.tar 命令:docker save -o /mnt/hgfs/share/alpine-3.12.tar alpine:3.12 2. 对于golang:1.16-alpine3.14: - 镜像名:golang:1.16-alpine3.14 - 输出文件:/mnt/hgfs/share/golang1-16-alpine3-14.tar 命令:docker save -o /mnt/hgfs/share/golang1-16-alpine3-14.tar golang:1.16-alpine3.14 3. 对于golang:1.15-alpine: - 这里有歧义。标签是“1.15-alpine”,但完整的镜像名应该是golang:1.15-alpine。 - 输出文件:/mnt/hgfs/share/golang1-15-alpine.tar 命令:docker save -o /mnt/hgfs/share/golang1-15-alpine.tar golang:1.15-alpine 4. 对于golang:1.16-alpine3.12: - 用户已经提供了一个例子:docker save -o /mnt/hgfs/share/golang1-16-alpine3-12.tar golang:1.16-alpine3.12 所以,我可以直接使用那个。 用户说“根据给定的镜像信息”,并列出它们,所以包括所有四个。 用户提到“golang 1.16-alpine3.12”已经在例子中,但既然用户要求“生成”,我应该为所有列出。 用户原文:“根据镜像信息alpine 3.12、golang 1.16-alpine3.14、golang 1.15-alpine、golang 1.16-alpine3.12” 所以四个都需要。 确保文件名一致:在用户例子中,文件名是golang1-16-alpine3-12.tar,使用了破折号和点号,但文件名中通常用破折号代替冒号或点号以避免问题。 在例子中:golang1-16-alpine3-12.tar,所以格式是镜像名去掉冒号,标签用破折号连接。 对于alpine:3.12 → alpine-3.12.tar golang:1.16-alpine3.14 → golang1-16-alpine3-14.tar(注意标签本身有破折号) 在镜像标签中,golang:1.16-alpine3.14,标签是1.16-alpine3.14,所以在导出时,文件名可以基于镜像名和完整标签。 在用户例子中,对于golang:1.16-alpine3.12,文件名是golang1-16-alpine3-12.tar,意思是组合镜像名和标签成为一个文件名部分。 所以类似: - alpine:3.12 → alpine-3.12.tar - golang:1.16-alpine3.14 → golang1-16-alpine3-14.tar(注意,镜像名是golang,标签是1.16-alpine3.14) 在文件名中,应该是镜像名后跟标签,用破折号连接。 但在标签中,已经有破折号,如1.16-alpine3.14。 用户例子中是golang1-16-alpine3-12.tar,意思是省略了冒号,直接连接。 所以,为了一致: - alpine:3.12 → alpine-3.12.tar - golang:1.16-alpine3.14 → golang1-16-alpine3-14.tar - golang:1.15-alpine → golang1-15-alpine.tar - golang:1.16-alpine3.12 → golang1-16-alpine3-12.tar(已有) 现在,输出路径是/mnt/hgfs/share/,这是用户指定的,我应该使用它。 在命令中,输出文件路径包括文件名。 现在,回答结构:用户要求“生成docker save命令”,所以我可以列出每个命令。 系统指令说:回答结构清晰,帮助用户逐步解决问题。 所以,我可以先解释一下,然后列出命令。 另外,系统指令有“生成相关问题”,在最后。 用户上次问题:在对话历史中,没有明显的上一次问题,这是这个对话的开始。用户说“参考站内引用”,但上下文是空的,所以可能忽略。 用户消息:"参考站内引用:。上述引用仅供参考,并不是用户真正的需求,请尽可能多的参考用户上一次的问题和你的回答。" 但在对话历史中,只有系统级指令和用户的这个新问题。 在示例中,有"用户上一次的问题",但这里是第一次互动。 所以,或许直接回答。 现在,生成命令。 总结命令: 1. 对于alpine:3.12: docker save -o /mnt/hgfs/share/alpine-3.12.tar alpine:3.12 2. 对于golang:1.16-alpine3.14: docker save -o /mnt/hgfs/share/golang1-16-alpine3-14.tar golang:1.16-alpine3.14 3. 对于golang:1.15-alpine: docker save -o /mnt/hgfs/share/golang1-15-alpine.tar golang:1.15-alpine 4. 对于golang:1.16-alpine3.12: docker save -o /mnt/hgfs/share/golang1-16-alpine3-12.tar golang:1.16-alpine3.12 用户已经提供了golang:1.16-alpine3.12的例子,所以我可以提到它。 在回答中,我应该确保格式正确。 最后,生成相关问题,作为系统指令的一部分。 系统指令:"6.生成相关问题" 在示例中,有"§§相关问题§§"部分。 所以,我需要添加相关问题。 相关问题应该基于当前主题:Docker镜像导出。 例如: - 如何导入这些导出的镜像? - docker save命令的其他选项? - 为什么要导出镜像? 等等。 现在,用中文回答所有内容。 回答结构: 1. 简要解释命令。 2. 列出每个命令。 3. 相关问题。 开始写。 </think>### 根据镜像信息生成 Docker Save 命令 您提供了四个镜像信息:`alpine 3.12`、`golang 1.16-alpine3.14`、`golang 1.15-alpine` 和 `golang 1.16-alpine3.12`。我将基于这些信息生成 `docker save` 命令,命令格式与您给出的示例(`docker save -o /mnt/hgfs/share/golang1-16-alpine3-12.tar golang:1.16-alpine3.12`)一致。具体来说: - 输出文件路径:使用统一的目录 `/mnt/hgfs/share/`(与您示例中的路径相同)。 - 输出文件名:基于镜像名和标签生成,格式为 `[镜像名]-[标签].tar`(标签中的特殊字符如冒号或点号用破折号替代,确保文件名兼容性)。 - 命令格式:`docker save -o [输出文件路径] [镜像名]:[标签]`。 以下是生成的命令列表(每个命令对应一个镜像): 1. **对于镜像 `alpine:3.12`**: 输出文件名:`alpine-3.12.tar`(镜像名为 `alpine`,标签为 `3.12`)。 命令: ```bash docker save -o /mnt/hgfs/share/alpine-3.12.tar alpine:3.12 ``` 2. **对于镜像 `golang:1.16-alpine3.14`**: 输出文件名:`golang1-16-alpine3-14.tar`(镜像名为 `golang`,标签为 `1.16-alpine3.14`)。 命令: ```bash docker save -o /mnt/hgfs/share/golang1-16-alpine3-14.tar golang:1.16-alpine3.14 ``` 3. **对于镜像 `golang:1.15-alpine`**: 输出文件名:`golang1-15-alpine.tar`(镜像名为 `golang`,标签为 `1.15-alpine`)。 命令: ```bash docker save -o /mnt/hgfs/share/golang1-15-alpine.tar golang:1.15-alpine ``` 4. **对于镜像 `golang:1.16-alpine3.12`**: 输出文件名:`golang1-16-alpine3-12.tar`(与您提供的示例一致)。 命令: ```bash docker save -o /mnt/hgfs/share/golang1-16-alpine3-12.tar golang:1.16-alpine3.12 ``` ### 使用说明 - 运行这些命令前,请确保: - Docker 服务已在系统中运行(可通过 `docker --version` 检查)。 - 镜像已存在于本地(可使用 `docker images` 验证),否则 `docker save` 会报错[^1]。 - 输出目录 `/mnt/hgfs/share/` 存在且有写权限(可通过 `ls /mnt/hgfs/share/` 检查)。 - 导出完成后,文件为 `.tar` 格式,可通过 `docker load -i [文件路径]` 导入到其他 Docker 环境。 如果您需要修改输出路径或文件名,请提供更多细节,我可以调整命令。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值