Mostrando entradas con la etiqueta TDateTime. Mostrar todas las entradas
Mostrando entradas con la etiqueta TDateTime. Mostrar todas las entradas

viernes, 21 de junio de 2019

Formato de fecha y hora en SQLite.

En SQLite el formato de la fecha/hora es YYYY-MM-DD HH:MM.SS.MMM por ejemplo: 2019-06-22 01:00:27.123

Si bien Free Pascal tiene muchas funciones para el tratamiento de fecha y hora, a veces por la configuración regional hay que hacer conversiones.

Usando TFormatSettings:

aFormatSettings.LongDateFormat:='yyyy-mm-dd hh:nn:ss';
aFormatSettings.DateSeparator := '-';
aFormatSettings.TimeSeparator := ':';


Donde aFormatSettings es una variable del tipo TFormatSettings y luego utilizando la función FormatDateTime que devuelve un string:

function FormatDateTime(

const FormatStr: string;

DateTime: TDateTime;

Options: TFormatDateTimeOptions = []

):string;

function FormatDateTime(

const FormatStr: string;

DateTime: TDateTime;

const FormatSettings: TFormatSettings;

Options: TFormatDateTimeOptions = []

):string;


Por ejemplo en una sentencia SQL en WHERE:

sqlWhere:='WHERE regfecha BETWEEN '+QuotedStr(FormatDateTime('YYYY-MM-DD',edFechaDesde.Date))+
' AND '+QuotedStr(FormatDateTime('YYYY-MM-DD',edFechaHasta.Date))';


En este caso no fue necesario TFormatSettings y solo fue fecha, sin hora.

Con TZquery.FieldByName y utilizando componentes TDateTimePicker esto funciona:

ZQReg.FieldByName('regfechahora').AsDateTime:=dtpFecha.Date+dtpHora.Time;

En cuanto los campos del tipo TIME en SQLite; StrToTime('00:00:00') evita el valor nulo que muchas veces conviene evitar.

En SQLite la fecha debe ir entre comillas simples.

Y ante cualquier complicación siempre podemos hacer una función como la siguiente:

function FormatoFechaHoraSQLite(lafechahora: TDateTime): String;
var
  d,m,a,h,mi,s,ms:Word;
  dd,mm,hh,mmi,ss,mms:String;
  lfecha, lhora:String;
begin
  DecodeDate(lafechahora,a,m,d);
  if d < 10 then dd:='0'+IntToStr(d) else dd:=IntToStr(d);

  if m < 10 then mm:='0'+IntToStr(m) else mm:=IntToStr(m);
  lfecha:=IntToStr(a)+'-'+mm+'-'+dd;
  DecodeTime(lafechahora,h,mi,s,ms);
  if h < 10 then hh:='0'+IntToStr(h) else hh:=IntToStr(h);
  if mi < 10 then mmi:='0'+IntToStr(mi) else mmi:=IntToStr(mi);
  if s < 10 then ss:='0'+IntToStr(s) else ss:=IntToStr(s);
  if ms < 10 then mms:='00'+IntToStr(ms) else
    if ms < 100 then mms:='0'+IntToStr(ms) else
      mms:=IntToStr(ms);
  lhora:=hh+':'+mmi+':'+ss+'.'+mms;
  Result:=lfecha+' '+lhora;
end;

O más sencillo usando la función AddChar que se encuentra en la unidad strutils.

function FormatoFechaHoraSQLite2(lafechahora: TDateTime): String;
var
  d,m,a,h,mi,s,ms:Word;
  dd,mm,hh,mmi,ss,mms:String;
  lfecha, lhora:String;
begin
  DecodeDate(lafechahora,a,m,d);
  dd:=AddChar('0',IntToStr(d),2);
  mm:=AddChar('0',IntToStr(m),2);
  lfecha:=IntToStr(a)+'-'+mm+'-'+dd;
  DecodeTime(lafechahora,h,mi,s,ms);
  hh:=AddChar('0',IntToStr(h),2);
  mmi:=AddChar('0',IntToStr(mi),2);
  ss:=AddChar('0',IntToStr(s),2);
  mms:=AddChar('0',IntToStr(ms),3);
  lhora:=hh+':'+mmi+':'+ss+'.'+mms;
  Result:=lfecha+' '+lhora;
end;


DecodeDate y DecodeTime son procedimientos y utiliza variables del tipo Word que son enteros sin signo entre 0 y 65535. Le enviamos un TDateTime y las variables del tipo Word donde se escribirán el año, mes y día (en DecodeDate). No es necesario inicializar las variables, el procedimiento utiliza out:

procedure DecodeDate(

Date: TDateTime;

out Year: Word;

out Month: Word;

out Day: Word

);

domingo, 26 de noviembre de 2017

Recorrer un DataSet y actualizar registros

Si queremos actualizar un campo de una fila o registro mientras recorremos el TDataSet por ejemplo mediante un while, obtendremos un error en tiempo de ejecución. Con un ejemplo será más sencillo:

WHILE NOT ZQuery1.EOF DO
begin
  ZQuery1.Edit;
  ZQuery1.FieldByName('alguncampo').AsInteger:=0;   
  ZQuery1.Post
  ZQuery1..Next;
end;


El código precendente nos dará el error y es correcto que lo haga, porque no situamos el puntero al comienzo del DataSet que sería con ZQuery1.First.

ZQuery1.First;
WHILE NOT ZQuery1.EOF DO
begin
  ZQuery1.Edit;
  ZQuery1.FieldByName('alguncampo').AsInteger:=0;   
  ZQuery1.Post
  ZQuery1..Next;
end;


Otra manera de resolver esto es mediante el uso de ExecuteDirect (y más rápido si se trata de un gran volumen), si tenemos un identificador único, mejor:

ZQuery1.First;
WHILE NOT ZQuery1.EOF DO
begin
  ZConnection1.ExecuteDirect('UPDATE tabla SET alguncampo=0 WHERE    identificaorunico='+ZQuery1.FieldByName('id').AsString'+' ;');
  ZQuery1..Next;
end;


Se recomienda hacer esto cuando no podamos hacerlo mediante una sentencia SQL UPDATE, ya que puede ser lento dependiendo del volumen de datos.

domingo, 3 de septiembre de 2017

Diferencia horaria entre dos fechas

El tipo TDateTime es un número del tipo Double cuya parte entera se utiliza para la parte de la fecha y la parte fraccionaria para la hora.

Free Pascal dispone de una gran cantidad de funciones para el tratamiento de fechas y horas en la unidad dateutils.

En este ejemplo solo veremos como calcular la diferencia horaria, la parte time, de dos TDateTime y también la cantidad de horas entre dos fechas también del tipo TDateTime.


Lo primero que notamos es que el cálculo del tiempo transcurrido entre las 19:00 y 02:27 es correcto, 7 horas y 27 minutos.
Lo segundo, es que si se tomarán en cuenta los días de las fechas, las horas transcurridas serían 55 y 27 minutos.
Lo tercero, la cantidad de horas es correcta, 55, pero se ignoran los minutos.

Pero según lo que se necesite, esto puede servir o resultar insuficiente, en tal caso, hay que buscar la combinación de funciones que nos resuelvan el tema y de última siempre están las funciones Decode* y Encode* mediante las cuales, podemos hacer lo que queramos, aunque deberemos escribir más código.

El código del ejemplo:

unit Unit1;

{$mode objfpc}{$H+}

interface

uses
    Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, dateutils;

type

        { TForm1 }

    TForm1 = class(TForm)
                btnDiferencia: TButton;
                btnCantidad: TButton;
                Label1: TLabel;
                Label2: TLabel;
                Label3: TLabel;
                Label4: TLabel;
                procedure btnCantidadClick(Sender: TObject);
    procedure btnDiferenciaClick(Sender: TObject);
    private
        fechainicio, fechafin:TDateTime;
        { private declarations }
    public
        { public declarations }
    end;

var
    Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1.btnDiferenciaClick(Sender: TObject);
var
  Diferencia:TDateTime;
begin
  fechainicio:=StrToDateTime('05-07-2017 19:00');
  fechafin:=StrToDateTime('08-07-2017 02:27');
  Diferencia:=fechafin-fechainicio;
  Label3.Caption:=TimeToStr(TimeOf(Diferencia));
end;

procedure TForm1.btnCantidadClick(Sender: TObject);
var
  canthoras:Int64;
begin
  fechainicio:=StrToDateTime('05-07-2017 19:00');
  fechafin:=StrToDateTime('08-07-2017 02:27');
  canthoras:=HoursBetween(fechafin,fechainicio);
  Label4.Caption:=IntToStr(canthoras);
end;

end.

La función TimeOf recibe como parámetro un valor del tipo TDateTime y retorna la parte horaria, es decir, le pasamos un TDateTime y nos devuelve un TTime, por tal motivo utilizamos TimeToStr en lugar DateTimeToStr.

La función HoursBetween recibe como parámetros dos valores del tipo TDateTime y retorna un valor del tipo Int64 que serán la cantidad de horas entre las fechas.

Código fuente: Diferencia horaria entre fechas.7z

o en GitLab

sábado, 2 de septiembre de 2017

Comparar horas

CompareTime es un función que nos permite comparar tiempo entre dos valores del tipo TDateTime o TTime. Si el valor es del tipo TDateTime, la parte del valor correspondiente a la fecha, es ignorada.

Esta función se encuentra en DateUtils por lo tanto debe agregarse en uses.

La función recibe como parámetros dos constantes del tipo TDateTime y devuelve un TValueRelationship cuyos valores están en el rango -1..1

function CompareTime ( const A: TDateTime; const B: TDateTime ) : TValueRelationship;

Definición según la wiki de Free Pascal.

Los parámetros aceptados son tanto del tipo TDateTime como TTime.

Si los valores son iguales, entonces devuelve 0 (cero).

Si el primer valor es anterior o más temprano que el segundo, entonces devuelve un valor menor a 0 (cero), es decir, negativo.

Si el primer valor es posterior o más tarde que el segundo, entonces devuelve un valor mayor a 0 (cero), es decir, positivo.

El valor retornado por la función puede almacenarse en una variable del tipo Integer y si bien la documentación habla de valores mayores, iguales o menores a 0 (cero), siendo del tipo entero entonces solo debería retornar 1, 0 o -1.

Ejemplo:


Código:

unit Unit1;

{$mode objfpc}{$H+}

interface

uses
    Classes, SysUtils, FileUtil, DateTimePicker, Forms, Controls, Graphics, dateutils,
        Dialogs, StdCtrls;

type

        { TForm1 }

    TForm1 = class(TForm)
                btnComparar: TButton;
                DateTimePicker1: TDateTimePicker;
                DateTimePicker2: TDateTimePicker;
                Label1: TLabel;
                Label2: TLabel;
                Memo1: TMemo;
                procedure btnCompararClick(Sender: TObject);
    private
        { private declarations }
    public
        { public declarations }
    end;

var
    Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1.btnCompararClick(Sender: TObject);
begin
   CASE CompareTime(DateTimePicker1.Time,DateTimePicker2.Time) of
     1 : Memo1.Append('Llegó temprano');
     0 : Memo1.Append('Llego en horario.');
    -1 : Memo1.Append('Llegó tarde.');
     end;
end;

end.     

Descargar el código (.pas y .lfm): CompareTime.7z



domingo, 11 de junio de 2017

Calcular diferencia entre fechas

La función DaysBetween retorna el número de días entre dos fechas.

function DaysBetween (const ANow, aThen: TDateTime):Integer;

El primer parámetro es la fecha que se restará de la fecha del segundo parámetro. La función devuelve un entero que es la diferencia en días entre aThen y aNow, es decir, aThen - aNow.

Ejemplo:


var
  fechaInicio, fechaFin : TDate;
  intDias : Integer;
begin
  fechaInicio := StrToDate ('11/06/2017');
  fechaFin := StrToDate ('12/06/2017');
  intDias := DaysBetween (fechaInicio, fechaFin);
  ShowMessage (IntToStr (intDias)); // devuelve 1
end;