真日期时间格式

原创
2018/02/09 14:49
阅读数 372

程序语言几乎都设计了日期时间字符串解析格式. 事实上为了便于阅读

正常的日期时间字符串没有二义性

例:

Mon Jan 2 15:04:05 2006
Mon Jan 02 15:04:05 -0700 2006"
02 Jan 06 15:04 -0700
Monday, 02-Jan-06 15:04:05
Mon, 02 Jan 2006 15:04:05
Mon, 02 Jan 2006 15:04:05 -0700
2006-01-02T15:04:05Z07:00
2006-01-02T15:04:05.999999999Z07:00
2006 01 02T15:04:05.999999999
2006 01 02 15:04:05.999999999 -07:00

正常格式有以下特征:

  1. 第几周使用单词表示
  2. 年份用四位数字表示
  3. 年月日分隔符采用 /\s*[-\/,]?\s*/
  4. 时分秒间总是有分隔符的, 通常是冒号 h:m:s 或 h:m
  5. 秒尾数采用格式 /\.\d{3,9}/ 表示毫秒,微妙或纳秒
  6. 所有出现的单词(连续的字母)可用前三位区分

正如 Simplified ISO 8601 所述, 单词表示的时区频繁变更, 模糊且不可靠, 只采用 UTC 偏移量:

UTC 偏移量 `/(Z|GMT|UTC)([+-]?)(\d{0,2}):?(\d{0,2})/`
或与 `h:m:s` 无冲突的 `/([+-])(\d{1,2}):?(\d{0,2})/`

作者为正常的日期时间字符串设计了 True Time Format, 并支持:

  1. 缺省百年值
  2. 夏令时
  3. 纳秒
  4. 闰秒

layout

layout 是为了告知解析器缺省百年值, UTC 偏移量, Y,M,D,h,m,s 次序缺省为 YMDhms.

非 YMDhms 次序或无分隔符的紧凑(脏)年月日组合需要定义该次序

例如:

MDYhms

可匹配: 参见算法部分对特殊部分的识别

120199 T03/04/05
12-01-99 T03:04:05.999
12011999 T03/04/05LSCZ
Jun 01 1999 DST03/04/05 Z+0800
Jun-01-1999Z+0800 DST03/04/05

规则

  1. 不关心分隔符
  2. 缺省认为 hms 在数据尾部
  3. 缺省 layout 为 YMDhms 并允许部分匹配

缺省百年值

layout 可选数字前缀表示缺省的百年值, 比如 '19' 表示如果匹配到 2 位数的年份那么表示 19xx 年.

Y

Y 在 layout 中表示年份

/\d{1,4}/

如果年份不足 4 位且没有在 layout 中标示 YMD 顺序, 解析结果可能不正确.

M

M 在 layout 中表示月份, 1 或 2 位的数字或无数字单词表示的月份

/\d{1,2}/

支持表示月份的单词前缀(不区分大小写).

[
"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"
]

D

D 表示数字的日(1-31).

第 1,3,5,7,8,10,12 月 1-31 天. 第 4,6,9,11 月 1-30 天. 第 2 月平年 1-28 天, 闰年 1-29 天.

/\d{1,2}/

h

h 在 layout 中表示 24 小时制的小时(0-23), 数据可选时间前缀 'T' 或夏令时前缀 'DST'.

/(T|DST)?\d{1,2}/

m

m 在 layout 中表示分钟(0-59).

/\d{1,2}/

s

s 在 layout 中表示秒和可选的纳秒, 1 位或 2 位数字的秒(0-59), '60' 表示闰秒. 纳秒以 '.' 开头后跟 1 到 9 位数字. 数据可选闰秒补偿后缀 'LSC', 意味着期望在时间计算中考量闰秒影响.

/\d{1,2}(.\d{1,9})?(LSC)?/

每一个闰秒都必须对应确切的时间 leapseconds.

UTC 偏移量

layout 可选后缀 +hhmm-hhmm 表示缺省 UTC 偏移量, 默认值为 +0000.

数据中包含

/(Z|GMT|UTC)([+-]?)(\d{0,2}):?(\d{0,2})/

或与 h:m:s 无冲突的(忽略冲突算法描述)

`/([+-])(\d{1,2}):?(\d{0,2})/`

以 'Z','GMT','UTC' 结尾时表示 UTC+0000.

例子

格式

19YMDhms+0800

表示

  1. 数据以 '年月日时分秒' 的顺序组成
  2. 自动识别分隔符
  3. 如果匹配到 2 位数年份, 那么表示 19xx
  4. 如果数据没有包含 UTC 偏移量, 使用 +0800

该格式可以匹配

99-01-2 3:4:15
1999-1-2 3:4:5
1999-jan-2 3:4:5Z
1999-1-2 3:4:5.999 -0800
1999-1-2 3:4:5.000-0800
2000-01-2 T3:04:5 +08:00
2000-january-02DST03:04:5
990102 4:05:59
19990102T04:5:59
20000102T4:05:59
2016/12/31T23.59 60.001LSC

算法

识别并剔除周单词前缀, UTC 偏移量, 'LSC', 'DST', 'T', 纳秒.

/[^\dA-Za-z]+/ 分割得到 Y,M,D,h,m,s 组成的数组.

如果数组个数和 layout 长度一样, 按顺序识别即可.

否则以每个数字元素的长度和单词(标记位 M)形成 form. 如 :

422222
4M2222
222222
2M2222
224222
M24222
2M4222
M24
2M4
8222
6222

其中 82226222 会被拆分成 422222222222.

根据 form 可猜测最可能的 layout 来识别数据.

对难于猜测的 form, 可选择识别失败或尝试某种 layout 的可能.

展开阅读全文
加载中

作者的其它热门文章

打赏
0
0 收藏
分享
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部