3

Given a time_t or struct timeval, how do I get the timeval or time_t of midnight EST/EDT ( local timezone ) on that day ? As in assuming local timezone is EST/EDT, given a time_t corresponding to say 2010-11-30 08:00:00 EST/EDT, the expected answer is a time_t that corresponds to 2010-11-30 00:00:00 EST/EDT

Attempt 1 ( Incorrect: since it does not handle DST, and assumes EST/EDT is always 5 hours behind UTC ):

time_t RewindToMidnight ( const time_t temp_time_t_ )
{
  return ( (5*3600) + ((( temp_time_t_ - 5*3600 )/86400 ) * 86400) );
}

Attempt 2 ( Incorrect: since it returns a time_t that corresponds to when it was midnight UTC and not EST/EDT, local timezone ):

time_t RewindToMidnight ( const time_t temp_time_t_ )
{
   boost::posix_time::ptime temp_ptime_ = boost::posix_time::from_time_t ( temp_time_t_ );
   boost::gregorian::date temp_date_ = temp_ptime_.date();
   boost::posix_time::ptime temp_ptime_midnight_ ( temp_date_,
                                                   boost::posix_time::time_duration ( 0, 0, 0 ) );
   return to_time_t ( temp_ptime_midnight_ );
}

time_t to_time_t ( const boost::posix_time::ptime & temp_ptime_ )
{
   boost::posix_time::ptime temp_epoch_ptime_(boost::gregorian::date(1970,1,1));
   boost::posix_time::time_duration::sec_type temp_sec_type_ = ( temp_ptime_ - temp_epoch_ptime_ ).total_seconds();
   return time_t ( temp_sec_type_ );
}

I feel there should be a solution involving (i) struct tm, mktime or (ii) boost::local_date_time perhaps ?

Humble Debugger
  • 4,439
  • 11
  • 39
  • 56

3 Answers3

5

As time_t is time in seconds since the Epoch (00:00:00 UTC, January 1, 1970), you just need to get rid of the seconds of the day. There are 86400 seconds in a day (leap seconds are normally ignored) so the result should be a multiple of 86400. Hence:

time_t now = time();
time_t midnight = now / 86400 * 86400
Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
  • 1
    The answer needed is a time_t corresponding to midnight EST. The function written in the question although inefficient, actually returns time_t corresponding to midnight UTC. – Humble Debugger Feb 06 '11 at 03:44
  • In applications that manipulate with times in different timezones it is best to code your application to work in UTC times. Convert to/from local timezones only on input/output. This way you don't need to carry around the timezone along with the time value in the rest of your code. – Maxim Egorushkin Feb 06 '11 at 10:28
  • Unfortunately the much of the financial world sets it clock to EST/CST – Humble Debugger Feb 06 '11 at 13:15
  • The last two large scale electronic trading systems I've been working on only ever use UTC times. If a trading system needs to trade on exchanges across the world having system clock set in something other than UTC causes a lot of pain. Nevertheless, you are right that the original question requires an answer in non-UTC time. There are ways to convert current UTC time to local time and back and you can do that relatively straightforward with boost. – Maxim Egorushkin Feb 06 '11 at 13:32
  • @MaximYegorushkin I'll take your advice and try to move everything to UTC. However that will take some non-tech fight :) You mention "There are ways to convert current UTC time to local time and back and you can do that relatively straightforward with boost". any pointers ? – Humble Debugger Feb 06 '11 at 15:22
  • http://www.boost.org/doc/libs/1_45_0/doc/html/date_time/examples.html#date_time.examples.local_utc_conversion – Maxim Egorushkin Feb 07 '11 at 12:35
4
time_t local_midnight(time_t x) {
  struct tm t;
  localtime_r(&x, &t);
  t.tm_sec = t.tm_min = t.tm_hour = 0;
  return mktime(&t);
}

I used localtime_r since it must be available as you also used it in your answer.

Example:

int main() {
  time_t now = time(0);
  cout << "local: " << asctime(localtime(&now));
  cout << "UTC:   " << asctime(gmtime(&now));
  time_t midnight = local_midnight(now);
  cout << "\n       " << asctime(localtime(&midnight));
  return 0;
}
Fred Nurk
  • 13,952
  • 4
  • 37
  • 63
0

Current solution :

time_t RewindToMidnight ( const time_t & temp_time_t_ )
{
    int temp_yyyymmdd_ = iso_date_from_time_t ( temp_time_t_ );
    return time_t_from_iso_date ( temp_yyyymmdd_ );
}

int iso_date_from_time_t ( const time_t & in_time_t_ ) 
{
     tm temp_this_tm_;

     { // the following to set local dst fields of struct tm ?
         time_t tvsec_ = time(NULL);
         localtime_r ( & tvsec_, & temp_this_tm_ ) ;
     }
     localtime_r ( & in_time_t, & temp_this_tm_ ) ;

     return ( ( ( ( 1900 + temp_this_tm_.tm_year ) * 100 + ( 1 + temp_this_tm_.tm_mon ) ) * 100 ) + temp_this_tm_.tm_mday ) ;
}

time_t time_t_from_iso_date ( const int & temp_yyyymmdd_ ) 
{ 

     boost::gregorian::date d1 ( (int)( temp_yyyymmdd_/10000), 
                                 (int)( ( temp_yyyymmdd_/100) % 100), 
                                 (int)( temp_yyyymmdd_ % 100) );

     std::tm this_tm_ = to_tm ( d1 );
     return ( mktime ( & this_tm_ ) ) ;
}

Please advise.

Humble Debugger
  • 4,439
  • 11
  • 39
  • 56