代码之家  ›  专栏  ›  技术社区  ›  Gabriel Schreiber

如何从字符串中分析日期/时间?

  •  52
  • Gabriel Schreiber  · 技术社区  · 15 年前

    输入 :带有日期和可选时间的字符串。不同的表述是不错的,但也是必要的。字符串由用户提供,并且可能格式不正确。示例:

    • "2004-03-21 12:45:33" (我认为这是默认布局)
    • "2004/03/21 12:45:33" (可选布局)
    • "23.09.2004 04:12:21" (德语格式,可选)
    • "2003-02-11" (可能缺少时间)

    需要的输出 :从epoch(1970/01/01 00:00:00)或其他固定点开始的秒数。

    奖金 :另外,读取本地系统时间的UTC偏移量也很好。

    假设输入是相关机器上的本地时间。 输出必须是UTC。系统仅限Linux(需要Debian Lenny和Ubuntu)。

    我试过用 boost/date_time 但必须承认我不能把我的头绕在文件上。以下功能在不需要将系统本地时间转换为UTC的情况下工作:

    std::string date = "2000-01-01";
    boost::posix_time::ptime ptimedate = boost::posix_time::time_from_string(date);
    ptimedate += boost::posix_time::hours(Hardcoded_UTC_Offset);// where to get from?
    struct tm = boost::posix_time::to_tm(ptimedate);
    int64_t ticks = mktime(&mTmTime);
    

    我想 boost::date_time 可以提供所需的UTC偏移量,但我不知道如何提供。

    4 回复  |  直到 15 年前
        1
  •  64
  •   Cubbi    15 年前

    虽然我不知道如何在Boost中格式化一个数字月份输入,但在两位数编辑后我可以这样做:

    #include <iostream>
    #include <boost/date_time.hpp>
    namespace bt = boost::posix_time;
    const std::locale formats[] = {
    std::locale(std::locale::classic(),new bt::time_input_facet("%Y-%m-%d %H:%M:%S")),
    std::locale(std::locale::classic(),new bt::time_input_facet("%Y/%m/%d %H:%M:%S")),
    std::locale(std::locale::classic(),new bt::time_input_facet("%d.%m.%Y %H:%M:%S")),
    std::locale(std::locale::classic(),new bt::time_input_facet("%Y-%m-%d"))};
    const size_t formats_n = sizeof(formats)/sizeof(formats[0]);
    
    std::time_t pt_to_time_t(const bt::ptime& pt)
    {
        bt::ptime timet_start(boost::gregorian::date(1970,1,1));
        bt::time_duration diff = pt - timet_start;
        return diff.ticks()/bt::time_duration::rep_type::ticks_per_second;
    
    }
    void seconds_from_epoch(const std::string& s)
    {
        bt::ptime pt;
        for(size_t i=0; i<formats_n; ++i)
        {
            std::istringstream is(s);
            is.imbue(formats[i]);
            is >> pt;
            if(pt != bt::ptime()) break;
        }
        std::cout << " ptime is " << pt << '\n';
        std::cout << " seconds from epoch are " << pt_to_time_t(pt) << '\n';
    }
    int main()
    {
        seconds_from_epoch("2004-03-21 12:45:33");
        seconds_from_epoch("2004/03/21 12:45:33");
        seconds_from_epoch("23.09.2004 04:12:21");
        seconds_from_epoch("2003-02-11");
    }
    

    请注意,从epoch输出开始的秒数将假定日期为UTC:

    ~ $ ./test | head -2
    ptime is 2004-Mar-21 12:45:33
    seconds from epoch are 1079873133
    ~ $ date -d @1079873133
    Sun Mar 21 07:45:33 EST 2004
    

    你可能会用 boost::posix_time::c_time::localtime() #include <boost/date_time/c_time.hpp> 要在输入位于当前时区的情况下完成此转换,但这是相当不一致的:例如,对于我来说,当夏令时结束时,今天和下个月的结果将不同。

        2
  •  10
  •   Steve Townsend    15 年前

    boost::gregorian 有一些你需要的东西,你不用再做任何工作:

    using namespace boost::gregorian;
    {
      // The following date is in ISO 8601 extended format (CCYY-MM-DD)
      std::string s("2000-01-01");
      date d(from_simple_string(s));
      std::cout << to_simple_string(d) << std::endl;
    }
    

    有一个关于如何使用UTC偏移量的示例 boost::posix_time here .

    您可以使用 date_input_facet time_input_facet . 有一个I/O教程 this page 那会帮你走的。

        3
  •  7
  •   stefaanv    15 年前

    如果可以接受C样式: strptime ()是一种方法,因为您可以指定格式,并且可以考虑使用区域设置:

    tm brokenTime;
    strptime(str.c_str(), "%Y-%m-%d %T", &brokenTime);
    time_t sinceEpoch = timegm(brokenTime);
    

    必须使用返回值检查不同的布局(如果可能)。 必须通过检查系统时钟将时区添加到(localtime_r()with time(),tm_zone)

        4
  •  2
  •   Vijay Mathew Chor-ming Lung    15 年前

    最简单的便携式解决方案是 scanf :

    int year, month, day, hour, minute, second = 0;
    int r = 0;
    
    r = scanf ("%d-%d-%d %d:%d:%d", &year, &month, &day,
               &hour, &minute, &second);
    if (r == 6) 
    {
      printf ("%d-%d-%d %d:%d:%d\n", year, month, day, hour, minute,
              second);
    }
    else 
    {
        r = scanf ("%d/%d/%d %d:%d:%d", &year, &month, &day,
               &hour, &minute, &second);
        // and so on ...
    

    初始化 struct tm int 值并传递给 mktime 获取日历时间 time_t . 对于时区转换,请 see information gmtime .