View source with raw comments or as raw
    1/*  Part of SWI-Prolog
    2
    3    Author:        Jan Wielemaker and Willem Robert van Hage
    4    E-mail:        wielemak@science.uva.nl
    5    WWW:           http://www.swi-prolog.org
    6    Copyright (c)  2006-2014, University of Amsterdam
    7    All rights reserved.
    8
    9    Redistribution and use in source and binary forms, with or without
   10    modification, are permitted provided that the following conditions
   11    are met:
   12
   13    1. Redistributions of source code must retain the above copyright
   14       notice, this list of conditions and the following disclaimer.
   15
   16    2. Redistributions in binary form must reproduce the above copyright
   17       notice, this list of conditions and the following disclaimer in
   18       the documentation and/or other materials provided with the
   19       distribution.
   20
   21    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   22    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   23    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   24    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   25    COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   26    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   27    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   28    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   29    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   30    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   31    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   32    POSSIBILITY OF SUCH DAMAGE.
   33*/
   34
   35:- module(date,
   36          [ date_time_value/3,          % ?Field, ?DaTime, ?Value
   37            parse_time/2,               % +Date, -Stamp
   38            parse_time/3,               % +Date, ?Format, -Stamp
   39            day_of_the_week/2,          % +Date, -DayOfTheWeek
   40            day_of_the_year/2           % +Date, -DayOfTheYear
   41          ]).

Process dates and times

*/

 date_time_value(?Field:atom, +Struct:datime, -Value) is nondet
Extract values from a date-time structure. Provided fields are
yearinteger
month1..12
day1..31
hour0..23
minute0..59
second0.0..60.0
utc_offsetintegerOffset to UTC in seconds (positive is west)
daylight_savingboolName of timezone; fails if unknown
datedate(Y,M,D)
timetime(H,M,S)
   61date_time_value(year,            date(Y,_,_,_,_,_,_,_,_), Y).
   62date_time_value(month,           date(_,M,_,_,_,_,_,_,_), M).
   63date_time_value(day,             date(_,_,D,_,_,_,_,_,_), D).
   64date_time_value(hour,            date(_,_,_,H,_,_,_,_,_), H).
   65date_time_value(minute,          date(_,_,_,_,M,_,_,_,_), M).
   66date_time_value(second,          date(_,_,_,_,_,S,_,_,_), S).
   67date_time_value(utc_offset,      date(_,_,_,_,_,_,O,_,_), O).
   68date_time_value(time_zone,       date(_,_,_,_,_,_,_,Z,_), Z) :- Z \== (-).
   69date_time_value(daylight_saving, date(_,_,_,_,_,_,_,_,D), D) :- D \== (-).
   70
   71date_time_value(date,            date(Y,M,D,_,_,_,_,_,_), date(Y,M,D)).
   72date_time_value(time,            date(_,_,_,H,M,S,_,_,_), time(H,M,S)).
 parse_time(+Text, -Stamp) is semidet
 parse_time(+Text, ?Format, -Stamp) is semidet
Stamp is a timestamp created from parsing Text using the representation Format. Currently supported formats are:
rfc_1123
Used for the HTTP protocol to represent time-stamps, e.g.
Fri, 08 Dec 2006 15:29:44 GMT
iso_8601
Commonly used in XML documents. Actually the XML RFC3339 is a profile of ISO8601. For example
2006-12-08T15:29:44Z
See also
- xsd_time_string/3 from library(sgml) implements RFC3339 strictly.
   94parse_time(Text, Stamp) :-
   95    parse_time(Text, _Format, Stamp).
   96
   97parse_time(Text, Format, Stamp) :-
   98    atom_codes(Text, Codes),
   99    phrase(date(Format, Y,Mon,D,H,Min,S,UTCOffset), Codes),
  100    !,
  101    date_time_stamp(date(Y,Mon,D,H,Min,S,UTCOffset,-,-), Stamp).
  102
  103date(iso_8601, Yr, Mon, D, H, Min, S, 0) --> % BC
  104    "-", date(iso_8601, Y, Mon, D, H, Min, S, 0),
  105    { Yr is -1 * Y }.
  106date(iso_8601, Y, Mon, D, H, Min, S, 0) -->
  107    year(Y),
  108    iso_8601_rest(Y, Mon, D, H, Min, S).
  109date(rfc_1123, Y, Mon, D, Hr, Min, Sec, 0) --> % RFC 1123: "Fri, 08 Dec 2006 15:29:44 GMT"
  110    day_name(_), ", ", ws,
  111    day_of_the_month(D), ws,
  112    month_name(Mon), ws,
  113    year(Y), ws,
  114    hour(H), ":", minute(M), ":", second(S), ws,
  115    timezone(DH, DM, DS),
  116    { Hr is H + DH, Min is M + DM, Sec is S + DS }.
 iso_8601_rest(+Year:int, -Mon, -Day, -H, -M, -S)
Process ISO 8601 time-values after parsing the 4-digit year.
  123iso_8601_rest(_, Mon, D, H, Min, S) -->
  124    "-", month(Mon), "-", day(D),
  125    opt_time(H, Min, S).
  126iso_8601_rest(_, Mon, 0, 0, 0, 0) -->
  127    "-", month(Mon).
  128iso_8601_rest(_, Mon, D, H, Min, S) -->
  129    month(Mon), day(D),
  130    opt_time(H, Min, S).
  131iso_8601_rest(_, 1, D, H, Min, S) -->
  132    "-", ordinal(D),
  133    opt_time(H, Min, S).
  134iso_8601_rest(Yr, 1, D, H, Min, S) -->
  135    "-W", week(W), "-", day_of_the_week(DW),
  136    opt_time(H, Min, S),
  137    { week_ordinal(Yr, W, DW, D) }.
  138iso_8601_rest(Yr, 1, D, H, Min, S) -->
  139    "W", week(W), day_of_the_week(DW),
  140    opt_time(H, Min, S),
  141    { week_ordinal(Yr, W, DW, D) }.
  142iso_8601_rest(Yr, 1, D, 0, 0, 0) -->
  143    "W", week(W),
  144    { week_ordinal(Yr, W, 1, D) }.
  145
  146opt_time(Hr, Min, Sec) -->
  147    ("T";" "), !, iso_time(Hr, Min, Sec).
  148opt_time(0, 0, 0) --> "".
  149
  150
  151% TIMEX2 ISO: "2006-12-08T15:29:44 UTC" or "20061208T"
  152iso_time(Hr, Min, Sec) -->
  153    hour(H), ":", minute(M), ":", second(S),
  154    timezone(DH, DM, DS),
  155    { Hr is H + DH, Min is M + DM, Sec is S + DS }.
  156iso_time(Hr, Min, Sec) -->
  157    hour(H), ":", minute(M),
  158    timezone(DH, DM, DS),
  159    { Hr is H + DH, Min is M + DM, Sec is DS }.
  160iso_time(Hr, Min, Sec) -->
  161    hour(H), minute(M), second(S),
  162    timezone(DH, DM, DS),
  163    { Hr is H + DH, Min is M + DM, Sec is S + DS }.
  164iso_time(Hr, Min, Sec) -->
  165    hour(H), minute(M),
  166    timezone(DH, DM, DS),
  167    { Hr is H + DH, Min is M + DM, Sec is DS }.
  168iso_time(Hr, Min, Sec) -->
  169    hour(H),
  170    timezone(DH, DM, DS),
  171    { Hr is H + DH, Min is DM, Sec is DS }.
  172
  173% FIXME: deal with leap seconds
  174timezone(Hr, Min, 0) -->
  175    "+", hour(H), ":", minute(M), { Hr is -1 * H, Min is -1 * M }.
  176timezone(Hr, Min, 0) -->
  177    "+", hour(H), minute(M), { Hr is -1 * H, Min is -1 * M }.
  178timezone(Hr, 0, 0) -->
  179    "+", hour(H), { Hr is -1 * H }.
  180timezone(Hr, Min, 0) -->
  181    "-", hour(H), ":", minute(M), { Hr is H, Min is M }.
  182timezone(Hr, Min, 0) -->
  183    "-", hour(H), minute(M), { Hr is H, Min is M }.
  184timezone(Hr, 0, 0) -->
  185    "-", hour(H), { Hr is H }.
  186timezone(0, 0, 0) -->
  187    "Z".
  188timezone(0, 0, 0) -->
  189    ws, "UTC".
  190timezone(0, 0, 0) -->
  191    ws, "GMT". % remove this?
  192timezone(0, 0, 0) -->
  193    [].
  194
  195day_name(0) --> "Sun".
  196day_name(1) --> "Mon".
  197day_name(2) --> "Tue".
  198day_name(3) --> "Wed".
  199day_name(4) --> "Thu".
  200day_name(5) --> "Fri".
  201day_name(6) --> "Sat".
  202day_name(7) --> "Sun".
  203
  204month_name(1) --> "Jan".
  205month_name(2) --> "Feb".
  206month_name(3) --> "Mar".
  207month_name(4) --> "Apr".
  208month_name(5) --> "May".
  209month_name(6) --> "Jun".
  210month_name(7) --> "Jul".
  211month_name(8) --> "Aug".
  212month_name(9) --> "Sep".
  213month_name(10) --> "Oct".
  214month_name(11) --> "Nov".
  215month_name(12) --> "Dec".
  216
  217day_of_the_month(N) --> int2digit(N), { between(1, 31, N) }.
  218day_of_the_week(N)  --> digit(N),     { between(1,  7, N) }.
  219month(M)            --> int2digit(M), { between(1, 12, M) }.
  220week(W)             --> int2digit(W), { between(1, 53, W) }.
  221day(D)              --> int2digit(D), { between(1, 31, D) }.
  222hour(N)             --> int2digit(N), { between(0, 23, N) }.
  223minute(N)           --> int2digit(N), { between(0, 59, N) }.
  224second(S)           --> int2digit(N), { between(0, 60, N) }, % leap second
  225    opt_fraction(N, S).
  226
  227opt_fraction(I, F) -->
  228    ( "." ; "," ),
  229    !,
  230    digits(D),
  231    { length(D, N),
  232      N > 0,
  233      number_codes(FP, D),
  234      F is I + FP/(10^N)
  235    }.
  236opt_fraction(I, I) -->
  237    [].
  238
  239int2digit(N) -->
  240    digit(D0),
  241    digit(D1),
  242    { N is D0*10+D1 }.
  243
  244year(Y) -->
  245    digit(D0),
  246    digit(D1),
  247    digit(D2),
  248    digit(D3),
  249    { Y is D0*1000+D1*100+D2*10+D3 }.
  250
  251ordinal(N) --> % Nth day of the year, jan 1 = 1, dec 31 = 365 or 366
  252    digit(D0),
  253    digit(D1),
  254    digit(D2),
  255    { N is D0*100+D1*10+D2, between(1, 366, N) }.
  256
  257digit(D) -->
  258    [C],
  259    { code_type(C, digit(D)) }.
  260
  261digits([C|T]) -->
  262    [C],
  263    { code_type(C, digit) },
  264    !,
  265    digits(T).
  266digits([]) --> [].
  267
  268ws -->
  269    " ",
  270    !,
  271    ws.
  272ws -->
  273    [].
 day_of_the_week(+Date, -DayOfTheWeek) is det
Computes the day of the week for a given date. Days of the week are numbered from one to seven: monday = 1, tuesday = 2, ..., sunday = 7.
Arguments:
Date- is a term of the form date(+Year, +Month, +Day)
  283day_of_the_week(date(Year, Mon, Day), DotW) :-
  284    format_time(atom(A), '%u', date(Year, Mon, Day, 0, 0, 0, 0, -, -)),
  285    atom_number(A, DotW).
  286
  287week_ordinal(Year, Week, Day, Ordinal) :-
  288    format_time(atom(A), '%w', date(Year, 1, 1, 0, 0, 0, 0, -, -)),
  289    atom_number(A, DotW0),
  290    Ordinal is ((Week-1) * 7) - DotW0 + Day + 1.
 day_of_the_year(+Date, -DayOfTheYear) is det
Computes the day of the year for a given date. Days of the year are numbered from 1 to 365 (366 for a leap year).
Arguments:
Date- is a term of the form date(+Year, +Month, +Day)
  299day_of_the_year(date(Year, Mon, Day), DotY) :-
  300    format_time(atom(A), '%j', date(Year, Mon, Day, 0, 0, 0, 0, -, -)),
  301    atom_number(A, DotY)