Skip to content

Commit

Permalink
[libc++][format] Fixes times before epoch.
Browse files Browse the repository at this point in the history
The number of days should be rounded down, for both positive and
negative times since epoch. The original code truncated, which is
correct for positive values, but wrong for negative values.

Depends on D138826

Reviewed By: #libc, ldionne

Differential Revision: https://reviews.llvm.org/D154865
  • Loading branch information
mordante committed Jul 18, 2023
1 parent 1be4db7 commit b9f3d24
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 1 deletion.
2 changes: 1 addition & 1 deletion libcxx/include/__chrono/convert_to_tm.h
Expand Up @@ -78,7 +78,7 @@ _LIBCPP_HIDE_FROM_ABI _Tm __convert_to_tm(const _Date& __date, chrono::weekday _

template <class _Tm, class _Duration>
_LIBCPP_HIDE_FROM_ABI _Tm __convert_to_tm(const chrono::sys_time<_Duration> __tp) {
chrono::sys_days __days = chrono::time_point_cast<chrono::days>(__tp);
chrono::sys_days __days = chrono::floor<chrono::days>(__tp);
chrono::year_month_day __ymd{__days};

_Tm __result = std::__convert_to_tm<_Tm>(chrono::year_month_day{__ymd}, chrono::weekday{__days});
Expand Down
20 changes: 20 additions & 0 deletions libcxx/test/std/time/time.syn/formatter.file_time.pass.cpp
Expand Up @@ -49,10 +49,30 @@ static void test_no_chrono_specs() {
std::locale::global(std::locale(LOCALE_fr_FR_UTF_8));

// Non localized output

// [time.syn]
// using nanoseconds = duration<signed integer type of at least 64 bits, nano>;
// using microseconds = duration<signed integer type of at least 55 bits, micro>;
// using milliseconds = duration<signed integer type of at least 45 bits, milli>;
// using seconds = duration<signed integer type of at least 35 bits>;
// using minutes = duration<signed integer type of at least 29 bits, ratio< 60>>;
// using hours = duration<signed integer type of at least 23 bits, ratio<3600>>;
check(SV("1425-08-04 22:06:56"), SV("{}"), file_seconds(-17'179'869'184s)); // Minimum value for 35 bits.
check(SV("1901-12-13 20:45:52"), SV("{}"), file_seconds(-2'147'483'648s));

check(SV("1969-12-31 00:00:00"), SV("{}"), file_seconds(-24h));
check(SV("1969-12-31 06:00:00"), SV("{}"), file_seconds(-18h));
check(SV("1969-12-31 12:00:00"), SV("{}"), file_seconds(-12h));
check(SV("1969-12-31 18:00:00"), SV("{}"), file_seconds(-6h));
check(SV("1969-12-31 23:59:59"), SV("{}"), file_seconds(-1s));

check(SV("1970-01-01 00:00:00"), SV("{}"), file_seconds(0s));
check(SV("2000-01-01 00:00:00"), SV("{}"), file_seconds(946'684'800s));
check(SV("2000-01-01 01:02:03"), SV("{}"), file_seconds(946'688'523s));

check(SV("2038-01-19 03:14:07"), SV("{}"), file_seconds(2'147'483'647s));
check(SV("2514-05-30 01:53:03"), SV("{}"), file_seconds(17'179'869'183s)); // Maximum value for 35 bits.

check(SV("2000-01-01 01:02:03.123"), SV("{}"), file_time<std::chrono::milliseconds>(946'688'523'123ms));

std::locale::global(std::locale::classic());
Expand Down
21 changes: 21 additions & 0 deletions libcxx/test/std/time/time.syn/formatter.local_time.pass.cpp
Expand Up @@ -42,10 +42,31 @@ static void test_no_chrono_specs() {
std::locale::global(std::locale(LOCALE_fr_FR_UTF_8));

// Non localized output

// [time.syn]
// using nanoseconds = duration<signed integer type of at least 64 bits, nano>;
// using microseconds = duration<signed integer type of at least 55 bits, micro>;
// using milliseconds = duration<signed integer type of at least 45 bits, milli>;
// using seconds = duration<signed integer type of at least 35 bits>;
// using minutes = duration<signed integer type of at least 29 bits, ratio< 60>>;
// using hours = duration<signed integer type of at least 23 bits, ratio<3600>>;
check(
SV("1425-08-04 22:06:56"), SV("{}"), std::chrono::local_seconds(-17'179'869'184s)); // Minimum value for 35 bits.
check(SV("1901-12-13 20:45:52"), SV("{}"), std::chrono::local_seconds(-2'147'483'648s));

check(SV("1969-12-31 00:00:00"), SV("{}"), std::chrono::local_seconds(-24h));
check(SV("1969-12-31 06:00:00"), SV("{}"), std::chrono::local_seconds(-18h));
check(SV("1969-12-31 12:00:00"), SV("{}"), std::chrono::local_seconds(-12h));
check(SV("1969-12-31 18:00:00"), SV("{}"), std::chrono::local_seconds(-6h));
check(SV("1969-12-31 23:59:59"), SV("{}"), std::chrono::local_seconds(-1s));

check(SV("1970-01-01 00:00:00"), SV("{}"), std::chrono::local_seconds(0s));
check(SV("2000-01-01 00:00:00"), SV("{}"), std::chrono::local_seconds(946'684'800s));
check(SV("2000-01-01 01:02:03"), SV("{}"), std::chrono::local_seconds(946'688'523s));

check(SV("2038-01-19 03:14:07"), SV("{}"), std::chrono::local_seconds(2'147'483'647s));
check(SV("2514-05-30 01:53:03"), SV("{}"), std::chrono::local_seconds(17'179'869'183s)); // Maximum value for 35 bits.

check(SV("2000-01-01 01:02:03.123"), SV("{}"), std::chrono::local_time<std::chrono::milliseconds>(946'688'523'123ms));

std::locale::global(std::locale::classic());
Expand Down
20 changes: 20 additions & 0 deletions libcxx/test/std/time/time.syn/formatter.sys_time.pass.cpp
Expand Up @@ -42,10 +42,30 @@ static void test_no_chrono_specs() {
std::locale::global(std::locale(LOCALE_fr_FR_UTF_8));

// Non localized output

// [time.syn]
// using nanoseconds = duration<signed integer type of at least 64 bits, nano>;
// using microseconds = duration<signed integer type of at least 55 bits, micro>;
// using milliseconds = duration<signed integer type of at least 45 bits, milli>;
// using seconds = duration<signed integer type of at least 35 bits>;
// using minutes = duration<signed integer type of at least 29 bits, ratio< 60>>;
// using hours = duration<signed integer type of at least 23 bits, ratio<3600>>;
check(SV("1425-08-04 22:06:56"), SV("{}"), std::chrono::sys_seconds(-17'179'869'184s)); // Minimum value for 35 bits.
check(SV("1901-12-13 20:45:52"), SV("{}"), std::chrono::sys_seconds(-2'147'483'648s));

check(SV("1969-12-31 00:00:00"), SV("{}"), std::chrono::sys_seconds(-24h));
check(SV("1969-12-31 06:00:00"), SV("{}"), std::chrono::sys_seconds(-18h));
check(SV("1969-12-31 12:00:00"), SV("{}"), std::chrono::sys_seconds(-12h));
check(SV("1969-12-31 18:00:00"), SV("{}"), std::chrono::sys_seconds(-6h));
check(SV("1969-12-31 23:59:59"), SV("{}"), std::chrono::sys_seconds(-1s));

check(SV("1970-01-01 00:00:00"), SV("{}"), std::chrono::sys_seconds(0s));
check(SV("2000-01-01 00:00:00"), SV("{}"), std::chrono::sys_seconds(946'684'800s));
check(SV("2000-01-01 01:02:03"), SV("{}"), std::chrono::sys_seconds(946'688'523s));

check(SV("2038-01-19 03:14:07"), SV("{}"), std::chrono::sys_seconds(2'147'483'647s));
check(SV("2514-05-30 01:53:03"), SV("{}"), std::chrono::sys_seconds(17'179'869'183s)); // Maximum value for 35 bits.

check(SV("2000-01-01 01:02:03.123"), SV("{}"), std::chrono::sys_time<std::chrono::milliseconds>(946'688'523'123ms));

std::locale::global(std::locale::classic());
Expand Down

0 comments on commit b9f3d24

Please sign in to comment.