2009-03-23 13 views
28

Hasta donde yo sé, no hay forma de hacerlo, pero voy a preguntarlo en caso de que alguien más sepa cómo hacerlo. ¿Cómo puedo declarar una fecha como const en Delphi?Declare un TDateTime como Const en Delphi

La única solución que he encontrado es utilizar el equivalente numérico, que es tipo de un dolor para mantener porque no es legible para el ser humano.

const 
    Expire : TDateTime = 39895; // Is actually 3/23/2009 

Lo que me gustaría ser capaz de hacer es algo como esto:

const 
    Expire : TDateTime = TDateTime ('3/23/2009'); 

o

const 
    Expire : TDateTime = StrToDate('3/23/2009'); 

Así que vamos a saber si esto es una solicitud de función o si sólo se perdió la forma de hacer esto (sí, sé que parece una cosa extraña de querer ...)

+0

Gran pregunta: a menudo he querido hacer esto (más por tiempos que por fechas, pero el principio es muy similar - por ejemplo, quiero poner 6:45 pm en un TDateTime como const, etc.). Invariablemente termino haciendo algo como tu primer ejemplo, con comentarios, ¡y me duele cuando más tarde necesito cambiarlo! – robsoft

+0

Esto parece algo que GExperts o DLangExtensions deberían poder hacer, ya sea como un experto para ingresar la fecha y/o la hora para crear una constante debidamente comentada, o como una cadena de conversión de preprocesador a TDateTime. Permitir formatos ISO 8601 solo debe eliminar toda ambigüedad. – mghie

+0

@Mghie - buen punto. Una solución GExperts sería perfectamente aceptable para mí. Es cuando tengo que sacar la calculadora para comenzar a hacer divisiones que me frustran. :-) – robsoft

Respuesta

12

¿El único? posible manera, pero probablemente no sea lo que está buscando:

const 
{$J+} 
    Expire: TDateTime = 0; 
{$J-} 

initialization 
    Expire := EncodeDate(2009, 3, 23); 
+1

También puede declararlo como var en lugar de const. –

+1

Sí, tienes razón, pero al menos mi solución usa la palabra clave const;) –

+0

Jim, mi error tipográfico se origina en tu publicación: P –

6

No, Delphi no es compatible con eso.

Su primera idea sería una solicitud de literales de fecha y hora distintos de los literales de coma flotante ordinarios. Encontré QC 72000, que muestra los valores TDateTime como fechas en el depurador, pero nada sobre su solicitud particular. Aunque no es como si nadie lo hubiera mencionado antes. Es un tema perenne en los grupos de noticias; Simplemente no puedo encontrar nada en QC al respecto.

Su segunda idea requeriría StrToDate para ser evaluable en tiempo de compilación. No veo ninguna entrada en QC al respecto tampoco, pero por lo que vale, C++ está obteniendo esa característica para las funciones que tienen las cualidades necesarias. StrToDate no cumpliría con esos requisitos, sin embargo, porque es sensible a la configuración de fecha de la configuración regional actual.

+1

EncodeDate, EncodeTime no se ven afectados y se adaptan al requisito. –

+0

No del todo, @Craig. Uno de los requisitos de C++ es que la función no puede arrojar excepciones (implícita en el requisito de que la función consista únicamente en una declaración 'return').Las funciones Delphi tienen declaraciones compuestas y pueden lanzar. –

+1

Un ligero malentendido, debería haber sido menos ambiguo en mi comentario. Permítanme explicar: EncodeDate y EncodeTime no se ven afectados (por localización, son deterministas) y se adecuarían al requisito (de que Jim especifique una fecha/hora constante, aunque sintácticamente diferente de su pregunta). Por supuesto, la idea es un punto discutible ya que Delphi actualmente no tiene esa característica. :(Sin embargo, su comentario sobre el requisito de excepción de C++ es interesante. –

4

La respuesta de Rob Kennedy muestra que la solución StrToDate es inherentemente inadmisible ya que no desea que su código se rompa si está compilado en Europa.

Estoy de acuerdo en que debería haber alguna forma de hacer EncodeDate pero no es así.

Por lo que a mí respecta, el compilador simplemente debe compilar y ejecutar cualquier código que encuentre en una asignación constante y almacenar el resultado en la constante. Dejaría que el programador se asegure de que el código no sea sensible a su entorno.

8

No hay forma de hacerlo porque interpretar un literal de fecha en sí mismo no es determinista, depende de la convención/localidad que sigas.
'1/4/2009' no está en enero para cualquier persona francesa, por ejemplo, y tener el compilador traducido como 4 de enero lo convertiría en un compilador tonto ;-)
A menos que el compilador implemente alguna (bien documentada) "magia" "Función bijective para emparejar un valor de fecha y una representación de pantalla ... Y de todos modos, a la mitad del planeta no le gustaría.
La única forma no ambigua que veo ahora es proporcionar el valor incluso si se ve como un dolor ... ... mi $ 0,02

+3

Sólo depende de la configuración regional si el idioma se define como sensible a la configuración regional. Los literales de coma flotante no son sensibles a la configuración regional, simplemente no aceptan comas como el separador decimal. No hay razón para que un literal de fecha y hora no tenga restricciones similares en el formato. –

+1

EncodeDate y EncodeTime son deterministas, por lo que serían utilizables ** if ** podrían evaluarse en tiempo de compilación. –

3

fecha Un Delphi es el # de days since Dec 30, 1899. Por lo tanto, probablemente se te ocurra una fórmula matemática elaborada para expresar una fecha como una const.Entonces podrías formatearlo de manera muy extraña, para enfatizar las partes legibles por humanos. Mi mejor intento está abajo, pero está muy incompleto; por un lado, supone que todos los meses tienen 30 días.

Sin embargo, mi ejemplo es más que nada divertido. En la práctica, esto es bastante ridículo.

const 
    MyDate = ((
      2009 //YEAR 
              - 1900) * 365.25) + ((
      3  //MONTH 
              - 1) * 30) + 
      24 //DAY 
      ; 
+0

Me gusta, pero como usted señaló, tiene algunos problemas. –

+0

la parte fraccionaria también puede causar problemas a medida que su fecha se mueve lentamente desde la medianoche un año, a las 6 a.m., mediodía, a las 6 p.m. para regresar nuevamente en el año bisiesto a la medianoche. – skamradt

+0

Sí, absolutamente cierto Como dije, esto no es posible a menos que dediques mucho tiempo a diseñar una forumla realmente sofisticada para manejar todas las posibilidades. Mucho mejor solo obteniendo el valor y codificándolo. – JosephStyons

4

Una solución sería crear una lista de constantes durante años, otra para las compensaciones de un mes y luego compilarla sobre la marcha. Tendría que ocuparse de los años bisiestos añadiendo 1 a cada constante resultante. Sólo unos pocos de abajo para empezar ... :)

Const 
    Leap_Day = 1; // use for clarity for leap year dates beyond feb 29. 
    Year_2009 = 39812; // January 1, 2009 
    Year_2010 = Year_2009 + 365; // January 1, 2010 
    Year_2011 = Year_2010 + 365; // January 1, 2011 
    Year_2012 = Year_2011 + 365; // January 1, 2012 (is leap year) 
    Year_2013 = Year_2012 + Leap_Day + 365; // January 1, 2013 

Const 
    Month_Jan = -1; // because adding the day will make the offset 0. 
    Month_Feb = Month_Jan + 31; // 31 days more for the first day of Feb. 
    Month_Mar = Month_Feb + 28; // 28 days more for the first day of Mar. 
    Month_Apr = Month_Mar + 30; // 30 days more for the first day of Apr. 

Const 
    Expire_Jan1 : tDateTime = Year_2009 + Month_Jan + 1; 
    Expire : tDateTime = Year_2009 + Month_Mar + 23; 

Si usted tiene un año bisiesto después hay que añadir al menos 1 a nada más allá de febrero de ese año.

Const 
    Expire : tDateTime = Year_2008 + Month_Mar + 23 + Leap_Day; 

EDITAR

añadido unos cuantos años más para mayor claridad, y se añade una constante Leap_Day.

+0

¿Por qué no agrega otra constante: Leap_day = 1. De esta manera no hay un falso "+1" sentado que puede no ser intuitivo a primera vista ... –

1

Creo que la mejor solución disponible para usted es declarar:

ArmisticeDay: TDateTime = 6888.0 + (11.0/24.0); //Nov 11, 1918 11 AM 

y aceptarlo.


Mi intento Nº1

Expire = EncodeDate(2009, 3, 23); 

[error] expresión constante espera

Mi intento Nº2

Expire: TDateTime = EncodeDate(2009, 3, 23); 

[error] expresión constante espera

Así que, aunque son constantes, y determinista (es decir, no depende de ninguna información de localización), todavía no funciona.

18

Bien, mi reacción es un poco tarde, pero aquí hay una solución para la nueva Delphi.

Utiliza sobrecargas de clases implícitas para que los registros de este tipo puedan usarse como si fueran variables TDateTime.

TDateRec = record 
    year,month,day,hour,minute,second,millisecond:word; 
    class operator implicit(aDateRec:TDateRec):TDateTime; 
    class operator implicit(aDateTime:TDateTime):TDateRec; // not needed 
    class operator implicit(aDateRec:TDateRec):String; // not needed 
    class operator implicit(aDateRec:String):TDateRec; // not needed 
    end; 

Implementación:

uses DateUtils; 

class operator TDateRec.Implicit(aDateRec:TDateRec):TDateTime; 
begin 
    with aDateRec do // Yeah that's right you wankers. I like "with" :) 
    Result := encodeDateTime(Year,Month,Day,Hour,Minute,Second,Millisecond); 
end; 

class operator TDateRec.Implicit(aDateTime:TDateTime):TDateRec; 
begin 
    with Result do 
    DecodeDateTime(aDateTime,Year,Month,Day,Hour,Minute,Second,Millisecond); 
end; 

class operator TDateRec.Implicit(aDateRec:TDateRec):String; 
begin 
    Result := DateTimeToStr(aDateRec) 
end; 

class operator TDateRec.Implicit(aDateRec:String):TDateRec; 
begin 
    Result := StrToDateTime(aDateRec) 
end; 

Ahora usted puede declarar su período como esto:

const 
    Date1:TDateRec=(Year:2009;month:05;day:11); 
    Date2:TDateRec=(Year:2009;month:05;day:11;hour:05); 
    Date3:TDateRec=(Year:2009;month:05;day:11;hour:05;minute:00); 

Para ver si funciona, ejecute lo siguiente:

ShowMessage(Date1); // it can act like a string 
ShowMessage(DateToStr(Date1)); // it can act like a date 

Si Realmente quieres reemplazar todo tu Tdat Variables eTime con esto, probablemente necesite sobrecargar también a otros operadores (Agregar, restar, explícito, ...).

+0

+1 para la solución y +1 nuevamente para 'con', aunque despreciar su uso :-) –

+0

Tomé esto y agregué mis propias adiciones ... 'FriendlyDate',' FriendlyTime', y 'FriendlyDateTime' –

8

Tiendo a simular const fechas con una función. Técnicamente son un poco más constante que la asignación "pseudo constante" tipada const 's.

function Expire: TDateTime; 
begin 
    Result := EncodeDate(2009, 3, 23); 
end; 

NOTA el uso de EncodeDate en lugar de StrToDate. StrToDate se ve afectado por las configuraciones regionales, lo que significa que no hay garantía de que se interprete una cadena como se esperaría.

Por ejemplo, ¿sabía usted que hay un extraño grupo de personas que piensan que tiene sentido "mezclar" partes de fecha en un orden inconsistente de importancia? Utilizan la mitad, luego la parte menos importante (por ejemplo, '3/23/2009') < sonrisa ingeniosa >. La única vez que la lógica tiene sentido es cuando se enciende 102 años - entonces usted puede reclamar su edad es de 021.

Para los optimizadores prematuros por ahí, si la función se llama con tanta frecuencia que las nano segundos requerido para codificar una fecha se convierte en un problema - usted tiene un problema más grande que esta pequeña ineficiencia en el nombre de código legible y mantenible.

Cuestiones relacionadas