一想到日期格式,不免得想起java类SimpleDateFormat
中经典的yyyy-MM-dd hh:mm:ss格式,但可惜--date
并不支持这种格式
想查查git的命令参数,自然是先上官方文档,跳到https://git-scm.com/docs一看,很快就找到Basic Snapshotting下的commit,点进去翻到OPTIONS里找到--date=<date>
项,发现只写了句
Override the author date used in the commit.
这没有细说格式,就这么草草一句介绍,只能看看是不是下面有附录说明,果然找到了DATE FORMATS,https://git-scm.com/docs/git-commit#_date_formats
The GIT_AUTHOR_DATE, GIT_COMMITTER_DATE environment variables and the --date option support the following date formats:
Git internal format
It is<unix timestamp>
<time zone offset>
, where<unix timestamp>
is the number of seconds since the UNIX epoch.<time zone offset>
is a positive or negative offset from UTC. For example CET (which is 1 hour ahead of UTC) is +0100.RFC 2822:
The standard email format as described by RFC 2822, for example Thu, 07 Apr 2005 22:13:13 +0200.ISO 8601:
Time and date specified by the ISO 8601 standard, for example 2005-04-07T22:13:13. The parser accepts a space instead of the T character as well. Fractional parts of a second will be ignored, for example 2005-04-07T22:13:13.019 will be treated as 2005-04-07T22:13:13.Note:
In addition, the date part is accepted in the following formats: YYYY.MM.DD, MM/DD/YYYY and DD.MM.YYYY.
这里提到了三种格式
“内部”格式
这个“内部”格式又分为两种,一是unix timestamp,二是time zone offset。
其中,unix timestamp指的其实就是timestamp,时间戳一般都特指unix timestamp,这种表示方法很科学,其他系统平台都是照搬的,其实并不分什么Unix,只是因为Unix系统最初使用这种long表示date的格式罢了,java的System.currentTimeMillis()
,javascript的+new Date()
取出的值都是unix timestamp。
而time zone offset,其实就是在unix timestamp后加上时区,例如1599020738028 +0800,仅此而已
RFC 2822格式
RFC互联网标准,虽然RFC中没有单独的规定一个日期应该怎么表示,但RFC制定了邮件消息格式,其中3.3规定了邮件中如何表示日期的格式,翻到https://tools.ietf.org/html/rfc2822#section-3.3有极为详尽的介绍,格式是"周,日 月 年 时:分:秒 时区",例如Wed, 02 Sep 2020 13:09:52 +0800
,在国内其实比较少见,不太符合我们的文法
ISO 8601格式
国际标准ISO制定的8601很好看,年月日时分秒,符合大多数人的习惯,例如2020-09-02T13:11:11+08:00,还可以简写为20200902T131111+08,用T
隔开日期和时间
看了文档又想看看源码到底怎么写的,这几年会不会有些新格式兼容了又没改文档,众所周知文档写完万年不改的,我翻到合并这个功能修改的commit,https://github.com/git/git/commit/d939af12bd96db7ad3e671a0585ad8570aa7e9d3
一看前面的几个文件,发现这个contributors把一个公用常量从枚举改成了struct,随后有一系列伴随这个改动的修改,我直接查找DATE_ISO8601_STRICT
看看有没有测试用例,遗憾的是并没有专门测试这些字符串的用例,但在builtin/blame.c里发现居然是有一些用例,这个switch并不是parse时间的,但是是用来获取不同时间格式对应的字符串长度的,但应该也是一样的,直接转到这一行最新的master分支,https://github.com/git/git/blob/aa9166bcc0ba654fc21f198a30647ec087f733ed/builtin/blame.c#L993
这个switch从993行到1034行,一共10个case,果然文档还是有所遗漏。这10个case每一项都直接有用例了,源码部分如下(这也是一段祖传代码了):
switch (blame_date_mode.type) {
case DATE_RFC2822:
blame_date_width = sizeof("Thu, 19 Oct 2006 16:00:04 -0700");
break;
case DATE_ISO8601_STRICT:
blame_date_width = sizeof("2006-10-19T16:00:04-07:00");
break;
case DATE_ISO8601:
blame_date_width = sizeof("2006-10-19 16:00:04 -0700");
break;
case DATE_RAW:
blame_date_width = sizeof("1161298804 -0700");
break;
case DATE_UNIX:
blame_date_width = sizeof("1161298804");
break;
case DATE_SHORT:
blame_date_width = sizeof("2006-10-19");
break;
case DATE_RELATIVE:
/*
* TRANSLATORS: This string is used to tell us the
* maximum display width for a relative timestamp in
* "git blame" output. For C locale, "4 years, 11
* months ago", which takes 22 places, is the longest
* among various forms of relative timestamps, but
* your language may need more or fewer display
* columns.
*/
blame_date_width = utf8_strwidth(_("4 years, 11 months ago")) + 1; /* add the null */
break;
case DATE_HUMAN:
/* If the year is shown, no time is shown */
blame_date_width = sizeof("Thu Oct 19 16:00");
break;
case DATE_NORMAL:
blame_date_width = sizeof("Thu Oct 19 16:00:04 2006 -0700");
break;
case DATE_STRFTIME:
blame_date_width = strlen(show_date(0, 0, &blame_date_mode)) + 1; /* add the null */
break;
}
可以学习其中的用例进行一些测试:
git commit --date="2012-12-12"
git commit --date="2012-12-12 12:12:12 0800"
git commit --date="2012-12-12T12:12:12+08:00"
git commit --date="2 minutes ago"
测试发现都是可以的,关于第一种格式要注意的是只写年份不写时间的话,时间是会跟着走的,不会设个默认的0点0分之类的操作。例如现在是5点半,时间设为2012年12月12日,完整的时间戳就会表现为2012年12月12日五点半。
写于2021年4月13日,于2023年7月11日进行了一些修订。