Checking two TDateTime variables - c++

I am using C++ Builder and have the following question:
I am wanting to detect if a date/time is later than another date/time, and by how much.
Here is my current code:
TDateTime testFirstDate("11/09/2012");
TDateTime testFirstTime("14:00");
TDateTime testSecondDate("12/09/2012");
TDateTime testSecondTime("16:00");
TDateTime testCombined1 = testFirstDate + testFirstTime;
TDateTime testCombined2 = testSecondDate + testSecondTime;
TDateTime testDateDifference = testSecondDate - testFirstDate;
std::cout << testDateDifference;
In the above example, the following gets printed out: 31/12/1899
The difference between the two values is only 1 day. Why is: 31/12/1899 being printed, and not something like: 1?

The difference is 1 day, 22 hours.
TDateTime in Delphi and C++ Builder is a double, where the whole portion (the part to the left of the decimal point) stores the number of days since a base date of December 30, 1899 (see note below), and the fractional portion (the part to the right of the decimal point) is the time.
The 1899 you're seeing after the subtraction is because you have less than a full day, and therefore the whole portion of the number is zero, and as I mentioned a date of zero is the base date in December, 1899. Since your date is 1 day later than that base date (when represented as a TDateTime, the date is interpreted as December 31, 1899.
The time portion for 22 hours is approximately 0.9167 (actually, 0.916666666666667), which represents 22/24ths of a day.
Delphi's runtime library contains a unit called DateUtils, which IIRC is available to C++ Builder as well (there's a header file for it), which contains functions which may help you, like DaysBetween that you may find useful. There are C++ examples of it's use available here.
As far as equality (one date being after the other), you can use the standard >, <, >=, <=, !=, and == operators. I've demonstrated this below as well.
Here's a quick example (in Delphi, as I don't have C++ Builder installed on this machine) that might explain:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, DateUtils;
var
StartDate, EndDate, Diff: TDateTime;
begin
try
{ TODO -oUser -cConsole Main : Insert code here }
// Base date, formatted in US date format
WriteLn('BaseDate: ', FormatDateTime('mm/dd/yyyy hh:nn:ss', 0));
StartDate := EncodeDateTime(2012, 9, 11, 14, 0, 0, 0);
EndDate := EncodeDateTime(2012, 9, 12, 16, 0, 0, 0);
Diff := EndDate - StartDate;
WriteLn('Diff as String: ', DateToStr(Diff));
WriteLn('Diff as Double: ', Diff);
WriteLn('DaysBetween: ', DaysBetween(EndDate, StartDate));
// Equality
WriteLn('EndDate after StartDate`, EndDate > StartDate);
RegEx.Free;
ReadLn;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
This produces this output:
BaseDate: 12/30/1899 00:00:00
Diff as String: 12/31/1899
Diff as Double: 1.08333333332848E+0000
DaysBetween: 1
EndDate after StartDate: TRUE
NOTE: The base date was established by Microsoft for COM, and for compatibility reasons Delphi/C++ Builder adopted it.

You can use your normal -, +, <, >,== and = with TDateTime.
So to see if one date is ahead of another, you can, for example, subtract them and see if the result is greater or lesser than zero.

Related

Convert Unix Timestamp to Datetime in Power BI

Good morning Stack Overflow,
I have a question, I do have a list of Timestamp, I believe there are Unix Time Stamp, I'd like to convert to datetime on PBI, but I'm getting an error, using the following formula :' #datetime(1957,1,1,0,0,0) + #duration(0,0,0,[Timestamp]) ' , Timestamp is the column that I'd like to convert.
Below a sample list of the data :
Is there a way to fix this issue?
You're close but you need to remember that Unix timestamps are recorded in milliseconds since 1970, not seconds since 1957. Try this instead
#datetime(1970, 1, 1, 0, 0, 0) + #duration(0, 0, 0, [Timestamp]/1000)
Make sure the column is a datetime data type.

Convert UTC timestamp to Simple binary encoded message

I am trying to convert UTC timestamp to simple binary encoded message.
Would like to achieve what is mentioned in example here.
Binary Encoding Example
The following timestamp:
UTC timestamp 14:17:22 Friday, October 4, 2024
is expressed in binary code (nanoseconds since Unix epoch) this way:
007420bf8838fb17 (8 bytes in nanoseconds since Unix epoch synced to a master clock to microsecond accuracy.
What I have done so far is,
import struct
from datetime import datetime
dt = datetime(2024, 10, 4, 14, 17, 22, 0)
timestamp = (dt - datetime(1970, 1, 1)).total_seconds() * 1000000000
utc_timestamp = struct.pack('d', timestamp)
Output I see on CLI is '\xf4\x02\x82\xa1E\xfb\xb7C' but, as per example in shared link, expected is 007420bf8838fb17
TL;DR: I think there's either an error in linked example, or the description of the representation is incorrect or incomplete.
import struct
from datetime import datetime, timedelta, timezone
utc_tz = timezone(timedelta(0))
t = datetime(2024, 10, 4, 14, 17, 22, 0, utc_tz)
nanos = int(t.timestamp()) * 1_000_000_000
print(hex(timestamp))
This gives the result of 0x17fb45a18202f400, not the quoted 0x17fb3888bf297400 (as presented, I think it's a little-endian byte string, so this value has the order of bytes reversed).
The quoted answer, converted to decimal seconds (dividing by 1_000_000_000) is 1728037042.0005898. That value obviously has a sub-second quantity, which the source datetime does NOT have.
Decoding the seconds component of the quoted answer:
import time
answer = 0x17fb3888bf297400
secs = int(answer / 1_000_000_000)
print(time.gmtime(secs))
gives:
time.struct_time(tm_year=2024, tm_mon=10, tm_mday=4, tm_hour=10, tm_min=17, tm_sec=22, tm_wday=4, tm_yday=278, tm_isdst=0)
which looks almost correct, save that the hour component is 4 hours earlier. So ... my guess is that this is actually a US/Eastern timestamp (not UTC), and contains a sub-second component of 5898ns, and the example is misleading.
If the schema you're using is encoding timestamps as a 64-bit number of nanoseconds since the Unix epoch (midnight 1 January 1970), then I think your example code has only one error: use format <q (or <Q) rather than d, and you'll get a little-endian 64-bit integer as required. You will also need to convert the timestamp to an integer to have struct.pack() accept it.

Matching diverse dates in Openrefine

I am trying to use the value.match command in OpenRefine 2.6 for splitting the information presents in a column into (at least) 2 columns.
The data are, however, quite messed up.
I have sometimes full dates:
May 30, 1949
Sometimes full dates are combined with other dates and attributes:
May 30, 1949, published 1979
May 30, 1949 and 1951, published 1979
May 30, 1949, printed 1980
May 30, 1949, print executed 1988
May 30, 1949, prints executed 1988
published 1940
Sometimes you have timespan:
1905-05 OR 1905-1906
Sometimes only the year
1905
Sometimes year with attributes
August or September 1908
Doesn't seems to follow any specific schema or order.
I would like to extract (at least)ca start and end date year, in order to have two columns:
-----------------------
|start_date | end_date|
|1905 | 1906 |
-----------------------
without the rest of the attributes.
I can find the last date using
value.match(/.*(\d{4}).*?/)[0]
and the first one with
value.match(/.*^(\d{4}).*?/)[0]
but I got some trouble with the two formulas.
The latter cannot match anything in case of:
May 30, 1949 and 1951, published 1979
while in the case of:
Paris, winter 1911-12
The latter formula cannot match anything and the former formula match 1911
Anyone know how I can resolve the problem?
I would need a solution that take the first date as start_date and final date as end_date, or better (don't know if it is possible) earliest date as start_date and latest date as end_date.
Moreover, I would be glad to have some clue about how to extract other information, such as
if published or printed or executed is present in the text -> copy date to a new column name “execution”.
should be something like create a new column
if(value.match("string1|string2|string3" + (\d{4}), "perform the operation", do nothing)
value.match() is a very useful but sometimes tricky function. To extract a pattern from a text, I prefer to use Python/Jython's regular expressions :
import re
pattern = re.compile(r"\d{4}")
return pattern.findall(value)
From there, you can create a string with all the years concatenated:
return ",".join(pattern.findall(value))
Or select only the first:
return pattern.findall(value)[0]
Or the last:
return pattern.findall(value)[-1]
etc.
Same thing for your sub-question:
import re
pattern = re.compile(r"(published|printed|executed)\s+(\d+)")
return pattern.findall(value)[0][1]
Or :
import re
pattern = re.compile(r"(published|printed|executed)\s+(\d+)")
m = re.search(pattern, value)
return m.group(2)
Example:
Here is a regex which will extract start_date and end_date in named groups :
If there is only one date, then it consider it's the start_date :
((?<start_date>\d{4}).*?)?(?<end_date>\d{4}|(?<=-)\d{2})?$
Demo

Convert string to date object in Visual Studio

Need to convert a string, which stores the date in format like such: "Apr 23 2014 12:39:17" to a number or an object; Working with visual studio in a MS-specific environment.
In C++ is there a easy to use function that can achieve this?
I am doing this in order to do a comparison between the string date and now().
Thanks.
Here is the solution I found for my problem.
To clarify: A string representation of a date needed to be converted into some sort of date object, so that I could find the difference between 2 dates.
This works on MS VisualStudio2010 & uses the microsoft classes. (Basically; It won't work on a unix box!).
// Create 2 COleDateTime objects:
COleDateTime DateTime1;
COleDateTime DateTime2;
// 'Get' 2 string dates:
BSTR time1 = L"Apr 24 2014 09:20:20";
BSTR time2 = L"Apr 23 2014 12:39:17";
// Parse the string dates into the date objects (See! Its alot easier then I thought!)
DateTime1.ParseDateTime(time1);
DateTime2.ParseDateTime(time2);
// Calculate the time difference with a COleDateTimeSpan Object...
COleDateTimeSpan timeSpan = DateTime2 - DateTime1;
// Create integer with the difference in time in seconds...
CString str = timeSpan.Format(_T("%S"));
int differenceInSeconds = _tstoi(str);
Hope this helps someone!

Check if string is of SortableDateTimePattern format

Is there any way I can easily check if a string conforms to the SortableDateTimePattern ("s"), or do I need to write a regular expression?
I've got a form where users can input a copyright date (as a string), and these are the allowed formats:
Year: YYYY (eg 1997)
Year and month: YYYY-MM (eg 1997-07)
Complete date: YYYY-MM-DD (eg 1997-07-16)
Complete date plus hours and minutes: YYYY-MM-DDThh:mmTZD (eg 1997-07-16T19:20+01:00)
Complete date plus hours, minutes and seconds: YYYY-MM-DDThh:mm:ssTZD (eg 1997-07-16T19:20:30+01:00)
Complete date plus hours, minutes, seconds and a decimal fraction of a second
YYYY-MM-DDThh:mm:ss.sTZD (eg 1997-07-16T19:20:30.45+01:00)
I don't have much experience of writing regular expressions so if there's an easier way of doing it I'd be very grateful!
Not thoroughly tested and hence not foolproof, but the following seems to work:
var regex:RegExp = /(?<=\s|^)\d{4}(-\d{2}(-\d{2}(T\d{2}:\d{2}(:\d{2}(\.\d{2})?)?\+\d{2}:\d{2})?)?)?(?=\s|$)/g;
var test:String = "23 1997 1998-07 1995-07s 1937-04-16 " +
"1970-0716 1993-07-16T19:20+01:01 1979-07-16T19:20+0100 " +
"2997-07-16T19:20:30+01:08 3997-07-16T19:20:30.45+01:00";
var result:Object
while(result = regex.exec(test))
trace(result[0]);
Traced output:
1997
1998-07
1937-04-16
1993-07-16T19:20+01:01
2997-07-16T19:20:30+01:08
3997-07-16T19:20:30.45+01:00
I am using ActionScript here, but the regex should work in most flavors. When implementing it in your language, note that the first and last / are delimiters and the last g stands for global.
I'd split the input field into many (one for year, month, day etc.).
You can use Javscript to advance from one field to the next once full (i.e. once four characters are in the year box, move focus to month) for smoother entry.
You can then validate each field independently and finally construct the complete date string.