【问题标题】:linux bash - Parse date in custom formatlinux bash - 以自定义格式解析日期
【发布时间】:2013-12-19 21:16:51
【问题描述】:

我有一个%c 格式的日期(可以是其他格式),我需要在 date 命令中使用它。 %c 不是美国格式。它是德国服务器,因为它是德国服务器。这在美国服务器上也无法正常工作。 (区域设置为德语或美国)

这不起作用(包括错误):

user@server:~$ NOW=$(date +%c); echo $NOW
Do 19 Dez 2013 22:33:28 CET
user@server:~$ date --date="$NOW" +%d/%m/%Y
date: ungültiges Datum „Do 19 Dez 2013 22:33:28 CET“

(日期:ungültiges Datum „Do 19 Dez 2013 22:33:28 CET“=date: invalid date „Do 19 Dez 2013 22:33:28 CET“

困难在于我不知道以后会使用哪个语言环境甚至哪个日期格式,因为用户可以设置自己的格式。所以一个简单的特定解析解决方案是行不通的!

但是我该怎么做呢?

概括问题:

如果我有一个日期格式format1(可以是任何或至少一个可以反转的)我可以使用日期来获取格式化的日期。但是,如果我想将其格式化为另一个日期 (format2),我该怎么做?
任何使用 coreutils 以外的解决方案都是没有意义的,因为我正在尝试为尽可能多的 unix 机器开发一个 bash 脚本。

DATE=$(date "+$format1")

date --date="$DATE" "+$format2" # Error in most cases!

这是必需的,因为我有一个用户可以提供日期格式的命令。将显示此日期字符串。但在后面的步骤中,我需要将此日期字符串转换为另一个固定的日期字符串。我可以操纵命令将获得的 whcih 格式,并且可以操纵输出 (或用户将看到的内容)
我无法运行该命令两次,因为它非常耗时。


更新:

我找到了类似的解决方案:

# Modify $user_format so it can be parsed later
user_format="$user_format %s"

# Time consuming command which will print a date in the given format
output=$(time_consuming_command params "$user_format" more params)

# This will only display what $user_format used to be
echo ${output% *}

# A simple unix timestamp parsing ("${output##* }" will only return the timestamp)
new_formated_date=$(date -d "1970-01-01 ${output##* } sec UTC" "+$new_format")

这是有效的,可能对其他人有帮助。因此,我将与您分享。

【问题讨论】:

  • 为什么这不起作用?你遇到了什么错误?
  • 嗯,我们可以看看你的date +%c的输出吗?
  • env | grep ^LC的输出是什么
  • 使用 format1 获取当前日期然后使用它以 format2 打印有什么意义?你不能直接在 formrat2 中获取当前日期吗?如果您在非当前日期尝试此操作,例如从文件或表中提取的日期,那么它会更有意义。
  • 您能否更好地解释一下具体的用例?我认为您不能使用这种通用方法,尤其是仅使用 bash 和 coreutils .. (有些库试图猜测日期时间格式,但当然它们既不完美也不在任何标准库中.. )

标签: linux bash parsing date


【解决方案1】:

从 GNU coreutils 8.22 开始,--date 不可能。来自日期手册:

'-d datestr'

‘--date=datestr’

显示 datestr 中指定的日期和时间,而不是当前 日期和时间。 datestr 几乎可以是任何常见格式。它可以 包含月份名称、时区、“am”和“pm”、“yesterday”等。对于 例如, --date="2004-02-27 14:19:13.489392193 +0530" 指定 2 月 27 日之后 489,392,193 纳秒的瞬间, 2004 年下午 2:19:13,时区为东 5 小时 30 分钟 UTC。

注意:当前输入必须是独立于语言环境的格式。例如, 需要下面的 LC_TIME=C 才能打印出许多正确的日期 语言环境:

date -d "$(LC_TIME=C date)"

http://www.gnu.org/software/coreutils/manual/html_node/Options-for-date.html#Options-for-date

请注意,输入格式不能是特定于语言环境的格式。

可能还有其他库或程序可以识别更多日期格式,但对于给定的日期格式,编写一个短程序将其转换为日期可识别的格式(例如,使用 Perl 或 awk)并不难。

【讨论】:

  • 感谢您的信息,但此解决方案对我没有帮助。我不确定它将是哪种日期格式,因此我无法使用特定的解析方法。
  • 谢谢!我的语言环境 ("en_GB.UTF-8") 一直在制造麻烦。前缀LC_TIME=C 修复了它!奇怪的是,我系统手册页中的文本要短得多(Manjaro,coreutils 8.30-1)
【解决方案2】:

如果您的意思是格式错误,我认为您想要的是:

NOW=$(date +%c)
date --date="$NOW" +%d/%m/%Y

注意小写的%d%m

在本地,这是我得到的:

root@server2:~# NOW=$(date +%c)
root@server2:~# date --date="$NOW" +%d/%m/%Y
19/12/2013

【讨论】:

  • 不解析。我不关心输出日期格式输入日期格式是重要的!
【解决方案3】:

您为什么不将时间存储为 unixtime(即自 1970 年 1 月 1 日以来的毫秒数),例如 1388198714

尝试将来自世界各地的所有日期格式解析为没有合理依赖关系的一次性 bash 脚本的请求练习有点荒谬。

【讨论】:

  • 我同意。正如 OP 所说:“我不知道以后会使用哪个语言环境甚至哪个日期格式,因为用户可以设置自己的格式。”想象一下数字月份会发生什么(美国:2013 年 12 月 9 日,德国:2013 年 9 月 12 日)。保证误解!不惜一切代价避免使用用户配置的输出作为额外脚本的输入。
  • 我在我的问题中提出了类似的建议。我认为这样的事情将是最好的解决方案。
【解决方案4】:

您可以使用libdatetime-format-flexible-perl

#!/usr/bin/perl
use DateTime::Format::Flexible;
my $date_str = "So 22 Dez 2013 07:29:35 CET";
$parser = DateTime::Format::Flexible->new;
my $date = $parser->parse_datetime($date_str);
print $date

默认输出为2013-12-22T07:29:35,但由于$date 不是常规字符串而是对象,您可以执行以下操作:

printf '%02d.%02d.%d', $date->day, $date->month, $date->year;

另外date 的行为可能应该被视为一个错误。我认为是这样,因为格式相同但俄语的日期被正确解析。

$ export LC_TIME=ru_RU.UTF-8
$ NOW="$(date "+%c")"
$ date --date="$NOW" '+%d.%m.%Y'
22.12.2013

【讨论】:

  • 好吧。正如@Gavin Smith 所说,我对 GNU Date 的看法是错误的——这种行为不应被视为错误。特别是因为俄罗斯日期没有正确解析。它不会失败,是的。但将任何日期识别为当前日期:$ date --date="Вск 1 Дек 2013 06:09:16" 将产生 Вск Дек 22 00:00:00 MSK 2013
  • 我有两个问题: 1. 这个总是安装的吗? 2. 这适用于所有日期格式吗?
  • @BrainStone 1. 当然,libdatetime-format-flexible-perl 并不总是安装——甚至 Perl 也并非总是默认安装。但它仍然比date --date(GNU 扩展)更便携,因为它不仅在 GNU 上可用,而且在 FreeBSD、OS X 等上也可用。
  • @BrainStone 2. 它假装能够解析任何明确的格式。但是可以肯定的是,您可以发明一种人类可以阅读但该模块无法阅读的产品。例如。它无法解析时间提前的字符串:12:00 01 März 2013(虽然我不知道任何工具使用这种格式)。显然,它无法区分10/12/201312 Oct10/12/201310 Dec。第一个(美式风格)是默认设置,但您可以使用european => 1 选项覆盖它。
  • @DimitryAlexandrov 那么它不符合我的需要。我需要它才能在几乎任何 GNU 系统上工作。我正在编写的脚本是针对这些系统的,我不能假设除了安装默认工具之外的任何东西......但仍然是一个值得注意的解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-01
相关资源
最近更新 更多