#ifndef TIMESTAMP_HPP
#define TIMESTAMP_HPP
#include <cstdint>
#include <string>
#include <ctime>
#include <sys/time.h>
#include <utility>
#include <iomanip>
#include <sstream>
/**
* @brief 高精度不可变时间戳类(微秒级)
*/
class Timestamp
{
public:
/// 构造无效时间戳
Timestamp() noexcept : microSecondsSinceEpoch_(0) {}
/// 构造指定时间戳(微秒)
explicit Timestamp(int64_t microSecondsSinceEpochArg) noexcept
: microSecondsSinceEpoch_(microSecondsSinceEpochArg) {}
/// 交换
void swap(Timestamp& that) noexcept {
std::swap(microSecondsSinceEpoch_, that.microSecondsSinceEpoch_);
}
/// 转字符串(秒.微秒,形如:1502851234.123456)
std::string toString() const;
/// 转格式化字符串(支持是否显示微秒)
std::string toFormattedString(bool showMicroseconds = true) const;
/// 是否有效
bool valid() const noexcept { return microSecondsSinceEpoch_ > 0; }
/// 微秒时间戳
int64_t microSecondsSinceEpoch() const noexcept { return microSecondsSinceEpoch_; }
/// 秒级时间戳
time_t secondsSinceEpoch() const noexcept {
return static_cast<time_t>(microSecondsSinceEpoch_ / kMicroSecondsPerSecond);
}
/// 当前时间
static Timestamp now();
/// 无效时间戳
static Timestamp invalid() { return Timestamp(); }
/// Unix秒转Timestamp(可带微秒)
static Timestamp fromUnixTime(time_t t, int microseconds = 0) {
return Timestamp(static_cast<int64_t>(t) * kMicroSecondsPerSecond + microseconds);
}
static const int kMicroSecondsPerSecond = 1000 * 1000;
// 友元操作符
friend bool operator<(const Timestamp& lhs, const Timestamp& rhs) noexcept;
friend bool operator==(const Timestamp& lhs, const Timestamp& rhs) noexcept;
private:
int64_t microSecondsSinceEpoch_;
};
// 运算符重载
inline bool operator<(const Timestamp& lhs, const Timestamp& rhs) noexcept {
return lhs.microSecondsSinceEpoch_ < rhs.microSecondsSinceEpoch_;
}
inline bool operator==(const Timestamp& lhs, const Timestamp& rhs) noexcept {
return lhs.microSecondsSinceEpoch_ == rhs.microSecondsSinceEpoch_;
}
// 时间差(秒,double,精度足够)
inline double timeDifference(const Timestamp& high, const Timestamp& low) noexcept {
int64_t diff = high.microSecondsSinceEpoch() - low.microSecondsSinceEpoch();
return static_cast<double>(diff) / Timestamp::kMicroSecondsPerSecond;
}
// 时间加法
inline Timestamp addTime(const Timestamp& timestamp, double seconds) {
int64_t delta = static_cast<int64_t>(seconds * Timestamp::kMicroSecondsPerSecond);
return Timestamp(timestamp.microSecondsSinceEpoch() + delta);
}
#endif // TIMESTAMP_HPP
#include "Timestamp.hpp"
#include <gtest/gtest.h>
#include <thread>
#include <chrono>
// ----------- 单元测试主体 --------------
/**
* @brief 构造函数与有效性测试
* - 测试默认构造的无效性
* - 测试带参构造的有效性
*/
TEST(TimestampTest, ConstructionAndValidity) {
// 默认无效
Timestamp t1;
EXPECT_FALSE(t1.valid()) << "默认构造的时间戳应无效";
// 有参有效
Timestamp t2(123456789);
EXPECT_TRUE(t2.valid()) << "大于0的时间戳应有效";
EXPECT_EQ(t2.microSecondsSinceEpoch(), 123456789);
}
/**
* @brief 静态工厂与取值测试
* - 测试fromUnixTime接口
* - 测试invalid工厂方法
*/
TEST(TimestampTest, StaticFactoryAndAccess) {
time_t sec = 1000;
int usec = 200;
Timestamp t = Timestamp::fromUnixTime(sec, usec);
EXPECT_EQ(t.secondsSinceEpoch(), sec);
EXPECT_EQ(t.microSecondsSinceEpoch(), sec * Timestamp::kMicroSecondsPerSecond + usec);
Timestamp inv = Timestamp::invalid();
EXPECT_FALSE(inv.valid()) << "invalid()方法应生成无效时间戳";
}
/**
* @brief toString 与 toFormattedString 输出格式测试
* - 测试格式化字符串
* - 测试微秒显示与不显示
*/
TEST(TimestampTest, StringFormat) {
time_t sec = 1609459200; // 2021-01-01 00:00:00 UTC
int usec = 123456;
Timestamp t = Timestamp::fromUnixTime(sec, usec);
std::string s = t.toString();
EXPECT_NE(s.find("."), std::string::npos) << "应包含小数点";
std::string formattedWith = t.toFormattedString(true);
std::string formattedWithout = t.toFormattedString(false);
EXPECT_NE(formattedWith.find("."), std::string::npos) << "showMicroseconds=true 应包含小数点";
EXPECT_EQ(formattedWithout.find("."), std::string::npos) << "showMicroseconds=false 不应包含小数点";
// 核心时间字段应匹配
EXPECT_NE(formattedWith.find("20210101 00:00:00"), std::string::npos);
}
/**
* @brief now() 当前时间与递增性测试
* - 测试now生成的时间戳有效
* - 测试连续now严格递增
*/
TEST(TimestampTest, NowAndIncrement) {
Timestamp t1 = Timestamp::now();
EXPECT_TRUE(t1.valid());
// 休眠一段时间
std::this_thread::sleep_for(std::chrono::milliseconds(10));
Timestamp t2 = Timestamp::now();
EXPECT_LT(t1, t2) << "后获取的时间戳应更大";
EXPECT_GT(timeDifference(t2, t1), 0.0) << "时间差应为正数";
}
/**
* @brief 比较与等值性测试
* - 测试等于/小于/大于操作
*/
TEST(TimestampTest, ComparisonOperators) {
Timestamp t1(1000000);
Timestamp t2(2000000);
EXPECT_TRUE(t1 < t2);
EXPECT_FALSE(t2 < t1);
EXPECT_TRUE(t1 == t1);
EXPECT_FALSE(t1 == t2);
}
/**
* @brief 时间差与加法操作测试
* - 测试timeDifference函数
* - 测试addTime正确性
*/
TEST(TimestampTest, TimeDifferenceAndAdd) {
Timestamp base(1000000); // 1秒
Timestamp later = addTime(base, 2.5); // 加2.5秒
EXPECT_EQ(later.microSecondsSinceEpoch(), 1000000 + static_cast<int64_t>(2.5 * Timestamp::kMicroSecondsPerSecond));
double diff = timeDifference(later, base);
EXPECT_NEAR(diff, 2.5, 1e-9);
}
/**
* @brief 边界条件与异常输入测试
* - 测试负数与极小值
*/
TEST(TimestampTest, EdgeCase) {
Timestamp tneg(-1234567);
EXPECT_FALSE(tneg.valid()) << "负数时间戳应无效";
Timestamp tzero(0);
EXPECT_FALSE(tzero.valid()) << "0时间戳应无效";
}
/**
* @brief swap操作测试
* - 检查swap函数正确交换对象
*/
TEST(TimestampTest, SwapTest) {
Timestamp t1(1111);
Timestamp t2(2222);
t1.swap(t2);
EXPECT_EQ(t1.microSecondsSinceEpoch(), 2222);
EXPECT_EQ(t2.microSecondsSinceEpoch(), 1111);
}
#include "Timestamp.hpp"
#include <sys/time.h>
#include <cstdio>
std::string Timestamp::toString() const {
char buf[32] = {0};
int64_t seconds = microSecondsSinceEpoch_ / kMicroSecondsPerSecond;
int64_t microseconds = microSecondsSinceEpoch_ % kMicroSecondsPerSecond;
std::snprintf(buf, sizeof(buf), "%lld.%06lld",
static_cast<long long>(seconds),
static_cast<long long>(microseconds));
return buf;
}
std::string Timestamp::toFormattedString(bool showMicroseconds) const {
char buf[64] = {0};
time_t seconds = static_cast<time_t>(microSecondsSinceEpoch_ / kMicroSecondsPerSecond);
struct tm tm_time;
gmtime_r(&seconds, &tm_time); // POSIX
if (showMicroseconds) {
int microseconds = static_cast<int>(microSecondsSinceEpoch_ % kMicroSecondsPerSecond);
std::snprintf(buf, sizeof(buf), "%4d%02d%02d %02d:%02d:%02d.%06d",
tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday,
tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec,
microseconds);
} else {
std::snprintf(buf, sizeof(buf), "%4d%02d%02d %02d:%02d:%02d",
tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday,
tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec);
}
return buf;
}
Timestamp Timestamp::now() {
struct timeval tv;
gettimeofday(&tv, nullptr);
int64_t seconds = tv.tv_sec;
return Timestamp(seconds * kMicroSecondsPerSecond + tv.tv_usec);
}