View Issue Details

IDProjectCategoryView StatusLast Update
0026472FPCCompilerpublic2018-02-24 13:52
ReporterDenis Kozlov Assigned ToFlorian  
PrioritynormalSeverityminorReproducibilityN/A
Status resolvedResolutionfixed 
Product Version2.6.4 
Fixed in Version3.1.1 
Summary0026472: Add date/time tokens to comiler includes $I and $INCLUDE: YEAR, MONTH, DAY, HOUR, MINUTE, SECOND
DescriptionCurrently the build date/time can be inserted into code via compiler variables as so: {$I %DATE%} and {$I %TIME%} (http://www.freepascal.org/docs-html/prog/progsu41.html).

It would be very useful to also make the individual date/time tokens available too: {$I %YEAR%}, {$I %MONTH%}, {$I %DAY%}, {$I %HOUR%}, {$I %MINUTE%}, {$I %SECOND%}.

Or, alternatively, without polluting the naming space, as:
{$I %DATEYEAR%}, {$I %DATEMONTH%}, {$I %DATEDAY%}, {$I %TIMEHOUR%}, {$I %TIMEMINUTE%}, {$I %TIMESECOND%}.

There are several advantages:
1) {$I %DATE%} and {$I %TIME%} are inserted as strings and require parsing if any manipulations or reformatting needs to be done.
2) {$I %DATE%} and {$I %TIME%} are inserted as strings and can be easily found and replaced (patched) in the executable, which is a problem when used for some kind of restricted functionality.
TagsINCLUDE, patch
Fixed in Revision38329
FPCOldBugId
FPCTarget
Attached Files

Activities

Denis Kozlov

2014-07-12 17:23

reporter   ~0076198

Just to clarify: date/time tokens should be inserted as integers rather that strings.

Péter Gábor

2014-07-12 20:04

reporter   ~0076200

Last edited: 2014-07-12 20:06

View 2 revisions

To make unable the direct reading of strings from your files (executables too) you can use simple or advanced cryptography...
- xor all chars in the string you want to hide
or
- use DCPCrypt from Lazarus-CCR

To create feature limited applications you can use OnGuard from Lazarus-CCR

Denis Kozlov

2014-07-16 12:21

reporter   ~0076239

@_Gábor

I am aware of use of cryptography, DCPCrypt and OnGuard, but their use is not relevant for this topic.

Here I am talking about the automatic insertion of project build date at compile time, but as integer tokens instead of string.

Péter Gábor

2014-07-16 17:50

reporter   ~0076244

Last edited: 2014-07-16 17:51

View 2 revisions

You wrote "strings can be easily found and replaced (patched) in the executable, which is a problem when used for some kind of restricted functionality"

I only say that storing raw date/time values and comparing it (or a part of it) with an other constant value is wrong approach to keep control over restricted functionality. It will generate an easily identifiable binary code either you use binary or string constants.

Denis Kozlov

2014-08-04 15:37

reporter   ~0076449

Of course, it will not protect from reverse engineering and patching assembly code, nor it is the purpose of this request.

These variables are needed for convenience, and to protect from dummy search and replace date strings with almost any text editor.

Denis Kozlov

2015-02-10 09:07

reporter   ~0080913

Another alternative is to add includes in native TDateTime format (Double type), this would be much cleaner.

For example: {$I %TDate%}, {$I %TTime%}, {$I %TDateTime%}
Or: {$I %DateNative%}, {$I %TimeNative%}, {$I %DateTimeNative%}

Denis Kozlov

2016-01-09 20:03

reporter  

compiler-include-datetime.patch (1,240 bytes)   
Index: compiler/globals.pas
===================================================================
--- compiler/globals.pas	(revision 32893)
+++ compiler/globals.pas	(working copy)
@@ -509,6 +509,7 @@
 
     function getdatestr:string;
     function gettimestr:string;
+    function getdatetimerawstr:string;
     function filetimestring( t : longint) : string;
     function getrealtime : real;
 
@@ -770,6 +771,10 @@
         getdatestr:=L0(st.Year)+'/'+L0(st.Month)+'/'+L0(st.Day);
       end;
 
+   function getdatetimerawstr:string;
+   begin
+     getdatetimerawstr := FloatToStr(Now);
+   end;
 
    function  filetimestring( t : longint) : string;
    {
Index: compiler/scanner.pas
===================================================================
--- compiler/scanner.pas	(revision 32893)
+++ compiler/scanner.pas	(working copy)
@@ -2427,6 +2427,11 @@
                hs:=gettimestr;
              'DATE':
                hs:=getdatestr;
+             'DATETIME':
+               begin
+                 hs:=getdatetimerawstr;
+                 macroIsString:=false;
+               end;
              'FILE':
                hs:=current_module.sourcefiles.get_file_name(current_filepos.fileindex);
              'LINE':

Denis Kozlov

2016-01-09 20:08

reporter   ~0088750

Added patch to add support for {$I %DATETIME%} directive.

This is a simplest implementation which substitutes %DATETIME% with current date/time in native floating point form.

Now the following is possible:

const
  T = {$I %DATETIME%};
begin
  WriteLn(DateTimeToStr(T));
end.

Denis Kozlov

2016-03-03 11:31

reporter  

compiler-include-timestamp.patch (1,380 bytes)   
Index: compiler/globals.pas
===================================================================
--- compiler/globals.pas	(revision 33143)
+++ compiler/globals.pas	(working copy)
@@ -523,6 +523,7 @@
 
     function getdatestr:string;
     function gettimestr:string;
+    function gettimestampstr: string;
     function filetimestring( t : longint) : string;
     function getrealtime : real;
 
@@ -785,6 +786,13 @@
         getdatestr:=L0(st.Year)+'/'+L0(st.Month)+'/'+L0(st.Day);
       end;
 
+   function gettimestampstr: string;
+   {
+     get the current datetime as a timestamp, i.e. number of MSecs since 1/1/0001
+   }
+     begin
+       gettimestampstr := IntToStr(Round(TimeStampToMSecs(DateTimeToTimeStamp(Now))));
+     end;
 
    function  filetimestring( t : longint) : string;
    {
Index: compiler/scanner.pas
===================================================================
--- compiler/scanner.pas	(revision 33143)
+++ compiler/scanner.pas	(working copy)
@@ -2427,6 +2427,11 @@
                hs:=gettimestr;
              'DATE':
                hs:=getdatestr;
+             'TIMESTAMP':
+               begin
+                 hs:=gettimestampstr;
+                 macroIsString:=false;
+               end;
              'FILE':
                hs:=current_module.sourcefiles.get_file_name(current_filepos.fileindex);
              'LINE':

Denis Kozlov

2016-03-03 11:36

reporter   ~0090586

I've attached an alternative implementation which adds {$I %TIMESTAMP%} directive.

%TIMESTAMP% represents the current datetime as an integer timestamp, i.e. number of MSecs since 1/1/0001, similar to TTimeStamp type.

Now the following is possible:

uses
  SysUtils;
const
  BuildTimestamp = {$I %TIMESTAMP%};
begin
  WriteLn('Timestamp: ', BuildTimestamp);
  WriteLn('DateTime: ', DateTimeToStr(
    TimeStampToDateTime(MSecsToTimeStamp(BuildTimestamp))));
end.

Michael Van Canneyt

2016-03-04 15:04

administrator   ~0090636

The latter will most likely not make it for the same reason as the original request implementing encoding as TDateTime: it is a specific encoding.

The separate parts are better insofar that no assumption is made on a particular form of encoding. Just integers with well-known meanings.

Denis Kozlov

2016-03-07 15:10

reporter   ~0090729

I think I have finally found a solution which will address all issues with previous attempts, specifically, avoiding use of date/time encoding and floating point values.

I've attached a patch which adds the originally proposed date/time tokens:
%DATEYEAR%, %DATEMONTH%, %DATEDAY%, %TIMEHOUR%, %TIMEMINUTE%, %TIMESECOND%

These are inserted as integers, so no assumptions are made on date/time encoding. They are also bound to a fixed starting time of the compile operation, so they always represent a single fixed point in time, unlike %DATE% and %TIME% includes which suffer from a race condition.

Now the following is possible:

uses
  SysUtils, DateUtils;
const
  Year = {$I %DATEYEAR%};
  Month = {$I %DATEMONTH%};
  Day = {$I %DATEDAY%};
  Hour = {$I %TIMEHOUR%};
  Minute = {$I %TIMEMINUTE%};
  Second = {$I %TIMESECOND%};
var
  Date, Time, DateTime: TDateTime;
begin
  Date := EncodeDate(Year, Month, Day);
  Time := EncodeTime(Hour, Minute, Second, 0);
  DateTime := ComposeDateTime(Date, Time);
  WriteLn('Built at: ', DateTimeToStr(DateTime));
  WriteLn('Time ago: ', SecondsBetween(DateTime, Now), ' seconds');
end.

Denis Kozlov

2016-03-07 15:11

reporter  

compiler-include-datetime-tokens.patch (3,068 bytes)   
Index: compiler/compiler.pas
===================================================================
--- compiler/compiler.pas	(revision 33199)
+++ compiler/compiler.pas	(working copy)
@@ -248,7 +248,8 @@
        SetExceptionMask([exInvalidOp, exDenormalized, exZeroDivide,
                          exOverflow, exUnderflow, exPrecision]);
 
-       starttime:=getrealtime;
+       GetLocalTime(startsystime);
+       starttime := getrealtime(startsystime);
 
        { Initialize the compiler }
        InitCompiler(cmd);
Index: compiler/globals.pas
===================================================================
--- compiler/globals.pas	(revision 33199)
+++ compiler/globals.pas	(working copy)
@@ -520,10 +520,12 @@
 
     var
       starttime  : real;
+      startsystime : TSystemTime;
 
     function getdatestr:string;
     function gettimestr:string;
     function filetimestring( t : longint) : string;
+    function getrealtime(const st: TSystemTime) : real;
     function getrealtime : real;
 
     procedure DefaultReplacements(var s:ansistring);
@@ -807,6 +809,10 @@
        Result := L0(Year)+'/'+L0(Month)+'/'+L0(Day)+' '+L0(Hour)+':'+L0(min)+':'+L0(sec);
      end;
 
+   function getrealtime(const st: TSystemTime) : real;
+     begin
+       result := st.Hour*3600.0 + st.Minute*60.0 + st.Second + st.MilliSecond/1000.0;
+     end;
 
    function getrealtime : real;
      var
@@ -813,7 +819,7 @@
        st:TSystemTime;
      begin
        GetLocalTime(st);
-       result:=st.Hour*3600.0+st.Minute*60.0+st.Second+st.MilliSecond/1000.0;
+       result:=getrealtime(st);
      end;
 
 {****************************************************************************
Index: compiler/scanner.pas
===================================================================
--- compiler/scanner.pas	(revision 33199)
+++ compiler/scanner.pas	(working copy)
@@ -2427,6 +2427,36 @@
                hs:=gettimestr;
              'DATE':
                hs:=getdatestr;
+             'DATEYEAR':
+               begin
+                 hs:=tostr(startsystime.Year);
+                 macroIsString:=false;
+               end;
+             'DATEMONTH':
+               begin
+                 hs:=tostr(startsystime.Month);
+                 macroIsString:=false;
+               end;
+             'DATEDAY':
+               begin
+                 hs:=tostr(startsystime.Day);
+                 macroIsString:=false;
+               end;
+             'TIMEHOUR':
+               begin
+                 hs:=tostr(startsystime.Hour);
+                 macroIsString:=false;
+               end;
+             'TIMEMINUTE':
+               begin
+                 hs:=tostr(startsystime.Minute);
+                 macroIsString:=false;
+               end;
+             'TIMESECOND':
+               begin
+                 hs:=tostr(startsystime.Second);
+                 macroIsString:=false;
+               end;
              'FILE':
                hs:=current_module.sourcefiles.get_file_name(current_filepos.fileindex);
              'LINE':

Michael Van Canneyt

2016-03-07 15:15

administrator   ~0090731

For me, this is definitely OK to include !

Denis Kozlov

2016-04-12 16:16

reporter   ~0091977

Anyone interested in committing this?

Denis Kozlov

2017-05-31 12:02

reporter   ~0100740

Is it possible to apply this change?

> compiler-include-datetime-tokens.patch [^] (3,068 bytes) 2016-03-07

Just to summarize, it captures build date/time and provides atomic access to individual build date/time components (year, month, day, hour, min, sec) as integers via $I directive.

Unlike existing {$I %DATE%} and {$I %TIME%}, which return formatted strings, suffer from a race condition, and insert current date/time as opposed to the start of the building process.

Florian

2018-02-24 13:52

administrator   ~0106564

Thanks, finally applied.

Issue History

Date Modified Username Field Change
2014-07-12 17:19 Denis Kozlov New Issue
2014-07-12 17:20 Denis Kozlov Tag Attached: BUILD
2014-07-12 17:20 Denis Kozlov Tag Attached: DATE
2014-07-12 17:20 Denis Kozlov Tag Attached: INCLUDE
2014-07-12 17:20 Denis Kozlov Tag Attached: TIME
2014-07-12 17:21 Denis Kozlov Tag Attached: design-time
2014-07-12 17:21 Denis Kozlov Tag Attached: Invalidate
2014-07-12 17:21 Denis Kozlov Tag Detached: design-time
2014-07-12 17:21 Denis Kozlov Tag Detached: Invalidate
2014-07-12 17:23 Denis Kozlov Note Added: 0076198
2014-07-12 20:04 Péter Gábor Note Added: 0076200
2014-07-12 20:06 Péter Gábor Note Edited: 0076200 View Revisions
2014-07-16 12:21 Denis Kozlov Note Added: 0076239
2014-07-16 17:50 Péter Gábor Note Added: 0076244
2014-07-16 17:51 Péter Gábor Note Edited: 0076244 View Revisions
2014-08-04 15:37 Denis Kozlov Note Added: 0076449
2015-02-10 09:07 Denis Kozlov Note Added: 0080913
2016-01-09 20:03 Denis Kozlov File Added: compiler-include-datetime.patch
2016-01-09 20:08 Denis Kozlov Note Added: 0088750
2016-01-09 20:08 Denis Kozlov Tag Detached: DATE
2016-01-09 20:08 Denis Kozlov Tag Detached: BUILD
2016-01-09 20:08 Denis Kozlov Tag Detached: TIME
2016-01-09 20:08 Denis Kozlov Tag Attached: patch
2016-03-03 11:31 Denis Kozlov File Added: compiler-include-timestamp.patch
2016-03-03 11:36 Denis Kozlov Note Added: 0090586
2016-03-04 15:04 Michael Van Canneyt Note Added: 0090636
2016-03-07 15:10 Denis Kozlov Note Added: 0090729
2016-03-07 15:11 Denis Kozlov File Added: compiler-include-datetime-tokens.patch
2016-03-07 15:15 Michael Van Canneyt Note Added: 0090731
2016-04-12 16:16 Denis Kozlov Note Added: 0091977
2017-05-31 12:02 Denis Kozlov Note Added: 0100740
2018-02-24 13:52 Florian Fixed in Revision => 38329
2018-02-24 13:52 Florian Note Added: 0106564
2018-02-24 13:52 Florian Status new => resolved
2018-02-24 13:52 Florian Fixed in Version => 3.1.1
2018-02-24 13:52 Florian Resolution open => fixed
2018-02-24 13:52 Florian Assigned To => Florian