Branch data Line data Source code
1 : : /* 2 : : * Copyright (C) 2026 by Thun Lu. All rights reserved. 3 : : * Author: Thun Lu <thun.lu@zohomail.cn> 4 : : * Repo: https://github.com/thun-res/vlink 5 : : * _ __ __ _ __ 6 : : * | | / / / / (_) ____ / /__ 7 : : * | | / / / / / / / __ \ / //_/ 8 : : * | |/ / / /___ / / / / / / / ,< 9 : : * |___/ /_____/ /_/ /_/ /_/ /_/|_| 10 : : * 11 : : * Licensed under the Apache License, Version 2.0 (the "License"); 12 : : * you may not use this file except in compliance with the License. 13 : : * You may obtain a copy of the License at 14 : : * 15 : : * http://www.apache.org/licenses/LICENSE-2.0 16 : : * 17 : : * Unless required by applicable law or agreed to in writing, software 18 : : * distributed under the License is distributed on an "AS IS" BASIS, 19 : : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 : : * See the License for the specific language governing permissions and 21 : : * limitations under the License. 22 : : */ 23 : : 24 : : #include "./base/cached_timestamp.h" 25 : : 26 : : #include <cstdio> 27 : : #include <limits> 28 : : 29 : : namespace vlink { 30 : : 31 : 160 : CachedTimestamp::CachedTimestamp() = default; 32 : : 33 : 158 : CachedTimestamp::~CachedTimestamp() = default; 34 : : 35 : 1905 : std::string_view CachedTimestamp::get(const char* format, bool use_utc) { 36 : 1905 : return get_at(std::chrono::system_clock::now(), format, use_utc); 37 : : } 38 : : 39 : 1923 : std::string_view CachedTimestamp::get_at(std::chrono::system_clock::time_point now, const char* format, bool use_utc) { 40 [ + - ]: 1923 : const auto milliseconds = std::chrono::floor<std::chrono::milliseconds>(now.time_since_epoch()).count(); 41 : 1923 : int64_t sec = milliseconds / 1000; 42 : 1923 : int ms = static_cast<int>(milliseconds % 1000); 43 : : 44 [ + + ]: 1923 : if VUNLIKELY (ms < 0) { 45 : 4 : --sec; 46 : 4 : ms += 1000; 47 : : } 48 : : 49 [ + - ]: 1923 : std::lock_guard lock(mtx_); 50 : : 51 : 1924 : int64_t cached_sec = last_sec_; 52 : : 53 : : static constexpr const char* kCanonicalFormat = "%02d-%02d %02d:%02d:%02d.%03d"; 54 : : 55 [ - + ]: 1924 : if VUNLIKELY (format == nullptr) { 56 : 0 : format = kCanonicalFormat; 57 : : } 58 : : 59 [ + - + + ]: 1924 : const bool canonical = (format == kCanonicalFormat) || (std::string_view(format) == kCanonicalFormat); 60 : : 61 [ + + + + : 1924 : if VLIKELY (cache_valid_ && canonical && sec == cached_sec && is_utc_ == use_utc) { + + + + + + + - + + ] 62 [ + - ]: 1893 : update_milliseconds(ms); 63 : 1893 : return std::string_view(buffer_, buffer_len_); 64 : : } 65 : : 66 [ + - ]: 31 : format_full_timestamp(format, sec, use_utc, ms); 67 [ + + + - ]: 31 : cache_valid_ = canonical && buffer_len_ != 0; 68 : : 69 : 31 : last_sec_ = sec; 70 : 31 : is_utc_ = use_utc; 71 : : 72 : 31 : return std::string_view(buffer_, buffer_len_); 73 : 1924 : } 74 : : 75 : 31 : void CachedTimestamp::format_full_timestamp(const char* format, int64_t seconds, bool use_utc, int ms) { 76 : 31 : buffer_len_ = 0; 77 : : 78 : : if constexpr (!std::numeric_limits<std::time_t>::is_signed) { 79 : : if VUNLIKELY (seconds < 0) { 80 : : return; 81 : : } 82 : : } 83 : : 84 : 31 : const auto now_time_t = static_cast<std::time_t>(seconds); 85 : : 86 : : if constexpr (sizeof(std::time_t) < sizeof(int64_t)) { 87 : : if VUNLIKELY (static_cast<int64_t>(now_time_t) != seconds) { 88 : : return; 89 : : } 90 : : } 91 : : 92 : 31 : std::tm now_tm{}; 93 : 31 : bool converted = false; 94 : : 95 : : #if defined(_WIN32) 96 : : 97 : : if (use_utc) { 98 : : converted = gmtime_s(&now_tm, &now_time_t) == 0; 99 : : } else { 100 : : converted = localtime_s(&now_tm, &now_time_t) == 0; 101 : : } 102 : : #else 103 : : 104 [ + + ]: 31 : if (use_utc) { 105 : 14 : converted = gmtime_r(&now_time_t, &now_tm) != nullptr; 106 : : } else { 107 : 17 : converted = localtime_r(&now_time_t, &now_tm) != nullptr; 108 : : } 109 : : #endif 110 : : 111 [ - + ]: 31 : if VUNLIKELY (!converted) { 112 : 1 : return; 113 : : } 114 : : 115 : 31 : int len = std::snprintf(buffer_, sizeof(buffer_), format, now_tm.tm_mon + 1, now_tm.tm_mday, now_tm.tm_hour, 116 : : now_tm.tm_min, now_tm.tm_sec, ms); 117 : : 118 [ + - + + : 31 : if VUNLIKELY (len < 0 || len >= static_cast<int>(sizeof(buffer_))) { + + ] 119 : 1 : return; 120 : : } 121 : : 122 : 30 : buffer_len_ = static_cast<size_t>(len); 123 : 30 : ms_offset_ = buffer_len_ - 3; 124 : : } 125 : : 126 : 1893 : void CachedTimestamp::update_milliseconds(int ms) { 127 : 1893 : char* ms_ptr = buffer_ + ms_offset_; 128 : : 129 : 1893 : ms_ptr[0] = '0' + (ms / 100); 130 : 1893 : ms_ptr[1] = '0' + (ms / 10) % 10; 131 : 1893 : ms_ptr[2] = '0' + (ms % 10); 132 : 1893 : } 133 : : 134 : : } // namespace vlink