这是我参与「第五届青训营 」伴学笔记创作活动的第 11 天
这篇笔记总结了大项目遇到的一些问题以及对这些问题的总结。本次是第四次大项目总结。
本篇总结主要总结的是在极简版抖音,显示好友的消息页面,即/douyin/message/chat中遇到的一些问题,本次总结的是UNIX时间戳的相关问题。
青训营大项目官方给的消息页面接口说明如下:
/douyin/message/chat/ - 聊天记录
当前登录用户和其他指定用户的聊天消息记录
接口类型
GET
接口说明
syntax = "proto2";
package douyin.extra.second;
message douyin_message_chat_request {
required string token = 1; // 用户鉴权token
required int64 to_user_id = 2; // 对方用户id
required int64 pre_msg_time=3;//上次最新消息的时间(新增字段-apk更新中)
}
message douyin_message_chat_response {
required int32 status_code = 1; // 状态码,0-成功,其他值-失败
optional string status_msg = 2; // 返回状态描述
repeated Message message_list = 3; // 消息列表
}
message Message {
required int64 id = 1; // 消息id
required int64 to_user_id = 2; // 该消息接收者的id
required int64 from_user_id =3; // 该消息发送者的id
required string content = 4; // 消息内容
optional string create_time = 5; // 消息创建时间
}
然而,当我按照要求返回Message后,好友消息页面却什么都不显示。这是怎么回事?我debug了许久之后发现,前端需要返回的create_time虽然是string类型,但是需要是UNIX时间戳类型,直接用Go中的time.now().string()得到的string型时间是无法显示的。那么,我们就需要把时间转换为UNIX时间戳。
Unix时间戳概念
首先,说一下UNIX时间戳的概念。UNIX时间戳(英文为Unix epoch, Unix time, POSIX time 或 Unix timestamp)是从1970年1月1日(UTC/GMT的午夜)开始所经过的秒数,不考虑闰秒。
UNIX时间戳的0按照ISO 8601规范为 :1970-01-01T00:00:00Z.
为什么要使用UNIX时间戳呢?使用UNIX时间戳是为了跨平台开发。在现在的系统中经常遇到跨数据库的应用开发,在数据库系统中不同的数据库对时间类型却有不同解释,比如ORACLE的date和MYSQL里面的date就不能直接兼容转换,为了实现垮平台在应用系统中记录时间的时候我们就可以使用记录UNIX时间戳的方法做到垮平台性。
转换UNIX时间戳
go对于时间格式有一种可以直接转换为UNIX时间戳的函数,假设时间变量为t,直接使用t.unix()即可得到UNIX时间戳,这个UNIX时间戳是int64类型。但显然,我们不能直接将go标准时间的字符串转为UNIX时间戳。
如果我们在Go中直接使用标准库time.now().string()得到的是Go标准时间,以以下时间为例子讲解:
2023-02-15 16:53:36.4535341 +0800 CST m=+128.958241901
2023-02-15 16:53:36是时间标准格式yyyy-mm-dd hh:mm:ss,即年-月-日 时:分:秒。- .
4535341是小数点后面的数字表示时间的纳秒部分。 +0800 CST代表时区偏移量,表示比协调世界时(UTC)快8个小时。而CST表示时区名称,指代中国标准时间(China Standard Time)。m=+128.958241901与UNIX时间戳类似,都表示了表示当前时间相对于某个基准时间的时间差。UNIX时间戳的基准时间是1970年1月1日,而Go标准时间的基准时间通常是程序启动时的时间。其中,m表示分钟数,+表示比基准时间晚,128表示时间差的绝对值,.958241901表示剩余的秒数部分。
为了得到UNIX时间戳,显然当前时间与程序启动时间的时间差不需要,因此首先需要剔除 m=+128.958241901 的部分。代码如下:
createTime := strings.Split(createTime_origin, " m=")[0]
我使用strings.Split函数将时间字符串以m=隔开,并取第一部分,就剔除了 m=+128.958241901 的部分。
其次,要将上述的字符串转换为time型,代码如下:
layout := "2006-01-02 15:04:05.9999999 -0700 MST"
createTime_timeFmt, _ := time.Parse(layout, createTime)
time.Parse()用于将字符串解析为时间对象,函数说明如下:
func Parse(layout, value string) (Time, error)
其中,layout 参数表示被解析的字符串的时间格式,例如 "2006-01-02 15:04:05",value 参数表示要解析的时间字符串,例如 "2023-02-15 16:53:36"。函数返回一个 time.Time 类型的时间对象和一个 error 类型的错误对象。如果解析成功,错误对象为 nil,否则为相应的错误信息。
layout 参数中的 "2006-01-02 15:04:05.9999999 -0700 MST" 是一个特殊的时间格式,它表示年份使用四位数,月份、日期、小时、分钟、秒钟、纳秒、时区偏移量、时区名。这个时间格式的出现是为了方便时间的解析和格式化。
一般将string型的时间转为Time类型,layout都选取"2006-01-02 15:04:05.9999999 -0700 MST"。
此外,如果我的时间格式为yyyy-mm-dd hh:mm:ss,那layout也要相应的进行简化,选取2006-01-02 15:04:05。
最后,将转换成功的时间类型转换为UNIX时间戳,并重新转回字符串类型以便传值,代码如下:
createTime_unix := strconv.FormatInt(createTime_timeFmt.Unix(), 10)
前文已经提到,直接使用.unix()函数就可以得到int64类型的UNIX时间戳,但我们需要string类型,因此使用strconv.FormatInt()函数将整数值转换为字符串类型并返回,这个函数定义如下:
func FormatInt(i int64, base int) string
其中,base指的是进制数,一般取10即可。
综上所述,我们就将一个Go标准时间转换为了字符串型的UNIX时间戳,现在就可以成功在消息页面上显示消息了。