[m-rev.] for review: implement io__file_modification_time_2 in C#
Fergus Henderson
fjh at cs.mu.OZ.AU
Wed Oct 29 12:03:58 AEDT 2003
On 27-Oct-2003, Peter Ross <pro at missioncriticalit.com> wrote:
> library/io.m:
> Implement io__file_modification_time_2 in C#.
>
> library/time.m:
> Implement most of this module in C#.
> Add construct_time_t to the interface for use by
> io__file_modification_time_2.
> Index: library/time.m
...
> +:- pragma foreign_type(il, time_t_rep, "valuetype [mscorlib]System.DateTime")
> + where comparison is compare_time_t_reps.
You should document that this is represented in UTC.
(Or alternatively, document that it is represented in local time... no,
that won't work. Representing time_t in local time would cause problems
because times such as 2:30am on the day of the switch over from daylight
savings time back to standard time are ambiguous.)
> +:- pragma foreign_proc("C#", time__c_clock(Ret::out, _IO0::di, _IO::uo),
> + [will_not_call_mercury, promise_pure, tabled_for_io],
> +"{
> + // XXX Ticks is long in .NET!
> + Ret = (int) System.DateTime.Now.Ticks;
> +}").
That's wrong. time__c_clock should return "processor time", i.e. CPU usage,
but System.DateTime.Now returns wall clock time.
You should use System.Process.GetCurrentProcess.UserProcessorTime.Ticks
or something like that.
> @@ -373,6 +399,14 @@
> "{
> Diff = (MR_Float) difftime(T1, T0);
> }").
> +:- pragma foreign_proc("C#",
> + time__c_difftime(T1::in, T0::in, Diff::out),
> + [will_not_call_mercury, promise_pure],
> +"{
> + System.TimeSpan span;
> + span = T1 - T0;
> + Diff = span.Ticks / System.TimeSpan.TicksPerSecond;
> +}").
Here span.Ticks and System.TimeSpan.TicksPerSecond both have integral
types, so this will do integer division, discarding any fractional part,
and then convert the result to a double.
You should instead use "Diff = span.TotalSeconds;".
That will return a value that includes the appropriate fraction of a second
in cases where the difference is not an integral number of seconds.
(Also, it's simpler!)
> +:- pragma foreign_proc("C#",
> + time__c_time(Ret::out, _IO0::di, _IO::uo),
> + [will_not_call_mercury, promise_pure, tabled_for_io],
> +"{
> + Ret = System.DateTime.Now;
> +}").
That should be "Ret = System.DateTime.UtcNow;".
^^^
(Unless time_t_rep stores local time.)
> %-----------------------------------------------------------------------------%
>
> @@ -411,6 +445,25 @@
> YD = (MR_Integer) p->tm_yday;
> N = (MR_Integer) p->tm_isdst;
> }").
> +:- pragma foreign_proc("C#",
> + time__c_localtime(Time::in, Yr::out, Mnt::out, MD::out, Hrs::out,
> + Min::out, Sec::out, YD::out, WD::out, N::out),
> + [will_not_call_mercury, promise_pure],
> +"{
> + System.DateTime t = Time.ToLocalTime();
That's OK, if time_t_rep stores UTC.
(If time_t_rep stored local time, that would need to be just "t = Time;".)
> + // we don't handle leap seconds
> + Sec = t.Second;
> + Min = t.Minute;
> + Hrs = t.Hour;
> + Mnt = t.Month - 1;
> + Yr = t.Year - 1900;
> + WD = (int) t.DayOfWeek;
> + MD = t.Day;
> + YD = t.DayOfYear - 1;
> + // XXX Don't know how to determine if in DST.
> + N = -1;
> +}").
I think "N = (int) System.TimeZone.CurrentTimeZone.IsDayLightSavingTime(t);"
should do the trick.
> %:- func time__gmtime(time_t) = tm.
> @@ -448,6 +501,25 @@
> YD = (MR_Integer) p->tm_yday;
> N = (MR_Integer) p->tm_isdst;
> }").
> +:- pragma foreign_proc("C#",
> + time__c_gmtime(Time::in, Yr::out, Mnt::out, MD::out, Hrs::out,
> + Min::out, Sec::out, YD::out, WD::out, N::out),
> + [will_not_call_mercury, promise_pure],
> +"{
> + System.DateTime t = Time.ToUniversalTime();
That should be just "System.Datetime t = Time;", since Time should
already be in UTC.
(Unless time_t_rep stores local time.)
> + // we don't handle leap seconds
> + Sec = t.Second;
> + Min = t.Minute;
> + Hrs = t.Hour;
> + Mnt = t.Month - 1;
> + Yr = t.Year - 1900;
> + WD = (int) t.DayOfWeek;
> + MD = t.Day;
> + YD = t.DayOfYear - 1;
> + // XXX Don't know how to determine if in DST.
> + N = -1;
That should be "N = 0;", since time__c_gmtime returns a time in UTC,
and UTC times are never daylight savings times.
> +}").
>
> :- func int_to_maybe_dst(int) = maybe(dst).
>
> @@ -491,6 +563,14 @@
>
> Time = mktime(&t);
> }").
> +:- pragma foreign_proc("C#",
> + time__c_mktime(Yr::in, Mnt::in, MD::in, Hrs::in, Min::in, Sec::in,
> + _YD::in, _WD::in, _N::in, Time::out),
> + [will_not_call_mercury, promise_pure],
> + "{
> + // We don't use YD, WD and N.
> + Time = new System.DateTime(Yr + 1900, Mnt + 1, MD, Hrs, Min, Sec);
> +}").
Ignoring YD and WD is fine; mktime is supposed to do that.
But ignoring N (the daylight savings time indicator) is not.
On the day when you switch back to standard time from daylight savings time,
the time "2:30am" occurs twice, once during daylight savings time (N = 1),
and then again an hour later, during standard time (N = 0).
Not sure what to do about this right now, but at very least it warrants an XXX.
Also, if time_t_rep stores UTC, you need to convert from local time to UTC.
> :- func maybe_dst_to_int(maybe(dst)) = int.
>
> @@ -537,6 +617,18 @@
>
> MR_make_aligned_string_copy(Str, s);
> }").
> +:- pragma foreign_proc("C#",
> + time__c_asctime(Yr::in, Mnt::in, MD::in, Hrs::in, Min::in, Sec::in,
> + _YD::in, _WD::in, _N::in, Str::out),
> + [will_not_call_mercury, promise_pure],
> +"{
> + // We don't use YD, WD and N.
> + System.DateTime Time = new System.DateTime(Yr + 1900, Mnt + 1, MD,
> + Hrs, Min, Sec);
> +
> + // XXX this may need to be formatted differently.
> + Str = Time.ToString();
> +}").
This shouldn't ignore N either.
Also the XXX comment is correct, it should be formatted differently.
The C standard defines asctime() to be exactly equivalent to the following:
char *asctime(const struct tm *timeptr)
{
static const char wday_name[7][3] = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};
static const char mon_name[12][3] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
static char result[26];
sprintf(result, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
wday_name[timeptr->tm_wday],
mon_name[timeptr->tm_mon],
timeptr->tm_mday, timeptr->tm_hour,
timeptr->tm_min, timeptr->tm_sec,
1900 + timeptr->tm_year);
return result;
}
The simplest way to implement it would be to just convert this C code
to Mercury code.
Then ctime(T) can be implemented using asctime(localtime(T)).
--
Fergus Henderson <fjh at cs.mu.oz.au> | "I have always known that the pursuit
The University of Melbourne | of excellence is a lethal habit"
WWW: <http://www.cs.mu.oz.au/~fjh> | -- the last words of T. S. Garp.
--------------------------------------------------------------------------
mercury-reviews mailing list
post: mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------
More information about the reviews
mailing list