* Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
#include <stdexcept>
#include <chrono>
#include <iomanip>
#include <ctime>
#include <charconv>
#include "TimestampData.h"
#include "common.h"
TimestampData::TimestampData(long millisecond, int nanoOfMillisecond): millisecond(millisecond), nanoOfMillisecond(nanoOfMillisecond)
{
if (nanoOfMillisecond < 0 || nanoOfMillisecond > 999999) {
throw std::invalid_argument("nanoOfMillisecond must be between 0 and 999999.");
}
}
long TimestampData::getMillisecond() const
{
return millisecond;
}
int TimestampData::getNanoOfMillisecond() const
{
return nanoOfMillisecond;
}
TimestampData *TimestampData::fromEpochMillis(long milliseconds)
{
return new TimestampData(milliseconds, 0);
}
TimestampData *TimestampData::fromEpochMillis(long milliseconds, int nanosOfMillisecond)
{
return new TimestampData(milliseconds, nanosOfMillisecond);
}
bool TimestampData::isCompact(int percision)
{
return percision <= 3;
}
* Convert string to milliseconds since Unix Epoch
* @param str Support formats like "2025-02-07 12:00:00.000" and "1989-03-04 08:00:00"
* @return
*/
long TimestampData::stringToEpochMillis(const std::string& str)
{
const char* start = str.data();
const char* end = str.data() + str.size();
while (start < end && *start == ' ') ++start;
while (end > start && *(end - 1) == ' ') --end;
if (start >= end) {
THROW_RUNTIME_ERROR("Empty datetime string after trimming spaces")
}
const char* dotPtr = nullptr;
const char* tempPtr = start;
while (tempPtr < end - 1) {
if (*tempPtr == '.') {
dotPtr = tempPtr;
break;
}
++tempPtr;
}
const char* datetimeEnd = dotPtr ? dotPtr : end;
std::tm t = {};
int parse_count = sscanf(
start,
"%d-%d-%d %d:%d:%d",
&t.tm_year, &t.tm_mon, &t.tm_mday,
&t.tm_hour, &t.tm_min, &t.tm_sec
);
if (parse_count != 6) {
THROW_RUNTIME_ERROR("Failed to parse datetime string"+ std::string(start, datetimeEnd))
}
t.tm_year -= 1900;
t.tm_mon -= 1;
int milliseconds = 0;
if (dotPtr != nullptr) {
const char* msStart = dotPtr + 1;
const char* msEnd = end - msStart > 3 ? msStart + 3 : end;
int msInt = 0;
std::from_chars_result res = std::from_chars(msStart, msEnd, msInt);
if (res.ec != std::errc{}) {
THROW_RUNTIME_ERROR("Failed to parse milliseconds: " + std::string(msStart, msEnd));
}
size_t msDigits = res.ptr - msStart;
if (msDigits == 1) {
milliseconds = msInt * 100;
} else if (msDigits == 2) {
milliseconds = msInt * 10;
} else if (msDigits == 3) {
milliseconds = msInt;
}
}
std::time_t time_since_epoch = timegm(&t);
return static_cast<long>(time_since_epoch) * 1000 + milliseconds;
}
TimestampData* TimestampData::fromString(const std::string& str)
{
return new TimestampData(stringToEpochMillis(str), 0);
}
TimestampData* TimestampData::fromLocalTimeString(const std::string& str)
{
size_t pos = str.find_last_of('Z');
if (pos == std::string::npos) {
throw std::invalid_argument("Invalid timestamp_with_lzt string");
}
return new TimestampData(stringToEpochMillis(str.substr(0, pos)), 0);
}