Survey times. Refactor Chrono stuff. All times UTC, unless explicitly mentioned
Survey is set to be every 6 months, but you also get one in the first 10 days.
MODIFY
include/vcpkg/base/chrono.h
include/vcpkg/base/chrono.h
@@ -55,6 +55,8 @@ namespace vcpkg::Chrono
constexpr CTime() noexcept : m_tm {0} {}
explicit constexpr CTime(tm t) noexcept : m_tm {t} {}
+ CTime add_hours(const int hours) const;
+
std::string to_string() const;
std::chrono::system_clock::time_point to_time_point() const;
@@ -62,4 +64,6 @@ namespace vcpkg::Chrono
private:
mutable tm m_tm;
};
+
+ tm get_current_date_time_local();
}

MODIFY
include/vcpkg/base/system.h
include/vcpkg/base/system.h
namespace vcpkg::System
{
- tm get_current_date_time();
-
fs::path get_exe_path_of_current_process();
struct CMakeVariable

MODIFY
src/vcpkg.cpp
src/vcpkg.cpp
using namespace vcpkg;
+// 24 hours/day * 30 days/month * 6 months
+static constexpr int SURVEY_INTERVAL_IN_HOURS = 24 * 30 * 6;
+
+// Initial survey appears after 10 days. Therefore, subtract 24 hours/day * 10 days
+static constexpr int SURVEY_INITIAL_OFFSET_IN_HOURS = SURVEY_INTERVAL_IN_HOURS - 24 * 10;
+
void invalid_command(const std::string& cmd)
{
System::println(System::Color::error, "invalid command: %s", cmd);
@@ -120,12 +126,12 @@ static void inner(const VcpkgCmdArguments& args)
auto maybe_surveydate = Chrono::CTime::parse(surveydate);
if (auto p_surveydate = maybe_surveydate.get())
{
- auto delta = std::chrono::system_clock::now() - p_surveydate->to_time_point();
- // 24 hours/day * 30 days/month
- if (std::chrono::duration_cast<std::chrono::hours>(delta).count() > 24 * 30)
+ const auto now = Chrono::CTime::get_current_date_time().value_or_exit(VCPKG_LINE_INFO);
+ const auto delta = now.to_time_point() - p_surveydate->to_time_point();
+ if (std::chrono::duration_cast<std::chrono::hours>(delta).count() > SURVEY_INTERVAL_IN_HOURS)
{
std::default_random_engine generator(
- static_cast<unsigned int>(std::chrono::system_clock::now().time_since_epoch().count()));
+ static_cast<unsigned int>(now.to_time_point().time_since_epoch().count()));
std::uniform_int_distribution<int> distribution(1, 4);
if (distribution(generator) == 1)
@@ -214,7 +220,9 @@ static void load_config()
if (config.last_completed_survey.empty())
{
- config.last_completed_survey = config.user_time;
+ const auto now = Chrono::CTime::parse(config.user_time).value_or_exit(VCPKG_LINE_INFO);
+ const Chrono::CTime offset = now.add_hours(-SURVEY_INITIAL_OFFSET_IN_HOURS);
+ config.last_completed_survey = offset.to_string();
}
GlobalState::g_surveydate.lock()->assign(config.last_completed_survey);

MODIFY
src/vcpkg/base/chrono.cpp
src/vcpkg/base/chrono.cpp
namespace vcpkg::Chrono
{
+ static std::time_t get_current_time_as_time_since_epoch()
+ {
+ using std::chrono::system_clock;
+ return system_clock::to_time_t(system_clock::now());
+ }
+
+ static std::time_t utc_mktime(tm* time_ptr)
+ {
+#if defined(_WIN32)
+ return _mkgmtime(time_ptr);
+#else
+ return timegm(time_ptr);
+#endif
+ }
+
+ static tm to_local_time(const std::time_t& t)
+ {
+ tm parts {};
+#if defined(_WIN32)
+ localtime_s(&parts, &t);
+#else
+ parts = *localtime(&t);
+#endif
+ return parts;
+ }
+
+ static Optional<tm> to_utc_time(const std::time_t& t)
+ {
+ tm parts {};
+#if defined(_WIN32)
+ const errno_t err = gmtime_s(&parts, &t);
+ if (err)
+ {
+ return nullopt;
+ }
+#else
+ auto null_if_failed = gmtime_r(&t, &parts);
+ if (null_if_failed == nullptr)
+ {
+ return nullopt;
+ }
+#endif
+ return parts;
+ }
+
+ static tm date_plus_hours(tm* date, const int hours)
+ {
+ using namespace std::chrono_literals;
+ static constexpr std::chrono::seconds SECONDS_IN_ONE_HOUR =
+ std::chrono::duration_cast<std::chrono::seconds>(1h);
+
+ const std::time_t date_in_seconds = utc_mktime(date) + (hours * SECONDS_IN_ONE_HOUR.count());
+ return to_utc_time(date_in_seconds).value_or_exit(VCPKG_LINE_INFO);
+ }
+
static std::string format_time_userfriendly(const std::chrono::nanoseconds& nanos)
{
using std::chrono::duration_cast;
@@ -63,30 +118,14 @@ namespace vcpkg::Chrono
Optional<CTime> CTime::get_current_date_time()
{
- CTime ret;
-
-#if defined(_WIN32)
- struct _timeb timebuffer;
-
- _ftime_s(&timebuffer);
-
- const errno_t err = gmtime_s(&ret.m_tm, &timebuffer.time);
-
- if (err)
+ const std::time_t ct = get_current_time_as_time_since_epoch();
+ const Optional<tm> opt = to_utc_time(ct);
+ if (auto p_tm = opt.get())
{
- return nullopt;
+ return CTime {*p_tm};
}
-#else
- time_t now = {0};
- time(&now);
- auto null_if_failed = gmtime_r(&now, &ret.m_tm);
- if (null_if_failed == nullptr)
- {
- return nullopt;
- }
-#endif
- return ret;
+ return nullopt;
}
Optional<CTime> CTime::parse(CStringView str)
@@ -111,10 +150,13 @@ namespace vcpkg::Chrono
ret.m_tm.tm_year -= 1900;
if (ret.m_tm.tm_mon < 1) return nullopt;
ret.m_tm.tm_mon -= 1;
- mktime(&ret.m_tm);
+ utc_mktime(&ret.m_tm);
+
return ret;
}
+ CTime CTime::add_hours(const int hours) const { return CTime {date_plus_hours(&this->m_tm, hours)}; }
+
std::string CTime::to_string() const
{
std::array<char, 80> date {};
@@ -123,7 +165,13 @@ namespace vcpkg::Chrono
}
std::chrono::system_clock::time_point CTime::to_time_point() const
{
- const time_t t = mktime(&m_tm);
+ const time_t t = utc_mktime(&m_tm);
return std::chrono::system_clock::from_time_t(t);
}
+
+ tm get_current_date_time_local()
+ {
+ const std::time_t now_time = get_current_time_as_time_since_epoch();
+ return Chrono::to_local_time(now_time);
+ }
}

MODIFY
src/vcpkg/base/system.cpp
src/vcpkg/base/system.cpp
namespace vcpkg::System
{
- tm get_current_date_time()
- {
- using std::chrono::system_clock;
- std::time_t now_time = system_clock::to_time_t(system_clock::now());
- tm parts{};
-#if defined(_WIN32)
- localtime_s(&parts, &now_time);
-#else
- parts = *localtime(&now_time);
-#endif
- return parts;
- }
-
fs::path get_exe_path_of_current_process()
{
#if defined(_WIN32)

MODIFY
src/vcpkg/commands.exportifw.cpp
src/vcpkg/commands.exportifw.cpp
@@ -13,7 +13,7 @@ namespace vcpkg::Export::IFW
static std::string create_release_date()
{
- const tm date_time = System::get_current_date_time();
+ const tm date_time = Chrono::get_current_date_time_local();
// Format is: YYYY-mm-dd
// 10 characters + 1 null terminating character will be written for a total of 11 chars

MODIFY
src/vcpkg/export.cpp
src/vcpkg/export.cpp
@@ -108,7 +108,7 @@ namespace vcpkg::Export
static std::string create_export_id()
{
- const tm date_time = System::get_current_date_time();
+ const tm date_time = Chrono::get_current_date_time_local();
// Format is: YYYYmmdd-HHMMSS
// 15 characters + 1 null terminating character will be written for a total of 16 chars

Survey times. Refactor Chrono stuff. All times UTC, unless explicitly mentioned

Survey is set to be every 6 months, but you also get one in the first 10 days.