HowardHinnant / date

A date and time library based on the C++11/14/17 <chrono> header
Other
3.16k stars 685 forks source link

Equivalent to std::tm #124

Closed MikeGitb closed 7 years ago

MikeGitb commented 7 years ago

I hope I haven't just overlooked it, but does your library provide some equivalent to the std::tm struct? If not is there a particular reason for it?

HowardHinnant commented 7 years ago

There isn't a direct equivalent to std::tm because this structure is overkill for some applications and insufficient for others. Instead there are a wide variety of calendrical and temporal building blocks to make it easy for you to build what is just right for you.

year_month_day is the analog of {tm_year, tm_mon, tm_mday} but with better syntax. year_month_day excels at year and month oriented arithmetic.

time_of_day<seconds> is the analog of {tm_hour, tm_min, tm_sec}. But that should not be interpreted to mean that time_of_day<seconds> is the way to carry around the time of day. A count of seconds since midnight is arguably superior. Indeed you might want to create your own {year_month_day, seconds} type. Or maybe seconds isn't precise enough for you, so choose milliseconds instead. You can also get a time_of_day<milliseconds> which holds {hours, minutes, seconds, milliseconds} fields.

There is a weekday class that is the analog of tm_wday.

There is no analog of tm_yday, however this quantity is trivial to compute for any y/m/d triple: sys_days{y/m/d} - sys_days{y/jan/1}.

sys_info.save is the analog of tm_isdst. sys_info.save == 0min if Daylight Saving Time is not in effect, otherwise Daylight Saving Time is in effect.

So all the information is there, but presented so that you can mix, match and customize what you need (seconds precision is not presumed to be needed nor sufficient). Additionally there is much more information regarding time zones which is available that std::tm does not support:

Here (https://github.com/HowardHinnant/date/wiki/Examples-and-Recipes#time_point_to_components) is example code for converting to and from a std::tm.

HowardHinnant commented 7 years ago

A recent redesign of the I/O has led to a very tm-like structure that I have not documented:

template <class Duration>
struct fields
{
    year_month_day        ymd{0_y/0/0};
    weekday               wd{7u};
    time_of_day<Duration> tod{};
public:
    // ... constructors

I have not documented it because I don't want to introduce it to the API if it is not necessary. However if it turns out that people do need it, I can commit to it and document it.

jankratochvil commented 7 years ago

I use this project to simulate localtime()+mktime() for multiple timezones in a single process this way. It assumes: const date::time_zone *const date_time_zone(date::locate_zone("TIMEZONENAME"));

localtime(): GMT time_t -> local struct tm

  const auto zoned(date::make_zoned(date_time_zone,date::sys_time<std::chrono::nanoseconds>(std::chrono::system_clock::from_time_t(ts))));
  const time_t tslocal(std::chrono::duration_cast<std::chrono::seconds>(zoned.get_local_time().time_since_epoch()).count());
  struct tm tm;
  struct tm *const tmerr(gmtime_r(&tslocal,&tm));
  assert(tmerr==&tm);
  tm.tm_isdst=-1;

mktime(): local struct tm -> GMT time_t

  const date::year_month_day ymd(date::year(1900+tm.tm_year),date::month(1+tm.tm_mon),date::day(tm.tm_mday));
  const auto zoned(date::make_zoned(date_time_zone,date::local_days(ymd)+std::chrono::seconds((tm.tm_hour*60+tm.tm_min)*60+tm.tm_sec)));
  const time_t tsgmt(std::chrono::duration_cast<std::chrono::seconds>(zoned.get_sys_time().time_since_epoch()).count());
  assert(tsgmt!=-1);
MikeGitb commented 7 years ago

However if it turns out that people do need it, I can commit to it and document it.

Thank you very much. I'll have to experiment with it a bit, but I believe I would very much like to have it as a part of your library. Most importantly for me would be the ability to easily create this directly from a zoned or sys time.