* Dates and Times in GNAT on Linux
@ 2009-09-13 15:36 Marc A. Criley
2009-09-13 16:17 ` Dmitry A. Kazakov
2009-09-13 19:35 ` Jeffrey R. Carter
0 siblings, 2 replies; 4+ messages in thread
From: Marc A. Criley @ 2009-09-13 15:36 UTC (permalink / raw)
I'm confused about GNAT's implementation of some aspects of date/time
processing on Linux. I'm running GNAT GPL 2009 on Ubuntu Linux; I also
live in the US Central Time Zone and Daylight Savings Time is in effect
as I write this.
This is probably a stupid misunderstanding or mistaken expectations or
feature misuse on my part, but I would really like to know what's going on.
Basically what I'm trying to do is take the time I got from from
Ada.Real.Clock and convert it to a date/time rep. The result I'm coming
up with is always an hour off. (DST effect? Read on...) Code will follow
in a bit.
I discovered that GNAT's implementation of Ada.Real_Time.Clock returns
the number of seconds since the UTC epoch start, which is very nice and
very handy. Using Real_Time.Split I can get that number of seconds into
a visible type, Seconds_Count.
I can then get the start of the Unix/UTC epoch via:
UTC_Epoch_Start := Calendar.Time_Of(1970, 1, 1)
+ Duration(Calendar.Time_Zones.UTC_Offset * 60);
-- For where I live, right now the UTC_Offset is -300 minutes,
-- i.e. -5 hours.
Adding the Real_Time seconds count (as a Duration) to UTC_Epoch_Start
gives a Calendar.Time value containing the current UTC time, from which
I can generate an image...which is an hour off from the correct value.
So I'm thinking it might be a DST problem, but shouldn't the affected
Calendar procedures be taking that into account?
I saw that the Ada.Calendar package body uses a C function,
__gnat_localtime_tzoff(), which has "Parameter 'off' captur[ing] the UTC
offset which is either retrieved from the tm struct or calculated from
the 'timezone' extern and the tm_isdst flag in the tm struct." Looking
at the code for this function it appears that _for_Linux_ the
implementation ignores the "tm_isdst" value and just uses the
"tm_gmtoff" value, while for some other Unices it does look at tm_isdst.
I'd like to think there's a good reason for doing that--including me
being an idiot--but I don't see what's going on. And unfortunately I
don't yet have a support contract with AdaCore :-)
I hacked together some C and Ada examples to illustrate this:
tmt.c:
#include <time.h>
#include <stdio.h>
void tmt_c_time(time_t rt_secs)
{
struct tm *local;
time_t t;
t = time(NULL);
printf("secs %d\n", t);
local = localtime(&t);
printf("Local time and date: %s\n", asctime(local));
local = gmtime(&t);
printf("UTC time and date: %s\n", asctime(local));
t = rt_secs;
printf("rt secs %d (from Ada)\n", t);
local = localtime(&t);
printf("Local time and date: %s\n", asctime(local));
local = gmtime(&t);
printf("UTC time and date: %s\n", asctime(local));
}
$ gcc -c -g tmt.c
tmtada.adb:
with Text_IO; use Text_IO;
with Ada.Real_Time; use Ada.Real_Time;
with Ada.Calendar.Formatting; use Ada.Calendar.Formatting;
with Ada.Calendar.Time_Zones; use Ada.Calendar.Time_Zones;
procedure Tmtada is
T : Time := Clock;
Seconds : Seconds_Count;
Span : Time_Span;
Cal_Time : Ada.Calendar.Time;
UTC_Epoch : Ada.Calendar.Time;
procedure Tmt_C_Time(Rt_Secs : Seconds_Count);
pragma Import(C, Tmt_C_Time, "tmt_c_time");
use Ada.Calendar;
begin
Split(T, Seconds, Span);
Put_Line("Seconds since epoch:" & Seconds'Img);
UTC_Epoch := Ada.Calendar.Time_Of(1970, 1, 1) +
Duration(UTC_Time_Offset * 60);
Cal_Time := UTC_Epoch + Duration(Seconds);
Put_Line("Time Image " & Image(Cal_Time));
New_Line;
Put_Line("Via C...");
Tmt_C_Time(Seconds);
end Tmtada;
$ gnatmake -g tmtada -largs tmt.o
Here's what I get from a run:
[95] Marc say: ./tmtada
Seconds since epoch: 1252855814
Time Image 2009-09-13 16:30:14
Via C...
secs 1252855814
Local time and date: Sun Sep 13 10:30:14 2009
UTC time and date: Sun Sep 13 15:30:14 2009
rt secs 1252855814 (from Ada)
Local time and date: Sun Sep 13 10:30:14 2009
UTC time and date: Sun Sep 13 15:30:14 2009
Maybe my conversion from Real_Time.Time to Calendar.Time is flawed...I
don't know. Any explanation or clarifications would be much appreciated.
Marc A. Criley
Mckae Technologies
www.mckae.com
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: Dates and Times in GNAT on Linux
2009-09-13 15:36 Dates and Times in GNAT on Linux Marc A. Criley
@ 2009-09-13 16:17 ` Dmitry A. Kazakov
2009-09-13 19:35 ` Jeffrey R. Carter
1 sibling, 0 replies; 4+ messages in thread
From: Dmitry A. Kazakov @ 2009-09-13 16:17 UTC (permalink / raw)
On Sun, 13 Sep 2009 10:36:58 -0500, Marc A. Criley wrote:
> I'm confused about GNAT's implementation of some aspects of date/time
> processing on Linux. I'm running GNAT GPL 2009 on Ubuntu Linux; I also
> live in the US Central Time Zone and Daylight Savings Time is in effect
> as I write this.
>
> This is probably a stupid misunderstanding or mistaken expectations or
> feature misuse on my part, but I would really like to know what's going on.
>
> Basically what I'm trying to do is take the time I got from from
> Ada.Real.Clock and convert it to a date/time rep. The result I'm coming
> up with is always an hour off. (DST effect? Read on...) Code will follow
> in a bit.
>
> I discovered that GNAT's implementation of Ada.Real_Time.Clock returns
> the number of seconds since the UTC epoch start, which is very nice and
> very handy. Using Real_Time.Split I can get that number of seconds into
> a visible type, Seconds_Count.
>
> I can then get the start of the Unix/UTC epoch via:
> UTC_Epoch_Start := Calendar.Time_Of(1970, 1, 1)
> + Duration(Calendar.Time_Zones.UTC_Offset * 60);
> -- For where I live, right now the UTC_Offset is -300 minutes,
> -- i.e. -5 hours.
>
> Adding the Real_Time seconds count (as a Duration) to UTC_Epoch_Start
> gives a Calendar.Time value containing the current UTC time, from which
> I can generate an image...which is an hour off from the correct value.
>
> So I'm thinking it might be a DST problem, but shouldn't the affected
> Calendar procedures be taking that into account?
Hmm, it seems otherwise. It is DST now, and no DST for the time point you
calculated the epoch. So the epoch time is incoherent to the time now. Your
calculation presumes that (T + D1) + D2 = T + (D1 + D2) holds for any T, a
political time and any D1, D2, durations. That is wrong for political time.
(Ada.Calendar arithmetic is broken, when Ada.Calendar.Time is political
time) The problem is that UTC_Offset is not a constant, but itself is a
function of UTC time.
> Maybe my conversion from Real_Time.Time to Calendar.Time is flawed...I
> don't know. Any explanation or clarifications would be much appreciated.
You have to sum all clock skews (forth and back) within the interval
between the epoch and the time being converted. These skews will sum up to
either 0 or 1 hour, or maybe 1 hour + possibly n leap seconds. Not an easy
task.
P.S. I wished Ada.Calendar.Time_Zones weren't broken. This was discussed in
c.l.a. a couple of months ago.
--
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: Dates and Times in GNAT on Linux
2009-09-13 15:36 Dates and Times in GNAT on Linux Marc A. Criley
2009-09-13 16:17 ` Dmitry A. Kazakov
@ 2009-09-13 19:35 ` Jeffrey R. Carter
2009-09-13 20:41 ` Marc A. Criley
1 sibling, 1 reply; 4+ messages in thread
From: Jeffrey R. Carter @ 2009-09-13 19:35 UTC (permalink / raw)
Marc A. Criley wrote:
>
> I can then get the start of the Unix/UTC epoch via:
> UTC_Epoch_Start := Calendar.Time_Of(1970, 1, 1)
> + Duration(Calendar.Time_Zones.UTC_Offset * 60);
> -- For where I live, right now the UTC_Offset is -300 minutes,
> -- i.e. -5 hours.
This is your problem. The offset on 1970 Jan 01 00:00:00.00 was -6 hrs.
Of course, any attempt to relate an Ada.Real_Time.Time to an Ada.Calendar.Time
is completely compiler dependent, is unlikely to work with any other compiler,
and could stop working with a different version of the same compiler.
--
Jeff Carter
"C++: The power, elegance and simplicity of a hand grenade."
Ole-Hjalmar Kristensen
90
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: Dates and Times in GNAT on Linux
2009-09-13 19:35 ` Jeffrey R. Carter
@ 2009-09-13 20:41 ` Marc A. Criley
0 siblings, 0 replies; 4+ messages in thread
From: Marc A. Criley @ 2009-09-13 20:41 UTC (permalink / raw)
Jeffrey R. Carter wrote:
> Marc A. Criley wrote:
>>
>> I can then get the start of the Unix/UTC epoch via:
>> UTC_Epoch_Start := Calendar.Time_Of(1970, 1, 1)
>> + Duration(Calendar.Time_Zones.UTC_Offset * 60);
>> -- For where I live, right now the UTC_Offset is -300 minutes,
>> -- i.e. -5 hours.
>
> This is your problem. The offset on 1970 Jan 01 00:00:00.00 was -6 hrs.
Yep. I'm retrieving the UTC_Offset in effect today (which is the default
value of the UTC_Offset argument), not what it was at that date/time.
Thanks! I knew I was missing something basic here.
> Of course, any attempt to relate an Ada.Real_Time.Time to an
> Ada.Calendar.Time is completely compiler dependent, is unlikely to work
> with any other compiler, and could stop working with a different version
> of the same compiler.
Yep. But that's an issue I can deal with here.
Marc
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2009-09-13 20:41 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-09-13 15:36 Dates and Times in GNAT on Linux Marc A. Criley
2009-09-13 16:17 ` Dmitry A. Kazakov
2009-09-13 19:35 ` Jeffrey R. Carter
2009-09-13 20:41 ` Marc A. Criley
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox