我正在尝试制作一个计算器来确定特定日期开始前的秒数。
我目前能够确定当前的日期和时间,但我不确定如何确定我想要的未来一天开始的秒数(例如星期六)。
我想我可以计算星期六除了星期六之前的天数,然后把它转换成秒,但问题是可能还有额外的时间(我想知道午夜的时间,一天的开始)。
谁知道这怎么可能?
#pragma once
#include <string>
#include <ctime>
class DateTime
{
public:
DateTime();
DateTime(
const time_t& specific_datetime);
const std::string GetWeekDay() const;
const std::string GetMonth() const;
int GetDate() const;
const int GetSecondsUntilNextWeekDay(
const std::string& day_name) const;
private:
const int GetWeekDayNumberFromName(
const std::string& name) const;
tm m_time;
const time_t m_datetime;
DateTime(const DateTime &rhs);
DateTime &operator=(const DateTime &rhs);
};
#include "DateTime.h"
DateTime::DateTime() :
m_datetime(std::time(NULL))
{
localtime_s(&m_time, &m_datetime);
}
DateTime::DateTime(
const time_t& specific_datetime) :
m_datetime(specific_datetime)
{
localtime_s(&m_time, &m_datetime);
}
const std::string DateTime::GetWeekDay() const
{
switch (m_time.tm_wday)
{
case 0:
return "Sunday";
case 1:
return "Monday";
case 2:
return "Tuesday";
case 3:
return "Wednesday";
case 4:
return "Thursday";
case 5:
return "Friday";
case 6:
return "Saturday";
default:
return "Sunday";
}
}
const std::string DateTime::GetMonth() const
{
switch (m_time.tm_mon)
{
case 0:
return "January";
case 1:
return "February";
case 2:
return "March";
case 3:
return "April";
case 4:
return "May";
case 5:
return "June";
case 6:
return "July";
case 7:
return "August";
case 8:
return "September";
case 9:
return "October";
case 10:
return "November";
case 11:
return "December";
default:
return "January";
}
}
int DateTime::GetDate() const
{
return m_time.tm_mday;
}
int DateTime::GetYear() const
{
return 1900 + m_time.tm_year;
}
const int DateTime::GetSecondsUntilNextWeekDay(
const std::string& day_name) const
{
// Calculate how many seconds left for today...
const int todays_hours_left = 23 - m_time.tm_hour;
const int todays_minutes_left = (todays_hours_left * 60) + (59 - m_time.tm_min);
const int todays_seconds_left = (todays_minutes_left * 60) + (59 - m_time.tm_sec);
int overlap_seconds = 0;
// Calculate how many days until the desired date.
int current_day_number = m_time.tm_wday;
const int desired_day_number = GetWeekDayNumberFromName(day_name);
if (desired_day_number >= 0)
{
if (desired_day_number <= current_day_number)
{
// Find out how many days left in the week, add them to how many days until the today.
const int max_day = 6;
const int days_remaining = max_day - current_day_number;
overlap_seconds = (days_remaining * 24 * 60 * 60);
current_day_number = 0;
}
const int days_left = desired_day_number - current_day_number;
const int hours_left = days_left * 24;
const int minutes_left = hours_left * 60;
const int seconds_left = (minutes_left * 60) - (86400 - todays_seconds_left) + overlap_seconds;
return seconds_left;
}
return -1;
}
const int DateTime::GetWeekDayNumberFromName(
const std::string& name) const
{
if (name == "Sunday")
{
return 0;
}
else if (name == "Monday")
{
return 1;
}
else if (name == "Tuesday")
{
return 2;
}
else if (name == "Wednesday")
{
return 3;
}
else if (name == "Thursday")
{
return 4;
}
else if (name == "Friday")
{
return 5;
}
else if (name == "Saturday")
{
return 6;
}
return -1;
}
#include <iostream>
#include "DateTime.h"
int main()
{
DateTime date_time;
const int seconds = date_time.GetSecondsUntilNextWeekDay("Monday");
std::cout << "Seconds Till Date: " << seconds;
}
我希望如果我想知道从当前时间(星期三晚上9点)到星期四开始多长时间,它将返回3小时或10800秒(无论是工作还是工作)。
这个问题有几个微妙的问题:
通过阅读问题中的代码,似乎“一天的开始”由计算机的本地时区设置定义。
我测试了问题中给出的代码,使用“America / New_York”作为具有3个输入对的本地时区:
这是计算连续3周的星期六晚上和星期一开始之间的时间,由于夏令时生效,中间一周跨越UTC偏移变化。
问题中的代码为所有输入对提供7074s。用hh:mm:ss格式,即01:57:54。这是正确答案大约1天,对于第1和第3对输入对是93475s,或1天和7075s,或1天和01:57:55。
对于第二种情况的正确答案,因为星期日只有23小时,减少1小时,或89875秒。
我没有跟踪问题中代码中的所有问题,但似乎至少有这3个问题:
Howard Hinnant's free, open-source, time zone library1可用于纠正这些问题:
#include "date/tz.h"
#include <chrono>
#include <iostream>
std::chrono::seconds
GetSecondsUntilNextWeekDay(date::weekday wd,
date::sys_seconds tp =
date::floor<std::chrono::seconds>(std::chrono::system_clock::now()))
{
using namespace std::chrono;
using namespace date;
auto zone = current_zone();
zoned_seconds now = {zone, tp};
auto today_local = floor<days>(now.get_local_time());
weekday today_wd{today_local};
auto delta_days = wd - today_wd;
if (delta_days == days{0} && now.get_local_time() != today_local)
delta_days += weeks{1};
zoned_seconds target_date = {zone, today_local + delta_days};
return target_date.get_sys_time() - now.get_sys_time();
}
int
main()
{
using namespace date;
using namespace std::chrono;
zoned_seconds zt{current_zone(), local_days{March/9/2019} + 22h + 2min + 5s};
std::cout << GetSecondsUntilNextWeekDay(Monday, zt.get_sys_time()) << '\n';
}
此代码通过为输入时间和目标时间(由本地时区定义的目标工作日的开始)创建zoned_seconds
来工作。 zoned_seconds
是zoned_time<Duration>
的专业化,具有秒精度。
zoned_time
是当地时间点和time_zone
的配对。它可以等同地被认为是UTC时间点和time_zone
的配对。在任何一种情况下,可以使用local_time
或sys_time
(sys_time
是UTC)构建,并且可以提取local_time
和sys_time
,它们通过time_zone
相关。
本例中的time_zone
与current_zone()
一起发现,它检测计算机当前的本地时区设置。
qazxsw poi是输入qazxsw poi的配对(qazxsw poi是秒精度now
的别名),以及计算机当前的本地时区。
sys_time
是通过获得sys_seconds
的sys_time
并将其铺设到日精度而发现的日精度today_local
。
当地的local_time
可以直接从now
建造。
local_time
是必须添加到weekday
以达到today_local
目标delta_days
的天数。 today_wd
减法本质上是循环的:它总是在[0,6]范围内产生若干天,并且与工作日的基础编码无关。例如,星期六总是在星期六之后的1天,即使星期六编码为6,星期日编码为0。
如果当前的weekday
与目标wd
相同,并且如果这不是目标weekday
的第一秒,那么我们想要计算到下周同一天的开始。否则weekday
是目标日期,此函数将返回0秒。
给定天数(weekday
)和当天(weekday
),目标日期可以用now
计算。这是一个日精度delta_days
,它将隐式转换为秒精度并指向一天的开始。这与当地时区配对构建today_local
。
现在我们有today_local + delta_days
和local_time
,我们只需要减去它们以获得所需的秒数。这种减法有两种方法:
target_date
。这将测量当地target_date
定义的“日历秒”中的时间。在这个日历中,所有的日子都是24小时。now
。这在减法之前转换为UTC,因此测量“物理秒数”。这将检测上述案例2中的23h星期日。笔记:
local_time
编码,因此大大简化。在我写这篇文章时:
time_zone
输出:
sys_time
1 weekday
现在是C ++ 20规范草案的一部分,稍作修改,例如将它放入std::cout << GetSecondsUntilNextWeekDay(Saturday) << '\n';
。
试试这个,
128459s