c++ get milliseconds since 01/01/0001 00:00:00 - c++

I need a timestamp in a special format for an API call:
Dates are converted to UTC milliseconds elapsed since 12:00:00 midnight, January 1, 0001.
My first assumption was to use:
auto now = std::chrono::system_clock::now();
std::cout << "millisceconds since epoch: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(
now.time_since_epoch()).count()
But of course the output is the time interval from the UNIX epoch
Thu Jan 1 00:00:00 1970
So for a now = "Wed Dec 12 13:30:00 2018" it returns 1544617800000ms.
How do I get the milliseconds elapsed since 12:00:00 midnight, January 1, 0001?
Context OSISoft API
The OSISoft API Documentation for specifying a date range is quite strange
Numeric Range Queries
The previous examples were Range Queries against string fields. Numeric values > can also be searched for with Range Queries.
The only fields that are indexed as numeric fields are the CreationDate and ChangeDate fields for the respective PI Point attributes. To index these fields > add them to the list of PI Point Attributes. This configuration may be viewed > or modified on the Settings page.
These date time values are indexed as numeric values via a conversion: Dates are converted to UTC milliseconds elapsed since 12:00:00 midnight, January 1, 0001.
In the following example query is a request for last changed date equal to or > greater than February 26th, 22:16:50.000 (This is Universal Time). This DateTime, following the aforementioned conversion, would be represented as numeric value: 63655280210000. Therefore the query submitted is:
https://MyServer/piwebapi/search/query?q=changedate:[63655280210000 TO *]
From this documention I have asked this question on how to get the milliseconds elapsed since 12:00:00 midnight, January 1, 0001.
I also linked the Question to PISquare

There is no defined way to calculate:
UTC milliseconds elapsed since 12:00:00 midnight, January 1, 0001.
Judging by the examples they are using the same algorithm as https://www.epochconverter.com/seconds-days-since-y0. To get the same result you can just add 719162 days to the unix epoch:
auto now = std::chrono::system_clock::now();
std::cout << "millisceconds since epoch: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(
now.time_since_epoch() + std::chrono::hours(24 * 719162)).count()
Note c++20 introduces std::chrono::days which you could use instead of 24 hours.
Depending on the resolution of your system clock you may need to cast to milliseconds before adding the offset to avoid overflows (719162 days is more than 2^64 nanoseconds).

This is easy using Howard Hinnant's date/time library:
#include "date/date.h"
#include <iostream>
std::chrono::milliseconds
convert(std::chrono::system_clock::time_point tp)
{
using namespace date;
using namespace std::chrono;
return (floor<milliseconds>(tp) +
(sys_days{1970_y/January/1} - sys_days{1_y/January/1})).time_since_epoch();
}
int
main()
{
using namespace date;
using namespace std::chrono;
std::cout << convert(system_clock::now()) << '\n';
}
convert simply adds the difference between the two epochs to the system_clock::time_point, truncated to milliseconds precision, and extracts the duration to return it as milliseconds.
This program for me just output:
63680221359193ms
The range on milliseconds is plenty big enough to handle this computation, but the range on your system_clock::time_point may not be. Thus it is important to truncate to milliseconds right away as done in the code above to avoid overflow.

Related

Get Number of "Business Seconds" Between Two Unix Timestamps

Given these two timestamps/converted to datetimes:
Start - 1668105400.814 - Thursday, November 10, 2022 12:36 PM
End - 1668444427.195 - Monday, November 14, 2022 10:47 AM
...how can I get the number of seconds, adjusted for "business" days? With this example, you'll see that the start date was a Thursday (Friday was a holiday in Canada), and the end date was a Monday. Taking holidays into account isn't super important here, would be nice, but for simplicity of the solution, it would be cool to subtract 172800 seconds (2 days' worth) from the difference between the End and the Start if it stretches over a weekend.
My dataset looks like this:
type created_at emitted_at
assign 1668105400.814 1668105400.814
archive 1668105400.814 1668444427.195
How I'm currently calculating the number of seconds is in an added custom column with the formula:
_Created_To_Archive_Handle_Time = IF(Front_Email_Stats[type]="archive", ROUND((Front_Email_Stats[emitted_at] - Front_Email_Stats[conversation.created_at]), 1), BLANK())
...where it filters for type of archive only, and then subtracts the archived emitted_at timestamp from its created_at timestamp.
A naive approach would look something like this:
_Created_To_Archive_Handle_Time = IF(Front_Email_Stats[type]="archive", IF(AND(WEEKDAY(Front_Email_Stats[_created_at_datetime_custom_column]) < 7, WEEKDAY(Front_Email_Stats[_emitted_at_datetime_custom_column]) > 1), ROUND((Front_Email_Stats[emitted_at] - Front_Email_Stats[conversation.created_at]), 1) - 172800, ROUND((Front_Email_Stats[emitted_at] - Front_Email_Stats[conversation.created_at]), 1)), BLANK())
...where we filter for archive types only, and then do a simple check if the Start timestamp's day of week is less than Saturday (7 I think?) and the End timestamp's day of week is greater than Sunday (1?), but wondering if there's a more elegant solution.
Use NETWORKDAYS() and then subtract the seconds manually.
https://learn.microsoft.com/en-us/dax/networkdays-dax

How to add chrono::year_month_day to chrono::sys_seconds

Am holding duration's in a year_month_day. Is there a simple way to add the year_month_day duration to a time_point like sys_seconds?
sys_seconds date1 = {};
sys_seconds dat2 = {};
year_month_day calDuration;
date1 = date2 + calDuration; //error: no match for ‘operator+’
This is chrono catching logic bugs for you at compile-time. Adding date2 + calDuration is akin to adding tomorrow + today. It just doesn't make sense. And that's why it is a compile-time error.
What you may mean is that you have durations years, months and days. This is not the same as the similarly named types year, month and day. The plural forms are chrono::durations, just like minutes and nanoseconds. days is 24h. And years and months are the average length of those units in the civil calendar.
Conversely, the singular forms year, month and day are the calendrical components that give a name to a day in the civil calendar, e.g. 2020y, December, and 18d. And it is these singular forms that make up a year_month_day, e.g. 2020y/December/18d.
See this SO answer for a deep-dive on the difference between month and months.
There are multiple ways to add the units years and months to a time_point. See this SO answer for a deep-dive on that topic.

Can Fortran convert "time interval + reference date" into "date" conveniently?

In other languages, there usually occurs a function to calculate the date using the reference date and time interval. For example, in R, if the reference date is 2019/09/01, and the time interval is 2 days, then the calculated date is 2019/09/03. We can use the following date conversion function:
as.Date(2, origin = "2019-09-01")
# [1] "2019-09-03"
I was wondering if Fortran has the similar functions or packages?
The Fortran standard only provides the current date and time up to milliseconds.
call date_and_time ( [ date ] [ , time ] [ , zone ] [ , values ] )
returns the following (with default values blank or -huge(0), as appropriate, when there is no clock).
date is a scalar character variable of length 8 or more. Its first 8 characters are set to the century, year, month, and day in the form ccyymmdd.
time is a scalar character variable of length 10 or more. Its first 10 characters
are set to the time as hours, minutes, seconds, and milliseconds in the form hhmmss.sss.
zone is a scalar character variable of length 5 or more. Its first 5 characters are
set to the difference between local time and UTC (also known as Greenwich Mean Time) in the form Shhmm, corresponding to sign, hours, and minutes. For example, a processor in New York in winter would return the value -0500.
values is a rank-one default integer array of size at least 8 holding the sequence of
values: the year, the month of the year, the day of the month, the **time difference in minutes with respect to UTC, the hour of the day, the minutes of the hour, the seconds of the minute, and the milliseconds of the second.
If you need anything beyond this, you will have to currently write your own functions or, as mentioned in the comments, use one of the existing ones. Among the most prominent that I know of, there is the open-srouce library datetime-fortran here.

Get the current date including milli-seconds

I have to track the current system time including milli-seconds using ColdFusion 11. I am using the Now() function but it outputs the date like this {ts '2017-01-11 06:48:58'}. I need to include the milli-seconds as well. Please let me know.
The milliseconds are there and you can get to them by using the TimeFormat() function of ColdFusion. Here is some sample code showing this:
<cfscript>
currentTime = Now();
writeOutput('<p>' & currentTime & '</p>');
formattedTime = TimeFormat(currentTime,'HH:mm:ss.l');
writeOutput('<p>' & formattedTime & '</p>');
</cfscript>
<!--- which outputs the following --->
{ts '2017-01-11 13:10:03'}
13:10:03.827
The first bit of code show the standard display format that you referenced. The second bit uses the TimeFormat() function to also include the milliseconds using the l mask option.
Here is a gist of that code so you can see it in action - TimeFormat example on trycf.com
There are several formatting options available to you using that function.
Masking characters that determine the format:
h: hours; no leading zero for single-digit hours (12-hour clock)
hh: hours; leading zero for single-digit hours (12-hour clock)
H: hours; no leading zero for single-digit hours (24-hour clock)
HH: hours; leading zero for single-digit hours (24-hour clock)
m: minutes; no leading zero for single-digit minutes
mm: minutes; a leading zero for single-digit minutes
s: seconds; no leading zero for single-digit seconds
ss: seconds; leading zero for single-digit seconds
l or L: milliseconds, with no leading zeros
t: one-character time marker string, such as A or P
tt: multiple-character time marker string, such as AM or PM
short: equivalent to h:mm tt
medium: equivalent to h:mm:ss tt
long: medium followed by three-letter time zone; as in, 2:34:55 PM EST
full: same as long
From the Adobe ColdFusion documentation here
If you still need the date portion of the object then use the DateFormat() function to display that part.

How to properly format a DEVPROP_TYPE_DATE?

I want to format a DEVPROP_TYPE_DATE value. The official documentation says:
"In Windows Vista and later versions of Windows, the DEVPROP_TYPE_DATE property type represents the base-data-type identifier that indicates that the data type is a DOUBLE-typed value that specifies the number of days since December 31, 1899. For example, January 1, 1900, is 1.0; January 2, 1900, is 2.0; and so on."
The DEVPROPERTY structure documentation says:
"DEVPROP_TYPE_DATE - date (DATE)"
So far, so good! But, wait! DEVPROP_TYPE_DATE format is similar, but it is not equal the DATE datatype format:
"The DATE type is implemented using an 8-byte floating-point number. Days are represented by whole number increments starting with 30 December 1899, midnight as time zero. Example: 30 December 1899, midnight is 0.00 and 1 January 1900, midnight is 2.00."
And I found a PDF document saying that:
"DEVPROP_TYPE_DATE - Date value. PropertyBuffer specifies a 64-bit floating-point number representing the number of days (not seconds) since December 31, 1899. For example, January 1, 1900, is 2.0, January 2, 1900, is 3.0, and so on. PropertyBufferSize MUST be set to 8."
It seems to me as a lot of typos, but I'm not sure. I also found that the DATE datatype has a long history and some weirdness. Someone can help me to clarify what is the correct format for a DEVPROP_TYPE_DATE value?
P.S.: I'm working on a B plan to display the value and compare it with the value shown by Device Manager. It's not perfect but close enough.
Have a look at the DateTime.ToOADate() method.
Assuming data is an IntPtr pointing to the bytes of the date:
using System;
using System.Runtime.InteropServices;
var Bytes = new byte[8];
Marshal.Copy(data, Bytes, 0, 8);
var d = BitConverter.ToDouble(Bytes, 0);
var Value = DateTime.FromOADate(d).ToString();