c++ccalendartimestampvms

VMS timestamp to POSIX time_t --- Boost.DateTime bug?


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.

Update

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?


Solution

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