SWI-Prolog中的"strptime"

4
如何将原子'2015-12-15T05 PST'转换为时间戳或日期时间?
我已经尝试使用parse_time/3
?- parse_time('2015-12-15T05 PST', '%Y-%m-%dT%H %Z', Stamp)
false.

format_time/3相关的内容:

?- format_time('2015-12-15T05 PST', '%Y-%m-%dT%H %Z', date(Y,M,D,H,M,S,O,TZ,DST)).
ERROR: format_time/3: Arguments are not sufficiently instantiated
2个回答

3
根据文档,format_time/3的模式并不能真正帮助你,因为它期望传入所有参数:

format_time(+Out, +Format, +StampOrDateTime)

这意味着你需要提供每一个参数。你想看到一个具有 - 前缀的东西,它意味着它会返回一些东西,似乎应该是使用 parse_time/3,但是文档中说:

Text 的支持格式在下表中列出。

然后它继续列出了两个选项:rfc_1123iso_8601,都不能真正匹配你的格式。这里似乎没有提供格式代码的方法,这让我感到非常困惑,因为这里有底层的Unix库可以做到这一点。

然而,这个问题可以用大家最喜欢的工具来解决:确定性语法!这是我的解决方案:

:- use_module(library(dcg/basics)).

myformat(date(Y,M,D,H,_,_,_,TZ,_)) -->
    integer(Y), "-", integer(M), "-", integer(D),
    "T", integer(H), " ", timezone(TZ).

timezone('UTC') --> "UTC".
timezone('UTC') --> "GMT".
timezone(-18000) --> "PST".
timezone(Secs) -->
    [Sign], digit(H0), digit(H1), digit(M0), digit(M1),
    {
     (Sign = 0'+ ; Sign = 0'-),
     number_codes(Hour, [H0,H1]),
     number_codes(Minutes, [M0, M1]),
     (Sign = 0'+
     -> Secs is Hour * 3600 + Minutes * 60
     ;  Secs is -(Hour * 3600 + Minutes * 60))
    }.

my_time_parse(Atom, Date) :-
    atom_codes(Atom, Codes),
    phrase(myformat(Date), Codes).

我相信有经验的人会发现改进此代码的方法,但是对于您的样本数据,它已经能够解决问题。不幸的是,您需要枚举时区或找到更好的关于时区的数据来源(也许解析系统时区定义?),但是如果您事先知道只需要处理PST,您可以尝试使用它。以下是一个示例:

?- my_time_parse('2015-12-15T05 PST', Date).
Date = date(2015, 12, 15, 5, _G3204, _G3205, _G3206, -18000, _G3208) ;
false.

希望这能帮到你!

非常棒的解决方案。我从你的答案中学到了很多。只是希望有一个更方便的解决方案 :)。 - Fabricator
1
我也是... 我不完全确定为什么情况这么糟糕,但是一旦你有时间,你可以使用 julian,它非常有趣! - Daniel Lyons

0
来晚了,但是期望的格式与 iso_8601 很接近,它应该采用这种格式 "2015-12-15T05-08"。要将时区 "PST" 替换为 "-08",我们可以使用 append。代码如下:
:- set_prolog_flag(double_quotes, chars).

timezone(" PST", "-08").
timezone(" PDT", "-07").
%% etc

convert_time(Date, Stamp) :- 
    timezone(Zone, Delta),
    append(Front, Zone, Date),
    append(Front, Delta, Date2),
    string_chars(Date3, Date2),
    parse_time(Date3, iso_8601, Stamp).

test :-
    convert_time("2015-12-15T05 PST", Stamp),
    writeln('Stamp'=Stamp),
    fail.

带输出

?- test.
Stamp=1450184400.0
false.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接