C++ std::chrono::years存储真的至少有17位吗?

C++ std::chrono::years存储真的至少有17位吗?,c++,chrono,c++20,libc++,C++,Chrono,C++20,Libc++,从 std::chrono::years(从C++20开始) 持续时间 使用libc++,似乎std::chrono::years的下划线存储是short,其符号为16位 std::chrono::years( 30797 ) // yields 32767/01/01 std::chrono::years( 30797 ) + 365d // yields -32768/01/01 apparently UB 是否有打字错误或其他问题 例如: #include <fmt

std::chrono::years(从C++20开始)
持续时间

使用
libc++
,似乎
std::chrono::years
的下划线存储是
short
,其符号为16位

std::chrono::years( 30797 )        // yields  32767/01/01
std::chrono::years( 30797 ) + 365d // yields -32768/01/01 apparently UB
是否有打字错误或其他问题

例如:

#include <fmt/format.h>
#include <chrono>

template <>
struct fmt::formatter<std::chrono::year_month_day> {
  char presentation = 'F';

  constexpr auto parse(format_parse_context& ctx) {
    auto it = ctx.begin(), end = ctx.end();
    if (it != end && *it == 'F') presentation = *it++;

#   ifdef __exception
    if (it != end && *it != '}') {
      throw format_error("invalid format");
    }
#   endif

    return it;
  }

  template <typename FormatContext>
  auto format(const std::chrono::year_month_day& ymd, FormatContext& ctx) {
    int year(ymd.year() );
    unsigned month(ymd.month() );
    unsigned day(ymd.day() );
    return format_to(
        ctx.out(),
        "{:#6}/{:#02}/{:#02}",
        year, month, day);
  }
};

using days = std::chrono::duration<int32_t, std::ratio<86400> >;
using sys_day = std::chrono::time_point<std::chrono::system_clock, std::chrono::duration<int32_t, std::ratio<86400> >>;

template<typename D>
using sys_time = std::chrono::time_point<std::chrono::system_clock, D>;
using sys_day2 = sys_time<days>;

int main()
{
  auto a = std::chrono::year_month_day( 
    sys_day( 
      std::chrono::floor<days>(
        std::chrono::hours( (1<<23) - 1 ) 
      )
    )
  );

  auto b = std::chrono::year_month_day( 
    sys_day( 
      std::chrono::floor<days>(
        std::chrono::minutes( (1l<<29) - 1 ) 
      )
    )
  );

  auto c = std::chrono::year_month_day( 
    sys_day( 
      std::chrono::floor<days>(
        std::chrono::seconds( (1l<<35) - 1 ) 
      )
    )
  );

  auto e = std::chrono::year_month_day( 
    sys_day( 
      std::chrono::floor<days>(
        std::chrono::days( (1<<25) - 1 ) 
      )
    )
  );

  auto f = std::chrono::year_month_day( 
    sys_day( 
      std::chrono::floor<days>(
        std::chrono::weeks( (1<<22) - 1 ) 
      )
    )
  );

  auto g = std::chrono::year_month_day( 
    sys_day( 
      std::chrono::floor<days>(
        std::chrono::months( (1<<20) - 1 ) 
      )
    )
  );

  auto h = std::chrono::year_month_day( 
    sys_day( 
      std::chrono::floor<days>(
        std::chrono::years( 30797 ) // 0x7FFF - 1970
      )
    )
  );

  auto i = std::chrono::year_month_day( 
    sys_day( 
      std::chrono::floor<days>(
        std::chrono::years( 30797 ) // 0x7FFF - 1970
      ) + std::chrono::days(365)
    )
  );

  fmt::print("Calendar limit by duration's underlining storage:\n"
             "23 bit hour       : {:F}\n"
             "29 bit minute     : {:F}\n"
             "35 bit second     : {:F}\n"
             "25 bit days       : {:F}\n"
             "22 bit week       : {:F}\n"
             "20 bit month      : {:F}\n"
             "16? bit year      : {:F}\n"
             "16? bit year+365d : {:F}\n"
             , a, b, c, e, f, g, h, i);
}
#包括
#包括
模板
结构fmt::格式化程序{
字符表示='F';
constexpr自动解析(格式解析上下文和ctx){
auto it=ctx.begin(),end=ctx.end();
如果(it!=end&&*it='F')表示=*it++;
#ifdef_u异常
如果(it!=end&&*it!='}'){
抛出格式错误(“无效格式”);
}
#恩迪夫
归还它;
}
模板
自动格式(常数std::chrono::年、月、日和ymd、FormatContext和ctx){
国际年(ymd.year());
未签名月份(ymd.month());
未签名日(ymd.day());
将格式_返回到(
ctx.out(),
"{:#6}/{:#02}/{:#02}",
年、月、日);
}
};
使用天数=标准::计时::持续时间;
使用sys_day=std::chrono::time_point;
模板
使用sys\u time=std::chrono::time\u点;
使用sys_day2=sys_time;
int main()
{
自动a=std::时钟::年\月\日(
系统日(
标准::计时::楼层(

std::chrono::hours((1参考文章是。如果libc++使用较小的类型,那么这似乎是libc++中的一个错误。

我将逐一分析这个示例:

  auto a = std::chrono::year_month_day( 
    sys_days( 
      std::chrono::floor<days>(
        std::chrono::years(0) 
        + std::chrono::days( 365 )
      )
    )
  );
子表达式
年{0}
是一个
持续时间
,其
期间
等于
比率
,值等于
0
。请注意,
年{1}
,表示为浮点
,正好是365.2425。这是民事年度的平均长度


子表达式
days{365}
是一个
持续时间
,其
期间
等于
比率,但添加另一个
,可能不会不必要地增加
年/月/日
向量?这
至少17位
可以不算作正常文本吗?@sandthorn
年/月/日
包含
,而不是
的表示形式不要求为16位,尽管类型
被用作说明。
定义中的17位部分是规范性的,因为它不被标记为说明。坦率地说,它至少包含17位,然后不需要它是毫无意义的。啊
似乎是
int
的确。=>我认为这支持
至少17位
实现。你介意编辑你的答案吗?结果是std::chrono::years实际上是int,std::chrono::year任意最大值为32767。@sandthorn答案是正确,我不明白为什么需要编辑它。
year
range:
years
range:。
year
是“名称”“年”是一个计时持续时间,与“年”不同。一个人可以减去两个“年”
,结果类型为“年”
,“年”
,“年”
需要能够保存
year::max()-year::min()
的结果+365d
无法编译。
年{30797}+天{365}
的结果是204528013,单位为216。这只是添加了两个持续时间。禁止它意味着禁止
小时{2}+秒{5}
。我猜你把日历组件和持续时间类型混淆了,因为它们的名称非常相似。这里有一条一般规则:
持续时间
名称是复数:
。日历组件名称是单数:
year{30797}+day{365}
是编译时错误。
year{2020}
是今年。
year{2020}
是一个长达2020年的持续时间。很好的解释。我担心时间计算。如果我看到
year{14700}+0s+days{0}
在代码库中,我不知道
0s
在那里做什么,它有多重要。有没有其他更明确的方法?比如
duration\u cast(years{14700})+days{0}
更好?
duration\u cast
会更糟,因为使用
duration\u cast
进行非截断转换是不好的。截断转换可能会导致逻辑错误,最好只使用“大锤”当您需要时,您可以轻松发现代码中的截断转换。您可以创建一个自定义的持续时间:
使用llyears=duration;
,然后改用它。但最好的办法可能是思考您试图完成的任务,并质疑您是否以正确的方式进行。例如,您是否ally需要1万年的时间刻度的日精度?民用日历在4000年中只能精确到1天左右。也许浮点千年是一个更好的单位?澄清:chrono对民用日历的建模精确到-32767/1/1到32767/12/31。民用日历的精度与o对太阳系的建模在4000年中只有大约1天。这实际上取决于用例,我目前很难想出一个激励性的用例来添加
。这实际上是将365.2425天的倍数添加到某个整数天中。通常如果你想做计时按月或年的顺序进行逻辑计算,这是为了模拟一些物理或生物学。也许这篇关于将
months
添加到
system\u clock::time\u point
的不同方法的文章将有助于澄清这两种计算之间的差异:
year_month_day a = sys_days{floor<days>(years{0} + days{365})};
year_month_day a = sys_days{} + days{365};
year_month_day j = sys_days{floor<days>(years{14699} + days{0})};
year_month_day j = (1970y + years{14700})/1/1;
years{14700} + 0s + days{0}
463'887'194'400s == 14700 * 365.2425 * 86400
year_month_day j = sys_days{floor<days>(years{14700})} + days{0};
year_month_day j = (1970y + years{14700})/1/1;