https://www.timeanddate.com/date/weekday.html tính toán các sự kiện khác nhau về một ngày trong năm, ví dụ:
Cho một ngày tùy ý, làm thế nào những con số này có thể được tính toán với đặc tả chrono C ++ 20 ?
https://www.timeanddate.com/date/weekday.html tính toán các sự kiện khác nhau về một ngày trong năm, ví dụ:
Cho một ngày tùy ý, làm thế nào những con số này có thể được tính toán với đặc tả chrono C ++ 20 ?
Câu trả lời:
Điều này là khá dễ dàng với đặc điểm kỹ thuật chrono C ++ 20 . Dưới đây tôi hiển thị một hàm nhập ngày tùy ý và in thông tin này sang cout
. Mặc dù tại thời điểm viết bài này, đặc tả chrono của C ++ 20 chưa được vận chuyển, nhưng nó được xấp xỉ bởi một thư viện mã nguồn mở miễn phí . Vì vậy, bạn có thể thử nghiệm với nó ngay hôm nay và thậm chí đưa nó vào các ứng dụng vận chuyển miễn là bạn áp dụng C ++ 11 trở lên.
Câu trả lời này sẽ có dạng hàm:
void info(std::chrono::sys_days sd);
sys_days
là một ngày chính xác time_point
trong system_clock
gia đình. Điều đó có nghĩa là nó chỉ đơn giản là một số ngày kể từ 1970-01-01 00:00:00 UTC. Bí danh loại sys_days
là mới với C ++ 20, nhưng loại cơ bản đã có sẵn kể từ C ++ 11 ( time_point<system_clock, duration<int, ratio<86400>>>
). Nếu bạn sử dụng thư viện xem trước C ++ 20 nguồn mở , thì sys_days
có namespace date
.
Mã dưới đây giả định hàm-local:
using namespace std;
using namespace std::chrono;
để giảm tính dài dòng. Nếu bạn đang thử nghiệm thư viện xem trước C ++ 20 nguồn mở , cũng giả sử:
using namespace date;
Tiêu đề
Để xuất hai dòng đầu tiên là đơn giản:
cout << format("{:%d %B %Y is a %A}\n", sd)
<< "\nAdditional facts\n";
Chỉ cần lấy ngày sd
và sử dụng format
với cờ strftime
/ put_time
cờ quen thuộc để in ra ngày và văn bản. Các C ++ 20 thư viện xem trước mã nguồn mở vẫn chưa tích hợp các thư viện fmt , và do đó sử dụng các chuỗi định dạng một chút thay đổi "%d %B %Y is a %A\n"
.
Điều này sẽ xuất ra (ví dụ):
26 December 2019 is a Thursday
Additional facts
Kết quả trung gian chung được tính một lần
Phần này của hàm được viết sau cùng, bởi vì người ta chưa biết tính toán nào sẽ cần nhiều lần. Nhưng một khi bạn biết, đây là cách tính toán chúng:
year_month_day ymd = sd;
auto y = ymd.year();
auto m = ymd.month();
weekday wd{sd};
sys_days NewYears = y/1/1;
sys_days LastDayOfYear = y/12/31;
Chúng ta sẽ cần các trường năm và tháng sd
và weekday
(ngày trong tuần). Đó là hiệu quả để tính toán chúng một lần và mãi mãi theo cách này. Chúng tôi cũng sẽ cần (nhiều lần) những ngày đầu tiên và cuối cùng của năm hiện tại. Thật khó có thể nói vào thời điểm này, nhưng nó là hiệu quả để lưu trữ các giá trị như kiểu sys_days
như sử dụng tiếp theo của họ là duy nhất có số học ngày theo định hướng sys_days
là rất hiệu quả tại (tốc độ sub-nano giây).
Sự thật 1: số ngày trong năm và số ngày còn lại trong năm
auto dn = sd - NewYears + days{1};
auto dl = LastDayOfYear - sd;
cout << "* It is day number " << dn/days{1} << " of the year, "
<< dl/days{1} << " days left.\n";
Điều này in ra số ngày trong năm, với ngày 1 tháng 1 là ngày 1, và sau đó cũng in ra số ngày còn lại trong năm, không bao gồm sd
. Tính toán để làm điều này là tầm thường. Chia từng kết quả days{1}
là một cách để trích xuất số ngày trong dn
và dl
thành một loại tách rời cho mục đích định dạng.
Sự thật 2: Số ngày trong tuần này và tổng số ngày trong năm
sys_days first_wd = y/1/wd[1];
sys_days last_wd = y/12/wd[last];
auto total_wd = (last_wd - first_wd)/weeks{1} + 1;
auto n_wd = (sd - first_wd)/weeks{1} + 1;
cout << format("* It is {:%A} number ", wd) << n_wd << " out of "
<< total_wd << format(" in {:%Y}.\n}", y);
wd
là ngày trong tuần (Thứ Hai đến Chủ nhật) được tính ở đầu bài viết này. Để thực hiện tính toán này, trước tiên chúng ta cần ngày của lần đầu tiên và lần cuối cùng wd
trong năm y
. y/1/wd[1]
là lần đầu tiên wd
vào tháng Giêng, và y/12/wd[last]
là lần cuối cùng wd
vào tháng 12.
Tổng số wd
s trong năm chỉ là số tuần giữa hai ngày này (cộng 1). Biểu thức con last_wd - first_wd
là số ngày giữa hai ngày. Chia kết quả này cho 1 tuần sẽ dẫn đến một loại tích phân giữ số tuần giữa hai ngày.
Số tuần được thực hiện theo cách tương tự như tổng số tuần trừ một bắt đầu bằng ngày hiện tại thay vì cuối cùng wd
của năm : sd - first_wd
.
Sự thật 3: Số ngày trong tuần này và tổng số ngày trong tuần trong tháng
first_wd = y/m/wd[1];
last_wd = y/m/wd[last];
total_wd = (last_wd - first_wd)/weeks{1} + 1;
n_wd = (sd - first_wd)/weeks{1} + 1;
cout << format("* It is {:%A} number }", wd) << n_wd << " out of "
<< total_wd << format(" in {:%B %Y}.\n", y/m);
Điều này hoạt động giống như Fact 2, ngoại trừ chúng tôi bắt đầu với cặp đầu tiên và cuối cùng wd
của cặp tháng y/m
thay vì cả năm.
Sự thật 4: Số ngày trong năm
auto total_days = LastDayOfYear - NewYears + days{1};
cout << format("* Year {:%Y} has ", y) << total_days/days{1} << " days.\n";
Các mã khá nhiều nói cho chính nó.
Fact 5 Số ngày trong tháng
total_days = sys_days{y/m/last} - sys_days{y/m/1} + days{1};
cout << format("* {:%B %Y} has ", y/m) << total_days/days{1} << " days.\n";
Biểu thức y/m/last
là ngày cuối cùng của cặp năm y/m
và tất nhiên y/m/1
là ngày đầu tiên của tháng. Cả hai đều được chuyển đổi để sys_days
có thể trừ đi để có được số ngày giữa chúng. Thêm 1 cho số đếm dựa trên 1.
Sử dụng
info
có thể được sử dụng như thế này:
info(December/26/2019);
hoặc như thế này:
info(floor<days>(system_clock::now()));
Đây là ví dụ đầu ra:
26 December 2019 is a Thursday
Additional facts
* It is day number 360 of the year, 5 days left.
* It is Thursday number 52 out of 52 in 2019.
* It is Thursday number 4 out of 4 in December 2019.
* Year 2019 has 365 days.
* December 2019 has 31 days.
Biên tập
Đối với những người không thích "cú pháp thông thường", có một "cú pháp xây dựng" hoàn chỉnh có thể được sử dụng thay thế.
Ví dụ:
sys_days NewYears = y/1/1;
sys_days first_wd = y/1/wd[1];
sys_days last_wd = y/12/wd[last];
có thể được thay thế bởi:
sys_days NewYears = year_month_day{y, month{1}, day{1}};
sys_days first_wd = year_month_weekday{y, month{1}, weekday_indexed{wd, 1}};
sys_days last_wd = year_month_weekday_last{y, month{12}, weekday_last{wd}};
std::cout << "a*b = " << a*b << "; a^b = " << a^b << '\n';
(may mắn thay, hầu như luôn bị bắt tại thời gian biên dịch, nhưng vẫn gây phiền toái). Vì vậy, tôi nên thận trọng khi sử dụng lạm dụng toán tử phân chia mới này.