How can I write a C++ function which takes a long long
value representing a VMS timestamp and returns the corresponding time_t
value, assuming the conversion yields a valid time_t
? (I'll be parsing binary data sent over network on a commodity CentOS server, if that makes any differences.)
I've had a look into a document titled "Why Is Wednesday November 17, 1858 The Base Time For VAX/VMS" but I don't think I can write a correct implementation without testing with actual data which I don't have at hand right now, unfortunately.
If I'm not mistaken, it should be a simple arithmetic in this form:
time_t vmsTimeToTimeT(long long v) {
return v/10'000'000 - OFFSET;
}
Could somebody tell me what value to put into OFFSET
?
Things I'm concerned about:
I tried to compute it by myself with the help from Boost.DateTime, only to get a mysterious negative value...
int main() {
boost::posix_time::ptime x(
boost::gregorian::date(1858, boost::gregorian::Nov, 17),
boost::posix_time::time_duration(0, 0, 0) );
boost::posix_time::ptime y(
boost::gregorian::date(1970, boost::gregorian::Jan, 1),
boost::posix_time::time_duration(0, 0, 0) );
std::cout << (y - x).total_seconds() << std::endl;
std::cout << (y > x ? "y is after x" : "y is before x") << std::endl;
}
-788250496
y is after x
I used Boost 1.60 for it:
The current implementation supports dates in the range 1400-Jan-01 to 9999-Dec-31.
Crap, sizeof(total_seconds())
was 4, dispite what the document says
So I got 3506716800 from
auto diff = y - x;
std::cout << diff.ticks() / diff.ticks_per_second() << std::endl;
which doesn't look too wrong but... who can assure this is really correct?
Wow, you guys make it all appear to be so difficult with libraries and all. So you read up on November-17 1858 and found out that VMS stores the time as 100nS 'clunks' since that date. Right?
Unix times are Seconds (or microseconds) since 1-jan-1970. Right?
So all you need to do is to subtract the OpenVMS time value 'offset' for 1-jan-1970 from the reported OpenVMS times ad divide by 10,000,000 (seconds) or 10 (microseconds). You only need to find that value once using a trivial OpenVMS program. Below I did not even use a dedicated program, just used the OpenVMS interactive debugger running a random executable program:
$ run tmp/debug
DBG> set rad hex
DBG> dep/date 10000 = "01-JAN-1970 00:00:00" ! Local time
DBG> examin/quad 10000
TMP\main: 007C95674C3DA5C0
DBG> examin/quad/dec 10000
TMP\main: 35067168005400000
So there is you offset, both in HEX and DECIMAL to use as you see fit.
In the simplest form you pre-divide the incoming OpenVMS time by 10,000,000 and subtract 3506716800 (decimal) to get Epoch seconds. Be sure to keep the math, including the subtract to long-long int's
hth, Hein.