【问题标题】:Get time_t / timeval corresponding to ( local_timezone ) midnight on a given date获取与给定日期的 (local_timezone) 午夜对应的 time_t / timeval
【发布时间】:2011-06-22 01:29:07
【问题描述】:

给定 time_t 或 struct timeval,我如何获得当天 EST/EDT(本地时区)午夜的 timeval 或 time_t? 假设本地时区是 EST/EDT,假设 time_t 对应于 2010-11-30 08:00:00 EST/EDT,预期的答案是 time_t 对应于 2010-11-30 00:00:00 EST /EDT

尝试 1(不正确:因为它不处理 DST,并假设 EST/EDT 总是比 UTC 晚 5 小时):

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

尝试 2(不正确:因为它返回的 time_t 对应于 UTC 午夜时间,而不是 EST/EDT,本地时区):

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) 结构体 tm、mktime 或 (ii) boost::local_date_time 也许?

【问题讨论】:

  • 您的 time_t 是 UTC 还是本地时间?
  • 给定的 time_t 在本地时区,即 EST。
  • EST 总是比 UTC 晚 5 小时。 EDT 是 DST 时区。

标签: c++ unix-timestamp time-t boost-date-time timeval


【解决方案1】:

由于 time_t 是以秒为单位的时间(UTC,1970 年 1 月 1 日 00:00:00),因此您只需去掉一天中的秒数。一天有 86400 秒(通常忽略闰秒),所以结果应该是 86400 的倍数。因此:

time_t now = time();
time_t midnight = now / 86400 * 86400

【讨论】:

  • 所需的答案是对应于美国东部标准时间午夜的 time_t。问题中编写的函数虽然效率低下,但实际上返回了对应于午夜 UTC 的 time_t。
  • 在处理不同时区时间的应用程序中,最好将应用程序编码为在 UTC 时间工作。仅在输入/输出上转换为本地时区/从本地时区转换。这样您就不需要在其余代码中携带时区以及时间值。
  • 不幸的是,大部分金融界都将时钟设置为 EST/CST
  • 我最近使用的两个大型电子交易系统只使用 UTC 时间。如果一个交易系统需要在世界各地的交易所进行交易,而系统时钟设置为 UTC 以外的其他时间会导致很多痛苦。不过,您是对的,原始问题需要在非 UTC 时间得到答案。有多种方法可以将当前 UTC 时间转换为本地时间并返回,您可以通过 boost 相对简单地做到这一点。
  • @MaximYegorushkin 我会听取您的建议并尝试将所有内容移至 UTC。然而,这将需要一些非技术性的斗争:) 你提到“有一些方法可以将当前的 UTC 时间转换为本地时间并返回,你可以通过 boost 相对简单地做到这一点”。任何指针?
【解决方案2】:
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);
}

我使用 localtime_r 因为它必须可用,因为您在回答中也使用了它。

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;
}

【讨论】:

    【解决方案3】:

    目前的解决方案:

    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_ ) ) ;
    }
    

    请指教。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-01-18
      • 1970-01-01
      • 1970-01-01
      • 2018-08-19
      • 1970-01-01
      • 1970-01-01
      • 2016-11-27
      • 1970-01-01
      相关资源
      最近更新 更多