1

Consider the input: 2014-04-14T16:28:07.023 (no time-zone, milliseconds precision) I parsed it and I have the parts as numbers.

  • The input is always considered to be in UTC
  • I want to display it as local time
  • I want to keep the milliseconds precision when displaying

I have C++98 and boost 1.51.

I inspected high_resolution_clock and system_clock, but was unable to produce the final plot for the problem yet.

Notinlist
  • 16,144
  • 10
  • 57
  • 99
  • 1
    Does the accepted answer [here](http://stackoverflow.com/questions/3786201/parsing-of-date-time-from-string-boost?rq=1) answer your question? – Oliver Charlesworth Apr 13 '14 at 14:42
  • No milliseconds there. I also don't see utc-localtime conversion. But still might lead somewhere... – Notinlist Apr 13 '14 at 14:44
  • What do you mean by classic c++? Do you mean C++99 as in 1999 the year of the standard as apposed to the classic C++11 as in 2011. For sure nothing related to your question has changes in the last 20 years of c++. So your not using boost. I would start by learning how to process text. You could probably open up the boost code and take a look at what they have done. Even if your not going to use it. – Dan Apr 13 '14 at 14:49
  • I know how to process text, I should not have mentioned parsing. Let's start from the point where I have the parts as numbers. I have problem with choosing a good combination of utilities and methods for the rest. – Notinlist Apr 13 '14 at 14:54
  • @Dan By the way, I did not say I am using boost. I told that I have it. Meaning that I welcome answers which are using boost. – Notinlist Apr 13 '14 at 15:02
  • @Notinlist Why not increment/decrement the obtained hour and take care of carry digits. – user877329 Apr 13 '14 at 15:05
  • 1
    C++ has a C++98 standard from 1998, and a 2003 update known as C++03 to fix some bugs in the standard's text, without adding features. (C does have a C99 standard from 1999.) –  Apr 13 '14 at 15:06
  • @user877329 I would have problems at the end of February. I don't want to go on the road where I have to do date handling logic myself. – Notinlist Apr 13 '14 at 15:07
  • How about dropping the milliseconds (save it in a separate variable), do the conversion, then add the milliseconds back? Your question seems as if you have a working answer already, except for the milliseconds part, but milliseconds don't affect the rest of the result. –  Apr 13 '14 at 15:08
  • @hvd Yes. I wanted to simply say that I don't use C++11, but the one before that. It could be understood from "Classic C++ (not C++11)", but then it was not enough, so I started to refine it and made a mistake: wrote 99 instead of 98. Much ado about nothing. – Notinlist Apr 13 '14 at 15:13
  • @hvd Good idea. Handling milliseconds separately would mean that I can "avoid" boost entirely in regards of this feature because I could use `gmtime` and `localtime`. But on the other hand I already have boost in my project. I also posted an answer. I'm not yet confident about which way I will choose. – Notinlist Apr 13 '14 at 19:22
  • @hvd Your idea made me think harder. With the utility I'm writing I will not do any kind of timezone conversion nor enforcing of any particular variant of date-time facility. I will leave the parts as numbers and expose it to the higher levels like that. On that higher level I will use your method or mine (c_local_adjustor) but that does not matter for now. I would like to value your idea, please post an answer! – Notinlist Apr 13 '14 at 19:40

2 Answers2

1

I have a solution which will be sufficient for me, but I don't know if it is the best approach in general or not. I'm about to use boost::posix_time::ptime and boost::date_time's c_local_adjustor:

#include <iostream>
#include <boost/date_time.hpp>
#include <boost/date_time/c_local_time_adjustor.hpp>

int main()
{
  typedef boost::posix_time::ptime TP;
  typedef boost::date_time::c_local_adjustor<TP> local_adj;

  TP tUTC(boost::gregorian::date(2014,4,13),boost::posix_time::millisec(23));
  TP tLocal(local_adj::utc_to_local(tUTC));

  std::cout << boost::posix_time::to_simple_string(tUTC) << std::endl;
  std::cout << boost::posix_time::to_simple_string(tLocal) << std::endl;

  return 0;
}

Will print:

2014-Apr-13 00:00:00.023000
2014-Apr-13 02:00:00.023000

I did'nt use using namespace to show where is what. The ptime class has accessors to every detail I need. The c_local_adjustor does not have local_to_utc method, but it can be worked around.

(I got nowhere with chrono, I was able to do only circles in the documentation.)

Notinlist
  • 16,144
  • 10
  • 57
  • 99
  • +1 This is what I wanted to write up when my system went down. Chrono is "useless" because it is (deliberately) calendar-agnostic. – sehe Apr 13 '14 at 19:50
1

As requested in the comments to post as an answer, here is how it can be done without Boost:

#include <iostream>
#include <stdlib.h>
#include <time.h>

int main() {
  int year, month, day, hour, minute, second, millisecond;
  if (std::cin >> year >> month >> day >> hour >> minute >> second >> millisecond) {
    struct tm utc;
    utc.tm_year = year;
    utc.tm_mon = month;
    utc.tm_mday = day;
    utc.tm_hour = hour;
    utc.tm_min = minute;
    utc.tm_sec = second;
    utc.tm_isdst = 0;

    time_t time = timegm(&utc);
    if (time == (time_t) -1)
      abort();

    struct tm *local = localtime(&time);
    if (localtime == NULL)
      abort();

    year = local->tm_year;
    month = local->tm_mon;
    day = local->tm_mday;
    hour = local->tm_hour;
    minute = local->tm_min;
    second = local->tm_sec;

    std::cout << year << ' ' << month << ' ' << day << ' ' << hour << ' ' << minute << ' ' << second << ' ' << millisecond << std::endl;
  }
}

Note that the millisecond variable is read from input, and written to output, without any modification.

This uses the non-standard timegm function, but the documentation for that function contains a more portable implementation that you could include, if you want.