Italian community of Lazarus and Free Pascal

Programmazione => Generale => Topic aperto da: xinyiman - Marzo 14, 2017, 02:08:57 pm

Titolo: SNTP con lazarus
Inserito da: xinyiman - Marzo 14, 2017, 02:08:57 pm
Ciao ragazzi, una domanda, in lazarus ho bisogno di prendere la data e l'ora corretta da un server NTP con questo codice, dove XXX.XXX.XXX.XXX è l'indirizzo ip del server. Ho usato il codice che segue estrapolandolo dagli esempi di synapse. Compila, in esecuzione non da errori, però io mi aspetto di ricevere la data attuale (14:07) e invece mi ritorna un'ora indietro (13:07). So che si tratta dell'ora legale/solare. Ma da codice come faccio a farlo funzionare per ottenere la data che mi aspetto?

Grazie


Codice: [Seleziona]
program project1;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes, SysUtils, CustApp
  { you can add units after this }
  ,SNTPsend
  ;

type

  { TMyApplication }

  TMyApplication = class(TCustomApplication)
  protected
    procedure DoRun; override;
  public
    constructor Create(TheOwner: TComponent); override;
    destructor Destroy; override;
    procedure WriteHelp; virtual;
  end;

{ TMyApplication }

procedure TMyApplication.DoRun;
var
  ErrorMsg: String;
  sntp:TSntpSend;
begin
  // quick check parameters
  ErrorMsg:=CheckOptions('h','help');
  if ErrorMsg<>'' then begin
    ShowException(Exception.Create(ErrorMsg));
    Terminate;
    Exit;
  end;

  // parse parameters
  if HasOption('h','help') then begin
    WriteHelp;
    Terminate;
    Exit;
  end;

  { add your program here }

   sntp:=TSntpSend.Create;
  try
    sntp.TargetHost:='XXX.XXX.XXX.XXX';
    if sntp.GetSNTP
      then writeln(Datetimetostr(sntp.NTPTime)+' UTC')
      else writeln('Not contacted!');
  finally
    sntp.Free;
  end;

  // stop program loop
  Terminate;
end;

constructor TMyApplication.Create(TheOwner: TComponent);
begin
  inherited Create(TheOwner);
  StopOnException:=True;
end;

destructor TMyApplication.Destroy;
begin
  inherited Destroy;
end;

procedure TMyApplication.WriteHelp;
begin
  { add your help code here }
  writeln('Usage: ',ExeName,' -h');
end;

var
  Application: TMyApplication;
begin
  Application:=TMyApplication.Create(nil);
  Application.Title:='My Application';
  Application.Run;
  Application.Free;
end.
Titolo: Re:SNTP con lazarus
Inserito da: xinyiman - Marzo 14, 2017, 02:29:05 pm
Ok, rileggendo ho detto una caxxata. La differenza di un ora è legata al fuso orario con il meridiano di Greenwich. Ma il problema persiste, come calcolo l'ora o le due ore di differenza in relazione all'ora legale/solare?
Titolo: Re:SNTP con lazarus
Inserito da: bonmario - Marzo 14, 2017, 06:30:01 pm
Ciao,
tempo fa' avevo usato il codice qui sotto, però poi non avevo avuto modo di testarlo con il cambio dell'ora per verificarne l'effettivo funzionamento.
Prova a vedere se ti può essere d'aiuto.

Codice: [Seleziona]
function TForm1.LeggiDataOra(var WrkDataOra:TDateTime):Boolean;
var sntp :TSNTPSend;
    remoteTime:TDateTime;
    TimeZone: TTimeZoneInformation;
    OreDiff:Integer;
begin
  Result:=False;
  sntp:=TSNTPSend.Create;
  sntp.Timeout:=1000;
  sntp.TargetHost:='0.pool.ntp.org';
  sntp.SyncTime:=TRUE;
  // 'Contacting ' + sntp.TargetHost + ' on port ' +sntp.TargetPort;
  try
    try
      if sntp.GetSNTP then begin
        remoteTime:= sntp.NTPTime;

        //Determino quante ore aggiungere/togliere in base al fuso orario attuuale
        //ed al fatto che sia in vigore l'ora l'ora legale o solare
        GetTimeZoneInformation(TimeZone);
        OreDiff:=TimeZone.DaylightDate.Hour         //Ore di differenza del Fuso Orario
                 - (TimeZone.Bias div 60)           //??????????????
                 + (TimeZone.DaylightBias div 60);  //Ora legale/solare
        Sleep(0);
        //Oggi, 01/04/2016, quindi con l'ora legale, i valori di "TimeZone" sono Quelli qui sotto.
        //   OreDiff vale 2
        //   P.S. Secondo me, la discriminante da curare, sono i campi con "BIAS" nel nome
        {
        record _TIME_ZONE_INFORMATION {
          BIAS = -60,
          STANDARDNAME = 'ora solare Europa occidentale'#0#0,
          STANDARDDATE = {
            WYEAR = 0,
            WMONTH = 10,
            WDAYOFWEEK = 0,
            WDAY = 5,
            WHOUR = 3,
            WMINUTE = 0,
            WSECOND = 0,
            WMILLISECONDS = 0,
            YEAR = 0,
            MONTH = 10,
            DAYOFWEEK = 0,
            DAY = 5,
            HOUR = 3,
            MINUTE = 0,
            SECOND = 0,
            MILLISECOND = 0},
          STANDARDBIAS = 0,
          DAYLIGHTNAME = 'ora legale Europa occidentale'#0#0,
          DAYLIGHTDATE = {
            WYEAR = 0,
            WMONTH = 3,
            WDAYOFWEEK = 0,
            WDAY = 5,
            WHOUR = 2,
            WMINUTE = 0,
            WSECOND = 0,
            WMILLISECONDS = 0,
            YEAR = 0,
            MONTH = 3,
            DAYOFWEEK = 0,
            DAY = 5,
            HOUR = 2,
            MINUTE = 0,
            SECOND = 0,
            MILLISECOND = 0},
          DAYLIGHTBIAS = -60}        }






        //Rettifico l'ora in base al fuso orario attuale
        WrkDataOra:=IncHour(remoteTime, OreDiff);

        //Memo1.Lines.Add('Remote time is :' + DateTimeToStr(remoteTime)+' UTC');
        Result:=True;
      end else begin
        //Visto che la data non è stata reperita, ci metto dentro l'errore !!!!
        WrkDataOra:=sntp.Sock.LastError;
      end;
    except
      On E:Exception do Sleep(0); //Memo1.Lines.Add('Exception ' + E.ClassName + ': ' +E.Message);
    end;
  finally
    sntp.Free;
  end;
end;

Ciao, Mario
Titolo: Re:SNTP con lazarus
Inserito da: nomorelogic - Marzo 15, 2017, 08:26:45 am
puoi postare l'intera stringa che ti viene restituita?
Titolo: Re:SNTP con lazarus
Inserito da: xinyiman - Marzo 15, 2017, 03:45:12 pm
Peccato che funziona solo su windows e non su linux perchè la TTimeZoneInformation si trova nella unit windows.  :'(

Ciao,
tempo fa' avevo usato il codice qui sotto, però poi non avevo avuto modo di testarlo con il cambio dell'ora per verificarne l'effettivo funzionamento.
Prova a vedere se ti può essere d'aiuto.

Codice: [Seleziona]
function TForm1.LeggiDataOra(var WrkDataOra:TDateTime):Boolean;
var sntp :TSNTPSend;
    remoteTime:TDateTime;
    TimeZone: TTimeZoneInformation;
    OreDiff:Integer;
begin
  Result:=False;
  sntp:=TSNTPSend.Create;
  sntp.Timeout:=1000;
  sntp.TargetHost:='0.pool.ntp.org';
  sntp.SyncTime:=TRUE;
  // 'Contacting ' + sntp.TargetHost + ' on port ' +sntp.TargetPort;
  try
    try
      if sntp.GetSNTP then begin
        remoteTime:= sntp.NTPTime;

        //Determino quante ore aggiungere/togliere in base al fuso orario attuuale
        //ed al fatto che sia in vigore l'ora l'ora legale o solare
        GetTimeZoneInformation(TimeZone);
        OreDiff:=TimeZone.DaylightDate.Hour         //Ore di differenza del Fuso Orario
                 - (TimeZone.Bias div 60)           //??????????????
                 + (TimeZone.DaylightBias div 60);  //Ora legale/solare
        Sleep(0);
        //Oggi, 01/04/2016, quindi con l'ora legale, i valori di "TimeZone" sono Quelli qui sotto.
        //   OreDiff vale 2
        //   P.S. Secondo me, la discriminante da curare, sono i campi con "BIAS" nel nome
        {
        record _TIME_ZONE_INFORMATION {
          BIAS = -60,
          STANDARDNAME = 'ora solare Europa occidentale'#0#0,
          STANDARDDATE = {
            WYEAR = 0,
            WMONTH = 10,
            WDAYOFWEEK = 0,
            WDAY = 5,
            WHOUR = 3,
            WMINUTE = 0,
            WSECOND = 0,
            WMILLISECONDS = 0,
            YEAR = 0,
            MONTH = 10,
            DAYOFWEEK = 0,
            DAY = 5,
            HOUR = 3,
            MINUTE = 0,
            SECOND = 0,
            MILLISECOND = 0},
          STANDARDBIAS = 0,
          DAYLIGHTNAME = 'ora legale Europa occidentale'#0#0,
          DAYLIGHTDATE = {
            WYEAR = 0,
            WMONTH = 3,
            WDAYOFWEEK = 0,
            WDAY = 5,
            WHOUR = 2,
            WMINUTE = 0,
            WSECOND = 0,
            WMILLISECONDS = 0,
            YEAR = 0,
            MONTH = 3,
            DAYOFWEEK = 0,
            DAY = 5,
            HOUR = 2,
            MINUTE = 0,
            SECOND = 0,
            MILLISECOND = 0},
          DAYLIGHTBIAS = -60}        }






        //Rettifico l'ora in base al fuso orario attuale
        WrkDataOra:=IncHour(remoteTime, OreDiff);

        //Memo1.Lines.Add('Remote time is :' + DateTimeToStr(remoteTime)+' UTC');
        Result:=True;
      end else begin
        //Visto che la data non è stata reperita, ci metto dentro l'errore !!!!
        WrkDataOra:=sntp.Sock.LastError;
      end;
    except
      On E:Exception do Sleep(0); //Memo1.Lines.Add('Exception ' + E.ClassName + ': ' +E.Message);
    end;
  finally
    sntp.Free;
  end;
end;

Ciao, Mario
Titolo: Re:SNTP con lazarus
Inserito da: xinyiman - Marzo 15, 2017, 03:45:42 pm
puoi postare l'intera stringa che ti viene restituita?


15-3-17 14:44:12 UTC (dove UTC l'aggiungo io al momento della writeln)
Titolo: Re:SNTP con lazarus
Inserito da: nomorelogic - Marzo 15, 2017, 05:41:09 pm
mi aspettavo che ci fosse una "Z" alla fine dell'orario ma sembra che così non è visto che UCT lo aggiungi tu

cmq se  ci fosse stata l'indicazione UTC o UTC+1 (CET) sarebbe un buon punto di partenza in quanto poi basta fare una conversione
esempio da UTC a UTC+1 basta aggiungere 1 ora per il fuso + eventualmente 1 ora aggiuntiva nel caso di ora legale

a questo punto credo che il tuo server NPT risponda per default con una determinata localizzazione (altrimenti non si spiega il fatto che la stringa è priva del suffisso UTC)

cerca di capire se è così

in alternativa potresti trovare un server che risponde in modo ISO
Titolo: Re:SNTP con lazarus
Inserito da: corradoventu - Marzo 26, 2017, 11:40:26 am
vedi timezone in http://wiki.freepascal.org/PascalTZ