Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Windows file timestamp converted to local time

69 views
Skip to first unread message

Matt Borchers

unread,
Oct 16, 2023, 12:29:39 PM10/16/23
to
My need is to get the timestamp of a file corrected for local time. I am on Windows and the time should match the time that is reported on the Windows File Explorer which is is corrected for timezone and daylight savings time.

My program is a Win32 based program and the imported "localtime" C function does what is needed. However, sometimes the C function hangs after zero or more successful calls. I came to realize that this function is not thread-safe and so I wrote a wrapper function inside a protected object. This didn't help and I continued to add complexity to the protected code block but nothing seems to help. This is my current code:

type TM_STRUCT is record
tm_sec : INTEGER; --seconds after the minute - [0, 61]
tm_min : INTEGER; --minutes after the hour - [0, 59]
tm_hour : INTEGER; --hour since midnight - [0, 23]
tm_mday : INTEGER; --day of the month - [1, 31]
tm_mon : INTEGER; --months since January - [0, 11]
tm_year : INTEGER; --years since 1900
tm_wday : INTEGER; --days since Sunday - [0, 6]
tm_yday : INTEGER; --days since January 1 - [0, 365]
tm_isdst : INTEGER; --flag for alternate daylight savings time
end record;
pragma Convention( C, TM_STRUCT );

type A_TM_STRUCT is access all TM_STRUCT;

function LOCALTIME( timer : access OS_TIME ) return A_TM_STRUCT;
pragma Import( C, localtime, "localtime" );

protected type PROT_TIME is
entry LOCAL_TIME( ostime : GNAT.OS_Lib.OS_TIME; result : out TM_STRUCT );
private
busy : BOOLEAN := FALSE;
end PROT_TIME;

protected body PROT_TIME is

entry LOCAL_TIME( ostime : GNAT.OS_Lib.OS_TIME; result : out TM_STRUCT ) when not busy is
t : aliased GNAT.OS_Lib.OS_TIME := ostime;
begin
busy := TRUE;
result := localtime( t'Access ).all;
busy := FALSE;
end LOCAL_TIME;

end PROT_TIME;

pt : PROT_TIME;

function GET_LOCAL_TIME( ostime : GNAT.OS_Lib.OS_TIME ) return Ada.CALENDAR.TIME is
r : TM_STRUCT;
begin
pt.local_time( ostime, r );
return Ada.Calendar.time_of( ... );
end GET_LOCAL_TIME;

function GET_LAST_MODIFIED( path : STRING ) return Ada.CALENDAR.TIME is
(get_local_time( GNAT.OS_Lib.File_Time_Stamp( path ) ) );

My program calls "get_last_modified" with the file path.
The truth is that the behavior is the same without the guard condition. And the behavior is the same when written as a simple protected object, like:


protected PROT_TIME is
function LOCAL_TIME( ostime : GNAT.OS_Lib.OS_TIME ) return TM_STRUCT;
end PROT_TIME;

protected body PROT_TIME is

function LOCAL_TIME( ostime : GNAT.OS_Lib.OS_TIME ) return TM_STRUCT is
t : aliased GNAT.OS_Lib.OS_TIME := ostime;
begin
return localtime( t'Access ).all;
end LOCAL_TIME;

end PROT_TIME;

function GET_LOCAL_TIME( ostime : GNAT.OS_Lib.OS_TIME ) return Ada.CALENDAR.TIME is
r : TM_STRUCT;
begin
r := prot_time.local_time( ostime );
return Ada.Calendar.time_of( ... );
end GET_LOCAL_TIME;

The program seems to hang in the call to the "localtime" C function. A put_line immediately before the call to localtime will print.

Using the result in GNAT.OS_Lib.OS_TIME is correct and I could correct for the time zone myself, except for the fact that OS_TIME does not provide information about daylight savings time. Does anybody have any experience with dealing with file timestamps and converting them to the local time?

I hope I was both brief yet clear. Thank you.

Matt Borchers

unread,
Oct 16, 2023, 2:35:29 PM10/16/23
to
Below is the function from System.OS_Lib.
Does anybody know where the C implementation can be found?
Does anybody know where the C implementation of "localtime" is found?

function File_Time_Stamp (Name : C_File_Name) return OS_Time is
function File_Time (Name : Address) return OS_Time;
pragma Import (C, File_Time, "__gnat_file_time_name");
begin
return File_Time (Name);
end File_Time_Stamp;

Niklas Holsti

unread,
Oct 16, 2023, 2:49:52 PM10/16/23
to
(This question seems to be a follow-up ("Re:") to some earlier post, but
my newsreader does not seem to find or show that earlier post.)

What is the problem?

Have you tried using the standard Ada services:
Ada.Directories.Modification_Time and
Ada.Calendar.Time_Zones.Local_Time_Offset?

Simon Wright

unread,
Oct 16, 2023, 3:14:39 PM10/16/23
to
For the first question, very likely to be in gcc/ada/adaint.c in the GCC
sources (https://github.com/gcc-mirror/gcc)

localtime() is in libc; depends on your OS.

Matt Borchers

unread,
Oct 16, 2023, 3:26:27 PM10/16/23
to
HERE IS MY ORIGINAL POST IF IT DIDN'T MAKE IT...

Randy Brukardt

unread,
Oct 16, 2023, 10:38:45 PM10/16/23
to
"Niklas Holsti" <niklas...@tidorum.invalid> wrote in message
news:kp5euc...@mid.individual.net...
...as those will work on (almost) any target system, while the actual
implementation is going to be rather OS-dependent. And there never is a good
reason to use a GNAT-only (or any compiler-specific, for any compiler)
facility when there is an equivalent standard facility. Most of those
facilities pre-date the Ada ones.

Randy.


Dmitry A. Kazakov

unread,
Oct 17, 2023, 3:25:07 AM10/17/23
to
If I correctly interpret the description, OS_Time is FILETIME under
Windows, i.e. 64-bit value.

https://learn.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime

As for implementation it likely calls to GetFileTime after obtaining a
handle to the file.

https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfiletime

--
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

Matt Borchers

unread,
Oct 17, 2023, 10:13:15 AM10/17/23
to
On Monday, October 16, 2023 at 2:49:52 PM UTC-4, Niklas Holsti wrote:
Thank you for the suggestion of using "Ada.Directories.Modification_Time". I didn't think to look in that package. This function adjusts for daylight savings time and returns the time as displayed in Windows Explorer.

There needs to be better comments (and documentation) for these time related functions. It is often not clear what time is returned. It is safe to assume UTC or local time, but the daylight savings issue caused confusion.

Niklas Holsti

unread,
Oct 17, 2023, 12:28:49 PM10/17/23
to
On 2023-10-17 17:13, Matt Borchers wrote:
> On Monday, October 16, 2023 at 2:49:52 PM UTC-4, Niklas Holsti wrote:
>> On 2023-10-16 21:35, Matt Borchers wrote:
>>> Below is the function from System.OS_Lib.
>>> Does anybody know where the C implementation can be found?
>>> Does anybody know where the C implementation of "localtime" is found?
>>>
>>> function File_Time_Stamp (Name : C_File_Name) return OS_Time is
>>> function File_Time (Name : Address) return OS_Time;
>>> pragma Import (C, File_Time, "__gnat_file_time_name");
>>> begin
>>> return File_Time (Name);
>>> end File_Time_Stamp;
>> (This question seems to be a follow-up ("Re:") to some earlier post, but
>> my newsreader does not seem to find or show that earlier post.)
>>
>> What is the problem?
>>
>> Have you tried using the standard Ada services:
>> Ada.Directories.Modification_Time and
>> Ada.Calendar.Time_Zones.Local_Time_Offset?
>
> Thank you for the suggestion of using "Ada.Directories.Modification_Time".


Happy to help!


> I didn't think to look in that package.


Ada.Directories does, IMO, seem the best place for it, since it should
not depend on the type of the file -- text, sequential, etc.


> This function adjusts for daylight savings time and returns the time
> as displayed in Windows Explorer.
>
> There needs to be better comments (and documentation) for these time
> related functions. It is often not clear what time is returned.


Yes, but some of that documentation should not be in the Ada standard,
but in the compiler's documentation.

Ada.Directories.Modification_Time returns a value of type
Ada.Calendar.Time. However, "the time base associated with the type Time
of package Calendar is implementation defined" (RM 9.6(23)) so it should
be documented in the implementation documents, that is in the GNAT
documentation. Have you looked there?

Simon Wright

unread,
Oct 17, 2023, 12:35:50 PM10/17/23
to
Niklas Holsti <niklas...@tidorum.invalid> writes:

> Ada.Directories.Modification_Time returns a value of type
> Ada.Calendar.Time. However, "the time base associated with the type
> Time of package Calendar is implementation defined" (RM 9.6(23)) so it
> should be documented in the implementation documents, that is in the
> GNAT documentation. Have you looked there?

The GNAT RM says in Implementation Defined Characteristics[1]

"The time base used is that provided by the C library function gettimeofday."

[1] https://docs.adacore.com/live/wave/gnat_rm/html/gnat_rm/gnat_rm/implementation_defined_characteristics.html
0 new messages