• Windows file timestamp converted to local time

    From Matt Borchers@21:1/5 to All on Mon Oct 16 09:29:37 2023
    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Matt Borchers@21:1/5 to All on Mon Oct 16 11:35:27 2023
    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;

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Niklas Holsti@21:1/5 to Matt Borchers on Mon Oct 16 21:49:48 2023
    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?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Simon Wright@21:1/5 to Matt Borchers on Mon Oct 16 20:14:36 2023
    Matt Borchers <mattborchers@gmail.com> writes:

    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;

    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Matt Borchers@21:1/5 to Niklas Holsti on Mon Oct 16 12:26:25 2023
    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?

    HERE IS MY ORIGINAL POST IF IT DIDN'T MAKE IT...

    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Randy Brukardt@21:1/5 to Niklas Holsti on Mon Oct 16 21:39:09 2023
    "Niklas Holsti" <niklas.holsti@tidorum.invalid> wrote in message news:kp5eucFogqpU1@mid.individual.net...
    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?

    ...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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Dmitry A. Kazakov@21:1/5 to Matt Borchers on Tue Oct 17 09:25:03 2023
    On 2023-10-16 20: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;

    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Matt Borchers@21:1/5 to Niklas Holsti on Tue Oct 17 07:13:13 2023
    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". 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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Simon Wright@21:1/5 to Niklas Holsti on Tue Oct 17 17:35:45 2023
    Niklas Holsti <niklas.holsti@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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Niklas Holsti@21:1/5 to Matt Borchers on Tue Oct 17 19:28:45 2023
    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?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)