mirror of
https://github.com/fmtlib/fmt.git
synced 2025-04-18 11:42:22 +00:00
Improve ISO week-base-year formatter
This commit is contained in:
parent
fbaaa5906b
commit
79c00ad8f2
@ -1425,10 +1425,37 @@ template <typename FormatContext, typename OutputIt> struct tm_formatter {
|
|||||||
}
|
}
|
||||||
return {q, r};
|
return {q, r};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Algorithm:
|
||||||
|
// https://en.wikipedia.org/wiki/ISO_week_date#Calculating_the_week_number_from_a_month_and_day_of_the_month_or_ordinal_date
|
||||||
|
struct iso_weak {
|
||||||
|
int year;
|
||||||
|
int woy;
|
||||||
|
};
|
||||||
|
auto tm_iso_year_weaks(int year) -> int {
|
||||||
|
int p = (year + year / 4 - year / 100 + year / 400) % daysperweek;
|
||||||
|
int year_1 = year - 1;
|
||||||
|
int p_1 = (year_1 + year_1 / 4 - year_1 / 100 + year_1 / 400) % daysperweek;
|
||||||
|
return 52 + ((p == 4 || p_1 == 3) ? 1 : 0);
|
||||||
|
}
|
||||||
|
auto tm_iso_weak() -> iso_weak {
|
||||||
|
auto year = tm_year();
|
||||||
|
int w = (tm.tm_yday + 10 - (tm.tm_wday == 0 ? daysperweek : tm.tm_wday)) /
|
||||||
|
daysperweek;
|
||||||
|
if (w < 1) {
|
||||||
|
return {year - 1, tm_iso_year_weaks(year - 1)};
|
||||||
|
} else if (w > tm_iso_year_weaks(year)) {
|
||||||
|
return {year + 1, 1};
|
||||||
|
} else {
|
||||||
|
return {year, w};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto tm_hour12() const -> decltype(tm.tm_hour) {
|
auto tm_hour12() const -> decltype(tm.tm_hour) {
|
||||||
auto hour = tm.tm_hour % 12;
|
auto hour = tm.tm_hour % 12;
|
||||||
return hour == 0 ? 12 : hour;
|
return hour == 0 ? 12 : hour;
|
||||||
}
|
}
|
||||||
|
|
||||||
void write1(size_t value) { *out++ = detail::digits2(value)[1]; }
|
void write1(size_t value) { *out++ = detail::digits2(value)[1]; }
|
||||||
void write2(size_t value) {
|
void write2(size_t value) {
|
||||||
out = std::copy_n(detail::digits2(value), 2, out);
|
out = std::copy_n(detail::digits2(value), 2, out);
|
||||||
@ -1575,19 +1602,16 @@ template <typename FormatContext, typename OutputIt> struct tm_formatter {
|
|||||||
}
|
}
|
||||||
void on_iso_week_of_year(numeric_system ns) {
|
void on_iso_week_of_year(numeric_system ns) {
|
||||||
if (ns == numeric_system::standard) {
|
if (ns == numeric_system::standard) {
|
||||||
// TODO: Optimization
|
write2(detail::to_unsigned(tm_iso_weak().woy));
|
||||||
format_localized('V');
|
|
||||||
} else {
|
} else {
|
||||||
format_localized('V', 'O');
|
format_localized('V', 'O');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void on_iso_week_based_year() {
|
void on_iso_week_based_year() {
|
||||||
// TODO: Optimization
|
out = detail::write<char_type>(out, tm_iso_weak().year);
|
||||||
format_localized('G');
|
|
||||||
}
|
}
|
||||||
void on_iso_week_based_year_last2() {
|
void on_iso_week_based_year_last2() {
|
||||||
// TODO: Optimization
|
write2(detail::to_unsigned(tm_split_year(tm_iso_weak().year).lower));
|
||||||
format_localized('g');
|
|
||||||
}
|
}
|
||||||
void on_day_of_year() {
|
void on_day_of_year() {
|
||||||
auto yday = tm.tm_yday + 1;
|
auto yday = tm.tm_yday + 1;
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
#include "fmt/chrono.h"
|
#include "fmt/chrono.h"
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "gtest-extra.h" // EXPECT_THROW_MSG
|
#include "gtest-extra.h" // EXPECT_THROW_MSG
|
||||||
@ -57,6 +59,42 @@ TEST(chrono_test, format_tm) {
|
|||||||
EXPECT_EQ(fmt::format("{:%D}", tm), "04/25/16");
|
EXPECT_EQ(fmt::format("{:%D}", tm), "04/25/16");
|
||||||
EXPECT_EQ(fmt::format("{:%F}", tm), "2016-04-25");
|
EXPECT_EQ(fmt::format("{:%F}", tm), "2016-04-25");
|
||||||
EXPECT_EQ(fmt::format("{:%T}", tm), "11:22:33");
|
EXPECT_EQ(fmt::format("{:%T}", tm), "11:22:33");
|
||||||
|
|
||||||
|
// for week on the year
|
||||||
|
// https://www.cl.cam.ac.uk/~mgk25/iso-time.html
|
||||||
|
std::vector<std::string> str_tm_list = {
|
||||||
|
"1975-12-29", // W01
|
||||||
|
"1977-01-02", // W53
|
||||||
|
"1999-12-27", // W52
|
||||||
|
"1999-12-31", // W52
|
||||||
|
"2000-01-01", // W52
|
||||||
|
"2000-01-02", // W52
|
||||||
|
"2000-01-03", // W1
|
||||||
|
};
|
||||||
|
std::vector<std::string> spec_list = {"%G", "%g", "%V"};
|
||||||
|
for (const auto& str_tm : str_tm_list) {
|
||||||
|
tm = std::tm();
|
||||||
|
|
||||||
|
// GCC 4 does not support std::get_time
|
||||||
|
// MSVC dows not support POSIX strptime
|
||||||
|
#ifdef _WIN32
|
||||||
|
std::istringstream ss(str_tm);
|
||||||
|
ss >> std::get_time(&tm, "%Y-%m-%d");
|
||||||
|
#else
|
||||||
|
strptime(str_tm.c_str(), "%Y-%m-%d", &tm);
|
||||||
|
#endif
|
||||||
|
// Because std::get_time doesn't calculate tm_yday, tm_wday, etc.
|
||||||
|
tm.tm_isdst = 0;
|
||||||
|
auto t = std::mktime(&tm);
|
||||||
|
tm = *std::localtime(&t);
|
||||||
|
|
||||||
|
for (const auto& spec : spec_list) {
|
||||||
|
char output[256] = {};
|
||||||
|
std::strftime(output, sizeof(output), spec.c_str(), &tm);
|
||||||
|
auto fmt_spec = std::string("{:").append(spec).append("}");
|
||||||
|
EXPECT_EQ(output, fmt::format(fmt::runtime(fmt_spec), tm));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MSVC:
|
// MSVC:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user