如何使用Linux Date命令解析ISO8601日期


15

我正在尝试使用date命令来生成date命令本身可以解释的文件时间戳。但是,date命令似乎不喜欢它自己的输出,并且我不确定如何解决此问题。例子:

sh-4.2$ date
Fri Jan  3 14:22:19 PST 2014
sh-4.2$ date +%Y%m%dT%H%M
20140103T1422
sh-4.2$ date -d "20140103T1422"
Thu Jan  2 23:22:00 PST 2014

date似乎在解释字符串,偏移量为15小时。有任何已知的解决方法吗?

编辑:这不是显示问题:

sh-4.2$ date +%s
1388791096
sh-4.2$ date +%Y%m%dT%H%M
20140103T1518
sh-4.2$ date -d 20140103T1518 +%s
1388737080
sh-4.2$ python
Python 3.3.3 (default, Nov 26 2013, 13:33:18) 
[GCC 4.8.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 1388737080 - 1388791096
-54016
>>> 54016/3600
15.004444444444445
>>> 

当显示为unix时间戳时,它仍然关闭15个小时。

编辑#1

也许我应该以不同的方式提出这个问题。说我有以下形式的ISO8601基本时间戳的列表:

  • YYYYMMDDThhmm
  • YYYYMMDDThhmmss

将它们转换为相应的Unix时间戳的最简单方法是什么?

例如:

- 20140103T1422   = 1388787720
- 20140103T142233 = 1388787753

1
@drewbenn我在时间戳中不能有任何特殊字符。只是数字和字母。因此,不幸的是,我不能这样做。
alex.forencich 2014年

未设置@sim TZ,但/ etc / localtime已链接。
alex.forencich 2014年

你杀了我,这是你最后的问题吗?8
slm

20140103T1518是无效的ISO 8601,它错过了时区部分
Ferrybig'Dec 19''16

Answers:


9

您要求“已知的解决方法”。这是一个简单的例子:

$ date -d "$(echo 20140103T1422 | sed 's/T/ /')"
Fri Jan  3 14:22:00 PST 2014

这用于sed用空格替换“ T”。结果是一种可以date理解的格式。

如果我们在ISO8601日期上增加秒数,则date需要进行更多更改:

$ date -d "$(echo 20140103T142211 | sed -r 's/(.*)T(..)(..)(..)/\1 \2:\3:\4/')"
Fri Jan  3 14:22:11 PST 2014

在上面,sed用空格替换“ T”,并将HHMMSS分隔为HH:MM:SS。


如果+被删除,对我有用。但是,它不适用于秒精度时间戳,仅适用于分钟精度。
alex.forencich 2014年

@ alex.forencich答案以秒精度更新。让我知道我选择的秒格式是否不是您需要的秒格式。
2014年

8

coreutils的信息文档说,ISO 8601“扩展格式”的支持。

您需要添加连字符,冒号和a +%z使其起作用。

$ date +"%Y-%m-%dT%H:%M:%S%z"
2014-01-03T16:08:23-0800
$ date -d 2014-01-03T16:08:23-0800
Fri Jan  3 16:08:23 PST 2014

要回答问题的第二部分...

由于日期格式仅包含数字和符号,因此您可以将每个符号替换为唯一字母,例如使用 tr

$ ts="$(date +"%Y-%m-%dT%H:%M:%S%z" | tr -- '-:+' 'hcp')"; echo "$ts"
2014h01h03T16c18c04h0800
$ date -d "$(echo "$ts" | tr -- 'hcp' '-:+')"
Fri Jan  3 16:18:04 PST 2014

或者,您可以使用T和和-+作为分隔符来解析它,例如使用shell ${var%word}${var#word}扩展

$ ts="$(date +"%Y%m%dT%H%M%S%z")"; echo "$ts"
20140103T162228-0800
$ date=${ts%T*}; time=${ts#*T}
etc.    

或使用bash正则表达式匹配

$ ts="$(date +"%Y%m%dT%H%M%S%z")"; echo "$ts"
20140103T165611-0800
$ [[ "$ts" =~ (.*)(..)(..)T(..)(..)(..)(.....) ]]
$ match=("${BASH_REMATCH[@]}")
$ Y=${match[1]}; m=${match[2]}; d=${match[3]}; H=${match[4]}; M=${match[5]}; S=${match[6]}; z=${match[7]}
$ date -d "$Y-$m-$d"T"$H:$M:$S$z"
Fri Jan  3 16:56:11 PST 2014

或Perl,Python等,等等。


时间戳记中不能包含任何特殊字符。您知道自动添加这些内容的好方法吗?
alex.forencich 2014年

6

版本8.13起,GNU coreutils仅支持将ISO 8601日期作为输入。(于2011-09-08发行)。您必须使用旧版本。

在旧版本中,您需要用T空格替换。否则,它将被解释为美国军事时区

即使在最新版本下,也只能识别全标点符号,而不能识别仅包含数字和T中间的a的基本格式。

# Given a possibly abbreviated ISO date $iso_date...
date_part=${iso_date%%T*}
if [ "$date_part" != "$iso_date" ]; then
  time_part=${abbreviated_iso_date#*T}
  case ${iso_date#*T} in
    [!0-9]*) :;;
    [0-9]|[0-9][0-9]) time_part=${time_part}:00;;
    *)
      hour=${time_part%${time_part#??}}
      minute=${time_part%${time_part#????}}; minute=${minute#??}
      time_part=${hour}:${minute}:${time_part#????};;
  esac
else
  time_part=
fi
date -d "$date_part $time_part"

2

我确实在的手册页中注意到了此注释date

DATE STRING
      The --date=STRING is a mostly free format human readable date string
      such as "Sun, 29 Feb 2004 16:21:42 -0800"  or  "2004-02-29
      16:21:42"  or  even  "next Thursday".  A date string may contain 
      items indicating calendar date, time of day, time zone, day of
      week, relative time, relative date, and numbers.  An empty string 
      indicates the beginning of the day.  The date  string  format
      is more complex than is easily documented here but is fully described 
      in the info documentation.

它不是确定性的,但T对于[ISO 8601],它没有明确显示包含您尝试的时间格式字符串。如@Gilles答案所示,GNU CoreUtils支持ISO 8601相对较新。

重新格式化字符串

您可以使用Perl重新格式化您的字符串。

例:

$ date -d "$(perl -pe 's/(.*)T(\d{2})(\d{2})(\d{2})/$1 $2:$3:$4/' \
    <<<"20140103T142233")"
Fri Jan  3 14:22:33 EST 2014

您可以使此处理包含秒数的字符串和不包含秒数的字符串。

20140103T1422:

$ date -d "$(perl -pe 's/^(.*)T(\d{2})(\d{2})(\d{2})$/$1 $2:$3:$4/ || \
     s/^(.*)T(\d{2})(\d{2})$/$1 $2:$3:00/' <<<"20140103T1422")"
Fri Jan  3 14:22:00 EST 2014

20140103T142233:

$ date -d "$(perl -pe 's/^(.*)T(\d{2})(\d{2})(\d{2})$/$1 $2:$3:$4/ || \
     s/^(.*)T(\d{2})(\d{2})$/$1 $2:$3:00/' <<<"20140103T142233")"
Fri Jan  3 14:22:33 EST 2014

@ alex.forencich-处理两种时间格式的替代命令。请帮个忙,删除上面不再相关的评论。
slm

1

根据日期的手册页,您输出的格式与date期望输入的格式不同。这是手册页所说的:

date [-u|--utc|--universal] [MMDDhhmm[[CC]YY][.ss]]

所以你可以这样:

# date +%m%d%H%M%Y
010402052014
# date 010402052014
Sat Jan  4 02:05:00 EAT 2014

因为在用于定义输出字符串的变量中,+%m%d%H%M%Y它将等于它期望作为输入的值。


然后,您可以提供一个命令来将ISO8601格式的日期映射到所需的日期吗?实际存储的时间戳必须采用ISO8601格式,以便可以按日期对它们进行排序。
alex.forencich 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.