この記事は最終更新日から1年以上が経過しています。
@programming
投稿日 2021/2/10
更新日 2021/2/10 ✏
C++で日付時間の取得と変換
C++の標準ライブラリstd::chrono
で日付を扱う方法です。
目次:
前提
- Ubuntu 16.04 LTS
- g++ 7.5.0
- C++11
サンプルコード
以下のサンプルコードは、
- unixエポック時間(ミリ秒)を取得
- unixエポック時間(秒)を取得
- unixエポック時間(ミリ秒)からISO世界標準時間文字列を取得
- unixエポック時間(ミリ秒)からローカル時間文字列を取得
を行う方法を示しています。
time-test.cpp
#include <iostream>
#include <chrono>
using namespace std;
int main(int argc, char* argv[]) {
//
// 現在時間(unixエポック)を取得する方法
//
// 1. 現在のtime_pointを取得:
auto tp = chrono::system_clock::now();
// 2. time_pointからdurationを取得:
auto duration = tp.time_since_epoch();
// 3. durationからunixエポック(ミリ秒)を取得:
auto ms = chrono::duration_cast<chrono::milliseconds>(duration).count();
cout << "現在時間(unixエポックミリ秒): " << ms << endl;
// or durationからunixエポック(秒)を取得:
auto s = chrono::duration_cast<chrono::seconds>(duration).count();
cout << "現在時間(unixエポック秒): " << s << endl;
//
// unixエポック(ミリ秒)からISO世界標準時間文字列を取得する方法
//
long int sec = ms / 1000;
char isoStr[sizeof "2021-01-31T23:59:59.000Z"];
strftime(isoStr, sizeof isoStr, "%FT%T", gmtime(&sec));
int delta = ms - (sec * 1000);
sprintf(isoStr, "%s.%03dZ", isoStr, delta);
cout << "ISO世界標準時間文字列: " << isoStr << endl;
//
// unixエポック(ミリ秒)からローカル時間文字列を取得する方法
//
long int sec1 = ms / 1000;
struct tm* timeinfo;
timeinfo = localtime(&sec1);
int charsize = sizeof "2021/02/09(Tue)23:59:59";
char localStr[charsize];
strftime(localStr, charsize, "%Y/%m/%d(%a)%H:%M:%S", timeinfo);
cout << "ローカル時間文字列: " << localStr << endl;
return 0;
}
コンパイル&実行:
## コンパイル&実行:
$ g++ -o a.out time-test.cpp && ./a.out
現在時間(unixエポックミリ秒): 1612910593925
現在時間(unixエポック秒): 1612910593
ISO世界標準時間文字列: 2021-02-09T22:43:13.925Z
ローカル時間文字列: 2021/02/10(Wed)07:43:13
おまけ:自作日付操作クラス
せっかくなので、コピペで使えるシンプルなDate
クラスも自作してみました。
Date.h
#ifndef DATE_H
#define DATE_H
#include <chrono>
#include <sstream>
#include <regex>
using namespace std;
/**
* Date utility class
*
* Usage
* ```
* #include "path/to/Date.h"
*
* Date date;
*
* // Get a current unix epoch time in milliseconds.
* long int now = date.getTime();
* // or from ISO date string:
* // long int now = date.getTime("2021-02-09T07:20:29.096Z");
*
* // Get an ISO date string:
* std::string isoStr = date.getISOString();
* // or from unix epoch time in milliseconds:
* // std::string isoStr = date.getISOString(1612855960407);
*
* // Get a local date string:
* std::string localStr = date.getLocaleString();
* // or from unix epoch time in milliseconds:
* // std::string localStr = date.getLocaleString(1612855960407);
* // also, from unix epoch time in milliseconds with a format:
* // std::string localStr = date.getLocaleString(1612855960407, "%Y/%m/%d(%a)%H:%M:%S");
*
* ```
*/
class Date {
private:
/**
* Check whether ISO date string with milliseconds or not.
* @param isoStr {string} A ISO date string. e.g. "2021-02-09T01:46:45.595Z".
* @return {bool} e.g. Passing "2021-02-09T01:46:45.595Z" (has millisecond's part) returns true.
*/
static bool isLongISOString(std::string isoStr) {
return true;
regex re(R"(^(\d+)-(\d+)-(\d+)T(\d+):(\d+):(\d+)\.(\d+)Z$)");
smatch m;
regex_match(isoStr, m, re);
if (m.size() >= 1) return true;
return false;
}
public:
/**
* Get a current time in millisecond.
* @return {long int} a current unix epoch time in millisecond.
*/
static long int getTime() {
auto tp = std::chrono::system_clock::now();
auto duration = tp.time_since_epoch();
auto msec = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();
return msec;
}
/**
* Converts an ISO date string to unix epoch time and returns it.
* @param isoStr {string} A ISO date string. e.g. "2021-02-09T01:46:45.595Z"
* @return {long int} An unix epoch time in milliseconds.
*/
static long int getTime(std::string isoStr) {
int y, M, d, h, m, s;
int ms = 0;
if (Date::isLongISOString(isoStr)) {
// with milliseconds' part:
sscanf(isoStr.c_str(), "%d-%d-%dT%d:%d:%d.%dZ", &y, &M, &d, &h, &m, &s, &ms);
} else {
// without milliseconds' part:
sscanf(isoStr.c_str(), "%d-%d-%dT%d:%d:%dZ", &y, &M, &d, &h, &m, &s);
}
std::tm tm = {
/* .tm_sec = */ s,
/* .tm_min = */ m,
/* .tm_hour = */ h,
/* .tm_mday = */ (d),
/* .tm_mon = */ (M) - 1,
/* .tm_year = */ (y) - 1900,
};
tm.tm_isdst = -1; // Use DST value from local time zone
auto tp = std::chrono::system_clock::from_time_t(std::mktime(&tm));
auto duration = tp.time_since_epoch();
auto msec = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();
return msec + ms; // Add actual millisecond's value to the rough result in millisecond.
}
/**
* Get an ISO date string.
* @param msec {long int}
* @return {std::string} An ISO date string. e.g. "2021-02-09T01:46:45.595Z".
*/
static std::string getISOString(long int msec) {
long int sec = msec / 1000;
char isoStr[sizeof "2021-01-31T23:59:59.000Z"];
strftime(isoStr, sizeof isoStr, "%FT%T", gmtime(&sec));
int delta = msec - (sec * 1000);
sprintf(isoStr, "%s.%03dZ", isoStr, delta);
return isoStr;
}
/**
* Get a current ISO date string.
* @return {std::string} An ISO date string. e.g. "2021-02-09T01:46:45.595Z".
*/
static std::string getISOString() {
auto msec = Date::getTime();
return getISOString(msec);
}
/**
* Get a local date string.
* @param msec {long int} An unix epoch time in milliseconds.
* @return {std::string} A local date string. e.g. "2021/02/09(Tue)16:20:30".
*/
static std::string getLocaleString(long int msec) {
return Date::getLocaleString(msec, "%Y/%m/%d(%a)%H:%M:%S");
}
/**
* Get a local date string.
* @param msec {long int} An unix epoch time in milliseconds.
* @param dateformat {char*} A date format. e.g. "%Y/%m/%d(%a)%H:%M:%S"
* @return {std::string} A local date string. e.g. "2021/02/09(Tue)16:20:30".
*/
static std::string getLocaleString(long int msec, const char* dateformat) {
long int sec = msec / 1000;
struct tm* timeinfo;
timeinfo = localtime(&sec);
int charsize = sizeof "2021/02/09(Tue)23:59:59";
char output[charsize];
strftime(output, charsize, dateformat, timeinfo);
return string(output);
}
/**
* Get a current local date string.
* @return {std::string} A local date string. e.g. "2021/02/09(Tue)16:20:30".
*/
static std::string getLocaleString() {
return getLocaleString(Date::getTime());
}
};
#endif
上記のDate
クラスは以下のstaticメソッドを持っています:
- 現在のunixエポック時間(ミリ秒)の取得
- 現在のISO世界標準時間文字列の取得
- 現在のローカル時間文字列の取得
- unixエポック時間(ミリ秒)のISO世界標準時間文字列への変換
- unixエポック時間(ミリ秒)のローカル時間文字列への変換
使い方は以下のコードを参考にしてください。
Date-test.cpp
#include <iostream>
// 自作Dateクラスをinclude:
#include "Date.h"
using namespace std;
int main(int argc, char* argv[]) {
// 自作Dateクラスを定義:
const Date date;
// テスト用のISO世界標準時間文字列(ミリ秒部分無し):
const string isoShortStr = "2021-02-09T07:20:29Z";
// テスト用のISO世界標準時間文字列:
const string isoStr = "2021-02-09T07:20:29.096Z";
//
// ISO世界標準時間文字列 => unixエポックミリ秒
//
// ISO世界標準時間文字列(ミリ秒部分無し)をunixエポックミリ秒に変換:
const long int time = date.getTime(isoShortStr); // TIP: 引数無しなら現在のunixエポックミリ秒を取得
cout << isoShortStr << " => " << time << " (unixエポックミリ秒)" << endl;
// ISO世界標準時間文字列をunixエポックミリ秒に変換:
const long int time1 = date.getTime(isoStr);
cout << isoStr << " => " << time1 << " (unixエポックミリ秒)" << endl;
//
// unixエポックミリ秒 => ISO世界標準時間文字列
//
// unixエポックミリ秒をISO世界標準時間文字列に変換:
string isoStr1 = date.getISOString(time); // TIP: 引数無しなら現在のISO世界標準時間を取得
cout << time << " => " << isoStr1 << " (ISO世界標準時間)" << endl;
//
// unixエポックミリ秒 => ロケール時間文字列
//
// unixエポックミリ秒をロケール時間文字列に変換:
std::string localStr1 = date.getLocaleString(time); // TIP: 引数無しなら現在のロケール時間を取得
cout << time << " => " << localStr1 << " (ロケール時間)" << endl;
// unixエポックミリ秒をロケール時間文字列に変換(フォーマット指定):
string localStr2 = date.getLocaleString(time, "%Y-%m-%d %a %H:%M:%S");
cout << time << " => " << localStr2 << " (ロケール時間 with 形式指定)" << endl;
return 0;
}
コンパイル&実行:
## コンパイル&実行:
$ g++ -o a.out Date-test.cpp && ./a.out
2021-02-09T07:20:29Z => 1612822829000 (unixエポックミリ秒)
2021-02-09T07:20:29.096Z => 1612822829096 (unixエポックミリ秒)
1612822829000 => 2021-02-08T22:20:29.000Z (ISO世界標準時間)
1612822829000 => 2021/02/09(Tue)07:20:29 (ロケール時間)
1612822829000 => 2021-02-09 Tue 07:20:29 (ロケール時間 with 形式指定)
以上です。