* * * *
19 Visitatori, 0 Utenti

Autore Topic: [RISOLTO] Data ultima modifica di un file su rete Microsoft  (Letto 671 volte)

bonmario

  • Hero Member
  • *****
  • Post: 728
  • Karma: +1/-1
[RISOLTO] Data ultima modifica di un file su rete Microsoft
« il: Aprile 02, 2019, 08:15:09 am »
Ciao a tutti,
ieri mi sono imbattuto in un problema "strano". Non credo che sia a causa di Lazarus, perché lo steso programma su rete Novell non aveva questo problema. Purtroppo non conosco i dettagli delle 2 reti.
Provo a spiegarmi ...
Ho un programma che funziona da anni che, tra le altre cose, deve determinare la data/ora di creazione di parecchi files. Per ognuno, se la data/ora di creazione è maggiore di una certa data di riferimento, deve fare certe operazioni.

- Il 25 marzo, alle 12.00, ho creato un file.
- Il mio programma, quando è girato il 26 marzo, vedeva che quel file era stato creato il 25/03/2019 alle 12.00
- nel weekend c'è stato il cambio dell'ora
- Il mio programma, quando è girato ieri, vedeva che quel file era stato creato il 25/03/2019 alle 13.00, quindi un'ora dopo rispetto a quella effettiva

Qualcuno di voi si è mai imbattuto in questa "anomalia"?

Grazie in anticipo, Mario

P.S. Il mio programma determina la data di creazione, usando "FileDateToDateTime(DirInfo.Time);"
Ho provato anche usando la procedura qui sotto, ma il risultato è il medesimo

Codice: [Seleziona]
  function  DataUltimaModifica(const NomeFile:String;TipoRitorno:TipoData):TDateTime;
  var hFile:Integer;
      ftModifica, ftCreazione, ftAccesso:TFileTime;
      sysDateTime:_SYSTEMTIME;
  begin
    Result:=DimFileNonTrov;

    hFile:=0;
    try
      hFile:=CreateFile(PChar(NomeFile),
                        GENERIC_READ ,
                        FILE_SHARE_READ or FILE_SHARE_WRITE, //Faccio in modo di poter reperire la data
                        nil,                                 //anche dai files vincolati
                        OPEN_EXISTING,
                        FILE_FLAG_BACKUP_SEMANTICS,
                        0);
      if (GetLastError = 0) then begin
        GetFileTime(hFile, @ftCreazione, @ftAccesso, @ftModifica);
        if (GetLastError = 0) then begin
          FileTimeToLocalFileTime(ftModifica, ftModifica);
          FileTimeToSystemTime(ftModifica, sysDateTime);
          Result:=SystemTimeToDateTime(sysDateTime);

          Result:=FormattaData(Result, TipoRitorno);
        end;
      end;
    finally
      if (hFile <> 0) then begin
        CloseHandle(hFile);
      end;
    end;
  end;

Grazie in anticipo, Mario
« Ultima modifica: Aprile 05, 2019, 02:27:30 pm da bonmario »

nomorelogic

  • Global Moderator
  • Hero Member
  • *****
  • Post: 2133
  • Karma: +8/-1
Re:Data ultima modifica di un file su rete Microsoft
« Risposta #1 il: Aprile 02, 2019, 08:53:36 am »
in NTFS le date sono memorizzate nel formato UTC che è un formato che non tiene conto dei fusi orari

se usi FileTimeToLocalFileTime o FileTimeToSystemTime questi orari ti verranno convertiti tenendo conto del fuso orario del paese dove ti trovi

non mi è mai capitato un problema del genere ma penso che dovresti utilizzare la funzione GetLocalTimeOffset che trovi in
https://www.freepascal.org/docs-html/rtl/sysutils/getlocaltimeoffset.html
in questo modo dovresti ottenere la data UTC con la quale fare i controlli che ti servono

Edit:
c'è anche questa unit che può essere utile
http://wiki.freepascal.org/PascalTZ
« Ultima modifica: Aprile 02, 2019, 08:58:53 am da nomorelogic »
Imagination is more important than knowledge (A.Einstein)

bonmario

  • Hero Member
  • *****
  • Post: 728
  • Karma: +1/-1
Re:Data ultima modifica di un file su rete Microsoft
« Risposta #2 il: Aprile 03, 2019, 08:08:44 am »
Ciao,
grazie per la risposta, ma credo che il problema sia già a monte.

Ti faccio un esempio su un file preso a campione:
- se faccio la dir dal prompt di DOS mi da: 25/03/2019 13:43
- visto da Esplora risorse mi da: 25/03/2019 12:43
- visto con un altro file manager (Free Commander XE) mi da: 25/03/2019 13:43
- tutti i metodi che ho provato con Lazarus, mi danno: 25/03/2019 11:43

Credo però che "GetLocalTimeOffset" potrebbe tornarmi utile: al momento mi da come risultato -120. Al prossimo cambio dell'ora mi devo ricordare di riverificare il suo valore, e farci sopra qualche ragionamento.

Grazie, Mario

nomorelogic

  • Global Moderator
  • Hero Member
  • *****
  • Post: 2133
  • Karma: +8/-1
Re:Data ultima modifica di un file su rete Microsoft
« Risposta #3 il: Aprile 03, 2019, 05:23:51 pm »
se sommi 120 minuti alle 11:43 ottieni 13:43

se sei sicuro che l'ora 13:43 è quella giusta sai che GetLocalTimeOffset funziona bene
Imagination is more important than knowledge (A.Einstein)

bonmario

  • Hero Member
  • *****
  • Post: 728
  • Karma: +1/-1
Re:Data ultima modifica di un file su rete Microsoft
« Risposta #4 il: Aprile 04, 2019, 08:17:25 am »
Purtroppo non è così ....

Sono riuscito a recuperare i log del programma che ha creato quel file: è stato creato alle 12.43.

Credo che se i test che sto facendo oggi, li avessi fatti prima del cambio dell'ora, mi avrebbe dato 11:43, con un offset di -60 minuti.

Quindi, in merito al mio post precedente, l'unico che da una risposta corretta sembra essere "Esplora Risorse".

Ciao, Mario

bonmario

  • Hero Member
  • *****
  • Post: 728
  • Karma: +1/-1
Re:Data ultima modifica di un file su rete Microsoft
« Risposta #5 il: Aprile 05, 2019, 02:27:11 pm »
Ciao,
ho trovato la soluzione cercando su San Google "dst delphi", senza le virgolette.
dst sta per "Daylight Savings Time".


Codice: [Seleziona]
function  DataUltimaModifica(const NomeFile:String; TipoRitorno:TipoData):TDateTime;
var DirInfo: TSearchRec;
    UTCTime: TFileTime;
    GMTST: TSystemTime;
    LocalST: TSystemTime;
    ModifyDT: TDateTime;
    TZ: _TIME_ZONE_INFORMATION;
begin
  Result:=DimFileNonTrov;

  try
    if FindFirstUTF8(NomeFile, faAnyFile, DirInfo) = 0 then begin
      UTCTime:=DirInfo.FindData.ftLastWriteTime;
      if FileTimeToSystemTime(UTCTime, GMTST) then begin
         // Get Timezone Information
        if GetTimeZoneInformation(TZ) <> 0 then begin
          if SystemTimeToTzSpecificLocalTime(@TZ, GMTST, LocalST) then begin
            ModifyDT:=SystemTimeToDateTime(LocalST);
            Result:=FormattaData(ModifyDT, TipoRitorno);
          end;
        end;
      end;
    end;
  finally
    FindCloseUTF8(DirInfo);
  end;
end;

Ciao, Mario

xinyiman

  • Administrator
  • Hero Member
  • *****
  • Post: 2677
  • Karma: +9/-0
Re:[RISOLTO] Data ultima modifica di un file su rete Microsoft
« Risposta #6 il: Aprile 05, 2019, 04:55:22 pm »
Ottimo, grazie della condivisione.
Ieri è passato, domani è futuro, oggi è un dono...

bonmario

  • Hero Member
  • *****
  • Post: 728
  • Karma: +1/-1
Re:[RISOLTO] Data ultima modifica di un file su rete Microsoft
« Risposta #7 il: Aprile 10, 2019, 01:48:16 pm »
Ciao,
alla fine ho messo tutto in una unit, in modo da poterla usare ovunque mi dovesse servire.

Eccola:
Codice: [Seleziona]
unit BonMarGestDataOra;

{$mode objfpc}{$H+}

interface

uses LazFileUtils, LazUTF8, SysUtils, dateutils
  {$IFDEF UNIX}
    , Unix, unixutil
  {$ELSE}
    , windows
  {$ENDIF}
  ;

const CstConvDataErr=-1;

  function  UnixTimeToLocalTime(UnixFileTime: Int64; var WrkDateTime:TDateTime):Boolean;
  {$IFDEF MSWINDOWS}
  function  UTCFileTimeToLocalTime(UTCFileTime: TFileTime; var WrkDateTime:TDateTime):Boolean;
  {$ENDIF}
  function  DataUltimaModifica(const NomeFile:String):TDateTime;
  function  DataDiCreazione(const NomeFile: String): TDateTime;

implementation

var
    {$IFDEF UNIX}
      SegnaPosto:Integer; //Messa solo per non adre errori di compilazione in Linux
    {$ELSE}
      TZ: _TIME_ZONE_INFORMATION;
    {$ENDIF}



{$IFDEF UNIX}
  function  UnixTimeToLocalTime(UnixFileTime: Int64; var WrkDateTime:TDateTime):Boolean;
  var DiffTimeLinux:Longint;
  begin
    //Inizializzazione output
    Result:=False;
    WrkDateTime:=CstConvDataErr;

    //Trasformo la Data/Ora Unix in una data normale
    WrkDateTime:=UnixToDateTime(UnixFileTime);

    //Determino il DST tra la data che devo gestire ed oggi
    GetLocalTimezone(UnixFileTime);
    DiffTimeLinux:=Tzseconds;

    //Rettifico l'orario ed emetto il risultato
    WrkDateTime:=IncSecond(WrkDateTime, DiffTimeLinux);
    Result:=True;
  end;
{$ELSE}
  function  UnixTimeToLocalTime(UnixFileTime: Int64; var WrkDateTime:TDateTime):Boolean;
  var GMTST: TSystemTime;
      LocalST: TSystemTime;
      ModifyDT: TDateTime;
  begin
    //Inizializzazione output
    Result:=False;
    WrkDateTime:=CstConvDataErr;

    //Trasformo la Data/Ora Unix in una data normale
    WrkDateTime:=UnixToDateTime(UnixFileTime);

    //Trasformo la data/ora appena trovata in una di sistema
    DateTimeToSystemTime(WrkDateTime, GMTST);

    //Converto l'orario in base ai dati della TimeZone
    if SystemTimeToTzSpecificLocalTime(@TZ, GMTST, LocalST) then begin
      //Converto la data nel formato corretto
      ModifyDT:=SystemTimeToDateTime(LocalST);

      //Comunico al chiamante che la conversione è andata a buon fine,
      //e ladata/ora corretta
      WrkDateTime:=ModifyDT;
      Result:=True;
    end;
  end;
{$ENDIF}


{$IFDEF MSWINDOWS}
function  UTCFileTimeToLocalTime(UTCFileTime: TFileTime; var WrkDateTime:TDateTime):Boolean;
var GMTST: TSystemTime;
    LocalST: TSystemTime;
    ModifyDT: TDateTime;
begin
  //Inizializzazione output
  Result:=False;
  WrkDateTime:=CstConvDataErr;

  //Converto la data di un file in una data di sistema
  if FileTimeToSystemTime(UTCFileTime, GMTST) then begin
    //Converto l'orario in base ai dati della TimeZone
    if SystemTimeToTzSpecificLocalTime(@TZ, GMTST, LocalST) then begin
      //Converto la data nel formato corretto
      ModifyDT:=SystemTimeToDateTime(LocalST);

      //Comunico al chiamante che la conversione è andata a buon fine,
      //e ladata/ora corretta
      WrkDateTime:=ModifyDT;
      Result:=True;
    end;
  end;
end;
{$ENDIF}




{Restituisco la data & ora di ultima modifica.
 ATTENZIONE: DirInfo.Time restituisce la data di creazione, non modifica !!!}
{$IFDEF MSWINDOWS}
  {
  function  DataUltimaModifica(const NomeFile:String;TipoRitorno:TipoData):TDateTime;
  var hFile:Integer;
      ftModifica, ftCreazione, ftAccesso:TFileTime;
      sysDateTime:_SYSTEMTIME;
  begin
    Result:=CstConvDataErr;

    hFile:=0;
    try
      hFile:=CreateFile(PChar(NomeFile),
                        GENERIC_READ ,
                        FILE_SHARE_READ or FILE_SHARE_WRITE, //Faccio in modo di poter reperire la data
                        nil,                                 //anche dai files vincolati
                        OPEN_EXISTING,
                        FILE_FLAG_BACKUP_SEMANTICS,
                        0);
      if (GetLastError = 0) then begin
        GetFileTime(hFile, @ftCreazione, @ftAccesso, @ftModifica);
        if (GetLastError = 0) then begin
          FileTimeToLocalFileTime(ftModifica, ftModifica);
          FileTimeToSystemTime(ftModifica, sysDateTime);
          Result:=SystemTimeToDateTime(sysDateTime);
        end;
      end;
    finally
      if (hFile <> 0) then begin
        CloseHandle(hFile);
      end;
    end;
  end;
  }
  function  DataUltimaModifica(const NomeFile:String):TDateTime;
  var DirInfo: TSearchRec;
      UTCFileTime: TFileTime;
      WrkDateTime:TDateTime;
  begin
    Result:=CstConvDataErr;

    try
      if FindFirstUTF8(NomeFile, faAnyFile, DirInfo) = 0 then begin
        UTCFileTime:=DirInfo.FindData.ftLastWriteTime;

        if UTCFileTimeToLocalTime(UTCFileTime, WrkDateTime) then begin
          Result:=WrkDateTime;
        end;
      end;
    finally
      FindCloseUTF8(DirInfo);
    end;
  end;



  function  DataDiCreazione(const NomeFile: String): TDateTime;
  var DirInfo:TSearchRec;
      ftCreazione:TFileTime;
      WrkDateTime:TDateTime;
  begin
    Result:=CstConvDataErr;

    try
      if (FindFirstUTF8(NomeFile, faAnyFile, DirInfo) = 0) then begin
        ftCreazione:=DirInfo.FindData.ftCreationTime;

        if UTCFileTimeToLocalTime(ftCreazione, WrkDateTime) then begin
          Result:=WrkDateTime;
        end;

        {
        FileTimeToLocalFileTime(ftCreazione, ftCreazione);
        FileTimeToSystemTime(ftCreazione, sysDateTime);
        Result:=SystemTimeToDateTime(sysDateTime);
        }
      end;
    finally
      LazFileUtils.FindCloseUTF8(DirInfo);
    end;
  end;
{$ELSE}
  function  DataUltimaModifica(const NomeFile:String):TDateTime;
  var DataFile:Longint;
  begin
    DataFile:=FileAgeUTF8(NomeFile);

    //In caso di file non trovato, DataFile vale -1
    if (DataFile = -1) then begin
      Result:=CstConvDataErr;
    end else begin
      UnixTimeToLocalTime(DataFile, Result);
    end;
  end;



  function  DataDiCreazione(const NomeFile: String): TDateTime;
  var DataFile:Longint;
      DirInfo:TSearchRec;
  begin
    {
    //In linux la data di creazione di un file non viene salvata
    //https://www.cyberciti.biz/tips/understanding-unixlinux-filesystem-inodes.html

    => File type (executable, block special etc)
    => Permissions (read, write etc)
    => Owner
    => Group
    => File Size
    => File access, change and modification time (remember UNIX or Linux never stores
       file creation time, this is favorite question asked in UNIX/Linux sys admin job interview)
    => File deletion time
    => Number of links (soft/hard)
    => Extended attribute such as append only or no one can delete file including root
       user (immutability)
    => Access Control List (ACLs)

    All the above information stored in an inode.
    In short the inode identifies the file and its attributes (as above).
    Each inode is identified by a unique inode number within the file system.
    Inode is also know as index number.    }
    Result:=DataUltimaModifica(NomeFile);
  end;
{$ENDIF}






initialization
  //Questa operazione, se usata per ogni file, ad esempio perché sto elaborando un elenco,
  //potrebbe durare parecchio, quindi la lancio una volta sola
  {$IFDEF UNIX}
    ReadTimezoneFile(GetTimezoneFile);
  {$ELSE}
    GetTimeZoneInformation(TZ);
  {$ENDIF}

finalization;

end.

Ciao, Mario
« Ultima modifica: Aprile 11, 2019, 07:58:55 am da bonmario »

xinyiman

  • Administrator
  • Hero Member
  • *****
  • Post: 2677
  • Karma: +9/-0
Re:[RISOLTO] Data ultima modifica di un file su rete Microsoft
« Risposta #8 il: Aprile 10, 2019, 02:11:10 pm »
Ok, solo un consiglio spassionato. Non usare
Codice: [Seleziona]
{$IFDEF LINUX}
    , Unix, unixutil
  {$ELSE}
    , windows
  {$ENDIF}
ma usa
Codice: [Seleziona]
{$IFDEF UNIX}
    , Unix, unixutil
  {$ELSE}
    , windows
  {$ENDIF}

Così dovrebbe funzionare anche su mac. In quanto mac osx ha un kernel freebsd derivato.
Ieri è passato, domani è futuro, oggi è un dono...

bonmario

  • Hero Member
  • *****
  • Post: 728
  • Karma: +1/-1
Re:[RISOLTO] Data ultima modifica di un file su rete Microsoft
« Risposta #9 il: Aprile 10, 2019, 03:01:22 pm »
Grazie per il consiglio ... devo solo farci l'abitudine: i miei programmi li uso a casa o al lavoro, su PC Windows o Linux, non avendoli mai compilati/usati su Mac, non ho mai avuto il problema.

P.S. Di solito faccio il contrario: if Windows ... else ... in quel caso mi sarebbe andata bene !!!

Ciao, Mario

bonmario

  • Hero Member
  • *****
  • Post: 728
  • Karma: +1/-1
Re:[RISOLTO] Data ultima modifica di un file su rete Microsoft
« Risposta #10 il: Aprile 11, 2019, 08:01:35 am »
Ok, solo un consiglio spassionato. Non usare ....


Ciao,
ho "sistemato" il codice postato nel messaggio precedente seguendo il tuo consiglio e facendo un paio di piccole correzioni nel codice specifico per Linux/Unix.

Ciao, Mario

 

Recenti

How To

Trascinare un file nel programma da xinyiman
DB concetti fondamentali e ZeosLib da xinyiman
Recuperare codice HTML da pagina web da xinyiman
Mandare mail con Lazarus da xinyiman
Stabilire il sistema operativo da xinyiman
Esempio lista in pascal da xinyiman
File INI da xinyiman
Codice di attivazione da xinyiman
Realizzare programmi multilingua da xinyiman
Lavorare con le directory da xinyiman
Utilizzare Unità esterne da Loryea
TTreeView da xinyiman
TTreeview e Menu da xinyiman
Generare controlli RUN-TIME da xinyiman
LazReport, PDF ed immagini da xinyiman
Intercettare tasti premuti da xinyiman
Ampliare Lazarus da xinyiman
Lazarus e la crittografia da xinyiman
System Tray con Lazarus da xinyiman
UIB: Unified Interbase da Microges2000
Il file: questo sconosciuto da Microges2000
Conferma di chiusura di un applicazione da xinyiman
Liste e puntatori da Microges2000
Overload di funzioni da Microges2000
Funzioni a parametri variabili da Microges2000
Proprietà da Microges2000
Conversione numerica da Microges2000
TImage su Form e Panel da Maverich
Indy gestiore server FTP lato Client da Maverich
PopUpMenu sotto Pulsante (TSpeedButton) da Maverich
Direttiva $macro da Microges2000
Toolbar da xinyiman
Evidenziare voci TreeView da Maverich
Visualizzare un file Html esterno da Maverich
StatusBar - aggirare l'errore variabile duplicata da Maverich
Da DataSource a Excel da xinyiman
Le permutazioni da xinyiman
Brute force da xinyiman
Indy 10 - Invio email con allegati da Maverich
La gestione degli errori in Lazarus da xinyiman
Pascal Script da xinyiman
Linux + Zeos + Firebird da xinyiman
Dataset virtuale da xinyiman
Overload di operatori da Microges2000
Lavorare con file in formato JSON con Lazarus da nomorelogic
Zeos ... dietro le quinte (prima parte) da Stilgar
Disporre le finestre in un blocco unico (come Delphi) da Maverich
Aspetto retrò (Cmd Line) da xinyiman
Come interfacciare periferica twain da Narciso
Ubuntu - aggiornare free pascal e lazarus da xinyiman
fpcup: installazioni parallele di lazarus e fpc da nomorelogic
Free Pascal e Lazarus sul Raspberry Pi da nomorelogic
Cifratura: breve guida all'uso dell'algoritmo BlowFish con lazarus e free pascal. da nomorelogic
Creare un server multithread da xinyiman
guida all'installazione di fpc trunk da subversion in linux gentoo da nomorelogic
Indice da nomorelogic
DB concetti fondamentali e connessioni standard da xinyiman
Advanced Record Syntax da nomorelogic
DB concetti fondamentali e DBGrid da xinyiman
DB concetti fondamentali e TDBEdit, TDBMemo e TDBText da xinyiman
Advanced Record Syntax: un esempio pratico da nomorelogic
Superclasse form base per programmi gestionali (e non) da nomorelogic
Superclasse form base per programmi gestionali (e non) #2 - log, exception call stack, application toolbox da nomorelogic
Superclasse form base per programmi gestionali (e non) #3 - traduzione delle form da nomorelogic
Superclasse form base per programmi gestionali (e non) #4 - wait animation da nomorelogic
Un dialog per la connessione al database:TfmSimpleDbConnectionDialog da nomorelogic
Installare lazarus su mac osx sierra da xinyiman
immagine docker per lavorare con lazarus e free pascal da nomorelogic
Utenti
  • Utenti in totale: 636
  • Latest: @diego
Stats
  • Post in totale: 12665
  • Topic in totale: 1578
  • Online Today: 40
  • Online Ever: 520
  • (Novembre 04, 2018, 12:00:31 pm)
Utenti Online
Users: 0
Guests: 19
Total: 19

Disclaimer:

Questo blog non rappresenta una testata giornalistica poiché viene aggiornato senza alcuna periodicità. Non può pertanto considerarsi un prodotto editoriale ai sensi della legge n. 62/2001.