The Shmoo
The Shmoo

Reputation: 478

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

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

Upvotes: 3

Views: 1716

Answers (2)

Howard Hinnant
Howard Hinnant

Reputation: 218750

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.

Upvotes: -1

Alan Birtles
Alan Birtles

Reputation: 36389

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).

Upvotes: 5

Related Questions