16

次の形式の文字列があります。

2010-11-04T23:23:01Z

Zは、時刻がUTCであることを示します。
比較を容易にするために、これをエポックタイムとして保存したいと思います。

これを行うための推奨される方法は何ですか?

現在(quck検索後)simplistアルゴリズムは次のとおりです。

1: <Convert string to struct_tm: by manually parsing string>
2: Use mktime() to convert struct_tm to epoch time.

// Problem here is that mktime uses local time not UTC time.
4

10 に答える 10

6

これはISO8601形式です。関数を使用strptimeして、引数を使用して解析でき%FT%T%zます。これはC++標準の一部ではありませんが、オープンソースの実装を使用できます(たとえば、これ)。

于 2010-11-09T19:52:05.693 に答える
5

文字列を手動で解析する代わりに、strptimeなどの関数を使用して文字列をに変換できます。struct tm

于 2010-11-09T19:46:10.810 に答える
3

これは正確な重複ではありませんが、ここからの@Cubbiの回答が役立つことがわかります。賭けます。これは特にUTC入力を想定しています。

boost::posix_time::from_iso_stringBoostは、呼び出しを介したISO 8601からの直接変換もサポートしますboost::date_time::parse_iso_time。ここでも、末尾の「Z」を削除して、TZを暗黙のUTCとして扱います。

#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");
}
于 2010-11-09T19:51:40.313 に答える
2

古い質問に対する新しい回答。<chrono>新しい回答の根拠:このような問題を解決するために型を使用したい場合。

C++11/C++14 に加えて、この無料のオープン ソースの日付/時刻ライブラリが必要になります。

#include "tz.h"
#include <iostream>
#include <sstream>

int
main()
{
    std::istringstream is("2010-11-04T23:23:01Z");
    is.exceptions(std::ios::failbit);
    date::sys_seconds tp;
    date::parse(is, "%FT%TZ", tp);
    std::cout << "seconds from epoch is " << tp.time_since_epoch().count() << "s\n";
}

このプログラムは次を出力します。

seconds from epoch is 1288912981s

解析が何らかの形で失敗した場合、例外がスローされます。例外をスローしたくない場合は、しないでください。is.exceptions(std::ios::failbit);代わりに、をチェックしてくださいis.fail()

于 2016-06-04T02:08:31.140 に答える
1

を利用して、文字列用boost::date_timeの小さな手動パーサー(おそらく正規表現ベース)を作成できます。

于 2010-11-09T19:44:58.903 に答える
1

ここでの問題は、mktime が UTC 時間ではなく現地時間を使用することです。

UTC と現地時間の時差を計算し、それを によって返される値に追加するだけではmktimeどうですか?

time_t local = time(NULL),
       utc   = mktime(gmtime(&local));
int    diff  = utc - local;
于 2010-11-09T19:57:55.643 に答える
1

何が問題なのstrptime()ですか?

Linux では、「UTC から東への秒数」フィールドを取得することもできるため、解析する必要がなくなります。

#define _XOPEN_SOURCE
#include <iostream>
#include <time.h>

int main(void) {

    const char *timestr = "2010-11-04T23:23:01Z";

    struct tm t;
    strptime(timestr, "%Y-%m-%dT%H:%M:%SZ", &t);

    char buf[128];
    strftime(buf, sizeof(buf), "%d %b %Y %H:%M:%S", &t);

    std::cout << timestr << " -> " << buf << std::endl;

    std::cout << "Seconds east of UTC " << t.tm_gmtoff << std::endl;
}   

私にとっては

/tmp$ g++ -o my my.cpp 
/tmp$ ./my
2010-11-04T23:23:01Z -> 04 Nov 2010 23:23:01
Seconds east of UTC 140085769590024
于 2010-11-09T19:58:13.630 に答える
1

X/Open は、timezone現地時間が UTC から遅れている秒数を示すグローバル変数を提供します。これを使用して、次の出力を調整できますmktime()

#define _XOPEN_SOURCE
#include <stdio.h>
#include <time.h>

/* 2010-11-04T23:23:01Z */
time_t zulu_time(const char *time_str)
{
    struct tm tm = { 0 };

    if (!strptime(time_str, "%Y-%m-%dT%H:%M:%SZ", &tm))
        return (time_t)-1;

    return mktime(&tm) - timezone;
}
于 2010-11-12T01:50:37.233 に答える