gpt4 book ai didi

c++ - 在 C++11/14 中处理儒略日期

转载 作者:IT老高 更新时间:2023-10-28 22:34:46 26 4
gpt4 key购买 nike

最好/最简单的处理方式是什么Julian dates在 C++ 中?我希望能够在儒略日期和公历日期之间进行转换。我有 C++11 和 C++14。可以<chrono>图书馆帮助解决这个问题?

最佳答案

Julian date 之间转换和 std::chrono::system_clock::time_point需要做的第一件事是找出时代之间的差异。
system_clock没有官方纪​​元,但事实上的标准纪元是 1970-01-01 00:00:00 UTC(公历)。为方便起见,声明 Julian date 很方便。纪元方面的proleptic Gregorian calendar .该日历将当前规则向后扩展,并包括第 0 年。这使算术更容易,但必须注意通过减 1 和求反将 BC 年转换为负年(例如 2BC 是第 -1 年)。 Julian date纪元是 -4713-11-24 12:00:00 UTC(粗略地说)。
<chrono>库可以方便地处理这种规模的时间单位。此外,this date library可以方便地在公历日期和 system_clock::time_point 之间转换.找出这两个时代之间的区别很简单:

constexpr
auto
jdiff()
{
using namespace date;
using namespace std::chrono_literals;
return sys_days{jan/1/1970} - (sys_days{nov/24/-4713} + 12h);
}

这将返回 std::chrono::duration以小时为单位。在 C++14 中,这可以是 constexpr我们可以使用计时持续时间文字 12h而不是 std::chrono::hours{12} .

如果您不想使用 date library ,这只是一个恒定的小时数,可以重写为这种更神秘的形式:
constexpr
auto
jdiff()
{
using namespace std::chrono_literals;
return 58574100h;
}

无论你怎么写,效率都是一样的。这只是一个返回常量 58574100 的函数.这也可能是 constexpr全局,但是你必须泄露你的 using 声明,或者决定不使用它们。

接下来创建一个 Julian 日期时钟 ( jdate_clock ) 很方便。由于我们至少需要处理半天这样的单位,而且通常将儒略日期表示为浮点日,所以我将 jdate_clock::time_point从纪元开始的双基天数:
struct jdate_clock
{
using rep = double;
using period = std::ratio<86400>;
using duration = std::chrono::duration<rep, period>;
using time_point = std::chrono::time_point<jdate_clock>;

static constexpr bool is_steady = false;

static time_point now() noexcept
{
using namespace std::chrono;
return time_point{duration{system_clock::now().time_since_epoch()} + jdiff()};
}
};

实现说明:

I converted the return from system_clock::now() to duration immediately to avoid overflow for those systems where system_clock::duration is nanoseconds.


jdate_clock现在是一个完全合规且功能齐全的 <chrono>时钟。例如,我可以找出现在的时间:
std::cout << std::fixed;
std::cout << jdate_clock::now().time_since_epoch().count() << '\n';

只是输出:
2457354.310832

这是一个类型安全的系统 jdate_clock::time_pointsystem_clock::time_point是两种截然不同的类型,您不会意外地在其中执行混合算术。但您仍然可以从 <chrono> 中获得所有丰富的好处。库,例如在您的 jdate_clock::time_point 中添加和减去持续时间.
using namespace std::chrono_literals;
auto jnow = jdate_clock::now();
auto jpm = jnow + 1min;
auto jph = jnow + 1h;
auto tomorrow = jnow + 24h;
auto diff = tomorrow - jnow;
assert(diff == 24h);

但如果我不小心说:
auto tomorrow = system_clock::now() + 24h;
auto diff = tomorrow - jnow;

我会收到这样的错误:
error: invalid operands to binary expression
('std::chrono::time_point<std::chrono::system_clock, std::chrono::duration<long long,
std::ratio<1, 1000000> > >' and 'std::chrono::time_point<jdate_clock, std::chrono::duration<double,
std::ratio<86400, 1> > >')
auto diff = tomorrow - jnow;
~~~~~~~~ ^ ~~~~

英语:你不能减去 jdate_clock::time_point来自 std::chrono::system_clock::time_point .

但有时我 想转换 jdate_clock::time_pointsystem_clock::time_point或相反亦然。为此,可以轻松编写几个辅助函数:
template <class Duration>
constexpr
auto
sys_to_jdate(std::chrono::time_point<std::chrono::system_clock, Duration> tp) noexcept
{
using namespace std::chrono;
static_assert(jdate_clock::duration{jdiff()} < Duration::max(),
"Overflow in sys_to_jdate");
const auto d = tp.time_since_epoch() + jdiff();
return time_point<jdate_clock, decltype(d)>{d};
}

template <class Duration>
constexpr
auto
jdate_to_sys(std::chrono::time_point<jdate_clock, Duration> tp) noexcept
{
using namespace std::chrono;
static_assert(jdate_clock::duration{-jdiff()} > Duration::min(),
"Overflow in jdate_to_sys");
const auto d = tp.time_since_epoch() - jdiff();
return time_point<system_clock, decltype(d)>{d};
}

实现说明:

I've added static range checking which is likely to fire if you use nanoseconds or a 32bit-based minute as a duration in your source time_point.



一般的秘诀是获取 duration由于纪元( duration s 是“时钟中性”),添加或减去纪元之间的偏移量,然后转换 duration进入想要的 time_point .

这些将在两个时钟的 time_point 之间转换s 使用任何精度,都以类型安全的方式。如果它编译,它就可以工作。如果你犯了一个编程错误,它会在编译时出现。有效的示例用途包括:
auto tp = sys_to_jdate(system_clock::now());
tpjdate::time_point除了它具有积分表示,精度与您的 system_clock::duration 相同。是(对我来说是微秒)。预先警告,如果它对你来说是纳秒(gcc),这将溢出,因为纳秒只有 +/- 292 年的范围。

您可以像这样强制精度:
auto tp = sys_to_jdate(time_point_cast<hours>(system_clock::now()));

现在 tp是自 jdate 以来的整数小时数时代。

如果您愿意使用 this date library ,您可以轻松地使用上面的实用程序将浮点儒略日期转换为公历日期,并且具有您想要的任何精度。例如:
using namespace std::chrono;
using namespace date;
std::cout << std::fixed;
auto jtp = jdate_clock::time_point{jdate_clock::duration{2457354.310832}};
auto tp = floor<seconds>(jdate_to_sys(jtp));
std::cout << "Julian date " << jtp.time_since_epoch().count()
<< " is " << tp << " UTC\n";

我们使用我们的 jdate_clock创建一个 jdate_clock::time_point .然后我们使用我们的 jdate_to_sys转换函数来转换 jtpsystem_clock::time_point .这将有一个双倍和一个小时的表示。但这并不重要。重要的是将其转换为您想要的任何表示和精度。我已经用 floor<seconds> 完成了上面的操作.我也可以使用 time_point_cast<seconds>它会做同样的事情。 floor来自 the date library , 总是向负无穷大截断,并且更容易拼写。

这将输出:
Julian date 2457354.310832 is 2015-11-27 19:27:35 UTC

如果我想四舍五入到最近的秒而不是地板,那就是:
auto tp = round<seconds>(jdate_to_sys(jtp));
Julian date 2457354.310832 is 2015-11-27 19:27:36 UTC

或者,如果我想要它到最接近的毫秒:
auto tp = round<milliseconds>(jdate_to_sys(jtp));
Julian date 2457354.310832 is 2015-11-27 19:27:35.885 UTC

更新
floorround上面提到的功能是 Howard Hinnant's date library 的一部分现在也可以在命名空间 std::chrono 下使用作为 C++17 的一部分。

关于c++ - 在 C++11/14 中处理儒略日期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33964461/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com