Как Алан Бертлс указывает в комментариях, это легко сделать на C ++ 20:
#include <chrono>
int
floor_to_month_utc(int timestamp)
{
using namespace std::chrono;
sys_seconds tp{seconds{timestamp}};
year_month_day ymd = floor<days>(tp);
sys_seconds result = sys_days{ymd.year()/ymd.month()/1};
return result.time_since_epoch().count();
}
Пояснение:
Первый шаг - поместить ввод в систему типов <chrono>
. Подразумевается, что timestamp
- это количество секунд с 1970-01-01 00:00:00 UT C (исключая дополнительные секунды). Это также известно как Unix Time .
std::chrono::sys_seconds
- это тип C ++ 20, который соответствует этой семантике. Итак, sys_seconds tp{seconds{timestamp}};
сначала преобразует timestamp
в длительность seconds
, а затем в time_point
sys_seconds
.
Далее нужно понимать, что это календарное вычисление , а не хронологическое вычисление. Используемый календарь - это гражданский календарь, который смоделирован на C ++ 20 <chrono>
. Итак, следующий шаг - преобразовать time_point
tp
в день в гражданском календаре:
year_month_day ymd = floor<days>(tp);
floor<days>
просто усекает точность до tp
до days
(делая это количество дней с 1970-01-01 00:00:00 UT C).
ymd
- это структура данных {year, month, day}
, преобразованная из days
-precision time_point
и имеет тип std::chrono::year_month_day
. И ymd
, и floor<days>(tp)
содержат точно такую же информацию. Но информация хранится в двух разных структурах данных: {year, month, day}
vs {count of days}
.
Следующий шаг - найти первый день года и месяца, на которые ссылается ymd
. Это просто выражение ymd.year()/ymd.month()/1
.
Его можно преобразовать обратно в структуру данных {count of days}
с помощью:
sys_days{ymd.year()/ymd.month()/1}
std::chrono::sys_days
- это просто псевдоним типа для типа выражение floor<days>(tp)
, которое имеет тип:
time_point<system_clock, days>
Затем структура данных sys_days
неявно преобразуется в seconds
-точность, и целая сумма извлекается и возвращается из этой структуры данных.
A превью библиотеки C ++ 20 <chrono>
находится здесь и может использоваться с C ++ 11/14/17. Чтобы перенести вышеуказанную функцию в эту библиотеку предварительного просмотра, просто добавьте "date/date.h"
и using namespace date;
. "date/date.h"
является библиотекой только для заголовков и поэтому не требует установки.
Это можно сделать следующим образом:
std::cout << floor_to_month_utc(1594386202) << '\n';
, что выводит:
1593561600
Поучительно сравнить приведенный выше код с этим ответом , который дает другой результат:
1593626076
Причина, по которой результат отличается, восходит к различию между календарные вычислений и хронологические вычислений. Календарные вычисления выполняются относительно некоторого календаря (гражданского, китайского, юлианского и т. Д.). В то время как хронологические вычисления оперируют только фиксированными (регулярными) единицами времени. Календарные месяцы и годы не имеют регулярной длины.
Библиотека C ++ 20 <chrono>
может выполнять хронологические вычисления с months
и years
. Иногда это правильный ответ, когда речь идет о физических или биологических процессах, которые растягиваются на месяцы или годы. Таким процессам наплевать на календари, созданные руками человека. Таким образом, в этом случае имеет смысл иметь дело со средней продолжительностью 1094 * месяцев и лет.
Этот оператор:
floor<months>(sys_seconds{seconds{timestamp}})
просто делит время с момента Unix Время эпоха в обычные, четные месяцы, причем каждый месяц длится ровно 2 629 746 секунд (средняя продолжительность гражданского месяца). Итак, этот ответ верен, если кто-то желает хронологического вычисления с гипотетическими единообразными месяцами (совершенно другой календарь, если хотите).