mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-17 23:05:21 +00:00
Estimated hours taken: 0.25 Branches: main, release compiler/timestamp.m: Fix a bug where we were implicitly relying on order-of-evaluation: use an if-then-else, which the language reference manual says will guarantee sequential evaluation. (No regression test since this bug is not actually triggered by the current compiler.)
172 lines
5.0 KiB
Mathematica
172 lines
5.0 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 2001-2002 The University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%-----------------------------------------------------------------------------%
|
|
% File: timestamp.m
|
|
% Main author: stayl
|
|
%
|
|
% Timestamp representation for smart recompilation.
|
|
%-----------------------------------------------------------------------------%
|
|
:- module libs__timestamp.
|
|
|
|
:- interface.
|
|
|
|
:- import_module time.
|
|
|
|
% A `timestamp' is similar to a `time_t' except that
|
|
% timestamps are system independent. A timestamp string
|
|
% (obtained using time__timestamp_to_string) written on
|
|
% one system can be read on any other system.
|
|
% Comparison of values of type `timestamp' (via compare/3)
|
|
% is equivalent to comparison of the times represented.
|
|
:- type timestamp.
|
|
|
|
% time_t_to_timestamp(Time) = Timestamp:
|
|
% Converts the calendar time value `Time' into a timestamp.
|
|
% Equivalent to `gm_time_to_timestamp(gmtime(Time))'.
|
|
:-func time_t_to_timestamp(time_t) = timestamp.
|
|
|
|
% timestamp_to_string(Timestamp) = String:
|
|
% Converts `Timestamp' into a string with format
|
|
% "yyyy-mm-dd hh:mm:ss", expressed as UTC.
|
|
:- func timestamp_to_string(timestamp) = string.
|
|
|
|
% string_to_timestamp(String) = Timestamp:
|
|
% Converts a string formatted as "yyyy-mm-dd hh:mm:ss",
|
|
% into a timestamp. Fails if the string does not have the
|
|
% correct format.
|
|
:- func string_to_timestamp(string) = timestamp is semidet.
|
|
|
|
% oldest_timestamp = Timestamp:
|
|
% Return a timestamp which is older than any other timestamp.
|
|
:- func oldest_timestamp = timestamp.
|
|
|
|
% newest_timestamp = Timestamp:
|
|
% Return a timestamp which is newer than any other timestamp.
|
|
:- func newest_timestamp = timestamp.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module int, std_util, string.
|
|
|
|
% A timestamp is a string formatted as "yyyy-mm-dd hh:mm:ss"
|
|
% representing a time expressed as UTC (Universal Coordinated Time).
|
|
%
|
|
% We use a no-tag type rather than an abstract equivalence type
|
|
% to avoid type errors with abstract equivalence types in the hlc
|
|
% back-end.
|
|
:- type timestamp ---> timestamp(string).
|
|
|
|
oldest_timestamp = timestamp("0000-00-00 00:00:00").
|
|
newest_timestamp = timestamp("9999-99-99 99:99:99").
|
|
|
|
time_t_to_timestamp(Time) = gmtime_to_timestamp(time__gmtime(Time)).
|
|
|
|
:- func gmtime_to_timestamp(tm) = timestamp.
|
|
|
|
gmtime_to_timestamp(tm(Year, Month, MD, Hrs, Min, Sec, YD, WD, DST)) =
|
|
timestamp(gmtime_to_timestamp_2(Year, Month, MD, Hrs, Min, Sec,
|
|
YD, WD, maybe_dst_to_int(DST))).
|
|
|
|
:- func gmtime_to_timestamp_2(int, int, int, int,
|
|
int, int, int, int, int) = string.
|
|
|
|
:- pragma foreign_decl("C", "
|
|
#include ""mercury_string.h""
|
|
#include <time.h>
|
|
").
|
|
:- pragma foreign_proc("C",
|
|
gmtime_to_timestamp_2(Yr::in, Mnt::in, MD::in, Hrs::in, Min::in,
|
|
Sec::in, YD::in, WD::in, N::in) = (Result::out),
|
|
[will_not_call_mercury, promise_pure],
|
|
"{
|
|
int size;
|
|
struct tm t;
|
|
|
|
t.tm_sec = Sec;
|
|
t.tm_min = Min;
|
|
t.tm_hour = Hrs;
|
|
t.tm_mon = Mnt;
|
|
t.tm_year = Yr;
|
|
t.tm_wday = WD;
|
|
t.tm_mday = MD;
|
|
t.tm_yday = YD;
|
|
t.tm_isdst = N;
|
|
|
|
size = sizeof ""yyyy-mm-dd hh:mm:ss"";
|
|
MR_allocate_aligned_string_msg(Result, size - 1, MR_PROC_LABEL);
|
|
|
|
strftime(Result, size, ""%Y-%m-%d %H:%M:%S"", &t);
|
|
}").
|
|
|
|
:- pragma foreign_proc("MC++",
|
|
gmtime_to_timestamp_2(_Yr::in, _Mnt::in, _MD::in, _Hrs::in, _Min::in,
|
|
_Sec::in, _YD::in, _WD::in, _N::in) = (_Result::out),
|
|
[will_not_call_mercury, promise_pure],
|
|
"{
|
|
mercury::runtime::Errors::SORRY(""foreign code for this function"");
|
|
}").
|
|
|
|
:- func maybe_dst_to_int(maybe(dst)) = int.
|
|
|
|
maybe_dst_to_int(M) = N :-
|
|
( M = yes(DST), DST = daylight_time,
|
|
N = 1
|
|
; M = yes(DST), DST = standard_time,
|
|
N = 0
|
|
; M = no,
|
|
N = -1
|
|
).
|
|
|
|
timestamp_to_string(timestamp(Timestamp)) = Timestamp.
|
|
|
|
string_to_timestamp(Timestamp) = timestamp(Timestamp) :-
|
|
% The if-then-else here is to force order of evaluation --
|
|
% we need to ensure that the length check occurs before the
|
|
% calls to unsafe_undex to avoid dereferencing invalid pointers.
|
|
(
|
|
string__length(Timestamp) `with_type` int =
|
|
string__length("yyyy-mm-dd hh:mm:ss")
|
|
->
|
|
string__to_int(string__unsafe_substring(Timestamp, 0, 4), _),
|
|
|
|
string__unsafe_index(Timestamp, 4, '-'),
|
|
|
|
string__to_int(string__unsafe_substring(Timestamp, 5, 2),
|
|
Month),
|
|
Month >= 1,
|
|
Month =< 12,
|
|
|
|
string__unsafe_index(Timestamp, 7, '-'),
|
|
|
|
string__to_int(string__unsafe_substring(Timestamp, 8, 2), Day),
|
|
Day >= 1,
|
|
Day =< 31,
|
|
|
|
string__unsafe_index(Timestamp, 10, ' '),
|
|
|
|
string__to_int(string__unsafe_substring(Timestamp, 11, 2),
|
|
Hour),
|
|
Hour >= 0,
|
|
Hour =< 23,
|
|
|
|
string__unsafe_index(Timestamp, 13, ':'),
|
|
|
|
string__to_int(string__unsafe_substring(Timestamp, 14, 2),
|
|
Minute),
|
|
Minute >= 0,
|
|
Minute =< 59,
|
|
|
|
string__unsafe_index(Timestamp, 16, ':'),
|
|
|
|
string__to_int(string__unsafe_substring(Timestamp, 17, 2),
|
|
Second),
|
|
Second >= 0,
|
|
Second =< 61 % Seconds 60 and 61 are for leap seconds.
|
|
;
|
|
fail
|
|
).
|