3

I have a requirement where I have to convert given string in date time format to milliseconds from epoch. In Javascript there is date to time conversion api but in c++ I couldn't find anything as such.

Input would look like '2016-Mar-15 09:23:58.665068'

output should be in milliseconds say 14520000785.

I have tried looking into boost but still couldn't find(or understand) how to do? Also, going through google I find the other way round i.e. converting milliseconds to date format but not what I require nor any helpful post for same.

Any help will be much appreciated.

Galimov Albert
  • 7,269
  • 1
  • 24
  • 50
harry
  • 105
  • 3
  • 13

2 Answers2

3

Using only standard library features:

#include <ctime>
#include <chrono>
#include <iostream>

int main()
{
    std::tm tm = {};
    const char* snext = ::strptime("2016-Mar-15 09:23:58.665068", "%Y-%b-%d %H:%M:%S", &tm);
    auto time_point = std::chrono::system_clock::from_time_t(std::mktime(&tm));
    long long  duration_ms = time_point.time_since_epoch() / std::chrono::milliseconds(1) + std::atof(snext) * 1000.0f;
    std::cout << duration_ms << std::endl;
}

Prints: 1458033838665

See std::chrono::system_clock::now and std::chrono::milliseconds.

YSC
  • 38,212
  • 9
  • 96
  • 149
  • 1
    My requirement is to get time in milliseconds for given date in string format ( '2016-Mar-15 09:23:58.665068') not for current time from epoch. I believe your code will give time from epoch till now. – harry Mar 16 '16 at 14:14
  • I'm curious why our outcomes don't match. They should right? – sehe Mar 16 '16 at 14:27
  • @sehe they do now. – YSC Mar 16 '16 at 14:28
  • Wait. You're having to manually factor in the fractional seconds? That's not very elegant. It does work of course. Is the epoch of system_clock guaranteed to be 19700101? ISTR those aren't specified, at least not for all (commonly used) chrono clocks – sehe Mar 16 '16 at 14:31
  • @sehe I found nothing in the POSIX functions to parse fractional seconds, so yes: one has to parse it manually. That's why the Boost solution is better. I'm not sure if the epoch is specified to be 1970-01-01T00:00:00+00:00 (I'd say it is), my solution doesn't depend on it though, so who cares? – YSC Mar 16 '16 at 14:35
  • @YSC Huh. Your solution depends on it 100%. `time_since_epoch` would be different if the epoch is boot time, or 1900-Jan-01 – sehe Mar 16 '16 at 14:38
  • if we multiply time_t (o/p of mktime(&tm) function ) with 1000 we will get duration in milliseconds. is there any specific reason for using Chrono functionality to convert it in milliseconds ?? – Vishal Gupta Feb 24 '17 at 13:01
  • @user3386918 Nothing specified `time_t` to be the number of seconds from Epoch. [From cppreference.com](http://en.cppreference.com/w/cpp/chrono/c/time_t): "_Although not defined, [time_t] is almost always an integral value holding the number of seconds (not counting leap seconds) since 00:00, Jan 1 1970 UTC, corresponding to POSIX time._" – YSC Feb 24 '17 at 13:11
  • but from this link :-https://en.wikibooks.org/wiki/C_Programming/C_Reference/time.h/time_t Unix and POSIX-compliant systems implement time_t as an integer or real-floating type [1] (typically a 32- or 64-bit integer) which represents the number of seconds since the start of the Unix epoch: midnight UTC of January 1, 1970 (not counting leap seconds). – Vishal Gupta Mar 01 '17 at 10:00
  • @user3386918 This is the difference between specified behaviour and implemented behaviour. You cannot rely on the later, but sometimes the former is not enough. Anyway, here it is thanks to `std::chrono`. This is why I didn't simply multiply the `time_t` by 1000. – YSC Mar 01 '17 at 10:07
2

Most straightforward would be to just spell it out:

auto pt = boost::lexical_cast<ptime>("2016-Mar-15 09:23:58.665068");
std::cout << (pt - ptime { {1970,0,0}, {} }).total_milliseconds();

Live On Coliru

#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time/posix_time/posix_time_io.hpp>
#include <boost/date_time.hpp>
#include <sstream>

int main() {
    using boost::posix_time::ptime;

    ptime pt;
    { 
        std::istringstream iss("2016-Mar-15 09:23:58.665068");
        auto* f = new boost::posix_time::time_input_facet("%Y-%b-%d %H:%M:%S%f");

        std::locale loc(std::locale(""), f);
        iss.imbue(loc);
        iss >> pt;
    }

    std::cout << pt << " " << (pt - ptime{{1970,1,1},{}}).total_milliseconds();
}

Prints

2016-Mar-15 09:23:58.665068 1458033838665

Of course, extract the parsing in a helper function. Keep the locale around for reuse etc.

sehe
  • 374,641
  • 47
  • 450
  • 633
  • When i use your given code, it gives me below error: 2016-Mar-16 13:41:07.123639 Day of month value is out of range 1..31 – harry Mar 16 '16 at 14:10
  • You have to cater for the input format - apparently short month names aren't the default (at least not on our systems). Added [a live sample](http://coliru.stacked-crooked.com/a/a21c0f6987da112e) – sehe Mar 16 '16 at 14:22
  • Ahan !! I was about to post same . :) Thanks a lot for the solution. – harry Mar 16 '16 at 14:25