boost — C ++ Получить номер дня ISO8601 из номера недели и дня недели

Я имею:

  • Номер года (может быть любым)
  • Номер месяца (с января по декабрь)
  • Номер недели (1-й, 2-й, 3-й, 4-й, последний)
  • День недели (Вс, пн, вт, ср, чт, пт, сб)

Мне нужно получить номер дня [от 1 до ~ 31] — «ГГГГ-ММ-DD«(ISO8601).

Есть ли способ рассчитать это, используя время ускорения posix или с помощью некоторых других библиотек C ++?

То есть

  • 2014, первое воскресенье марта — это будет 2014-03-02
  • 2014, четвертая среда декабря — это будет 2014-12-24

Благодарю.

3

Решение

Я написал легкий C библиотека что может делать то, что вы хотите, интересная часть Вот, как видите, алгоритм тривиален.

#include <stdio.h>
#include <stdint.h>
#include "dt_dow.h"#include "dt_accessor.h"
const struct test {
int      year;
int      month; /* Month of the year [1=Jan, 12=Dec] */
int      nth;   /* Occurrence within month           */
dt_dow_t dow;   /* Day of the week [1=Mon, 7=Sun]    */
int      dom;   /* Expected day of the month [1, 31] */
} tests[] =  {
{ 2014,  3,  1, DT_SUNDAY,     2 },
{ 2014,  4, -1, DT_TUESDAY,   29 },
{ 2014,  4, -2, DT_MONDAY,    21 },
{ 2014,  4, -5, DT_TUESDAY,    1 },
{ 2014,  4,  1, DT_TUESDAY,    1 },
{ 2014, 12,  4, DT_WEDNESDAY, 24 },
};

int
main() {
int i, ntests;

ntests = sizeof(tests) / sizeof(*tests);
for (i = 0; i < ntests; i++) {
const struct test t = tests[i];

{
int dom = dt_dom(dt_from_nth_dow_in_month(t.year, t.month, t.nth, t.dow));

if (t.dom != dom) {
printf("dt_dom(dt_from_nth_dow_in_month(%d, %d, %d, %d))\n",
t.year, t.month, t.nth, t.dow);
printf("  got: %d\n", dom);
printf("  exp: %d\n", t.dom);
}
}
}
return 0;
}

А вот повторная реализация, если вы не хотите использовать вышеуказанную библиотеку / код.

#include <stdio.h>
#include <assert.h>
#include <stdint.h>
#include <stdbool.h>

bool
leap_year(int y) {
return ((y % 4) == 0 && (y % 100 != 0 || y % 400 == 0));
}

int
days_in_month(int y, int m) {
static const int T[2][13] = {
{ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
{ 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
};
assert(m >=  1);
assert(m <= 12);
return T[leap_year(y)][m];
}

/* Computes the day of the week [1=Mon, 7=Sun] from the given year, month, day. */
int
ymd_to_dow(int y, int m, int d) {
static const int T[13] = { 0, 6, 2, 1, 4, 6, 2, 4, 0, 3, 5, 1, 3 };

assert(y >=  1);
assert(m >=  1);
assert(m <= 12);
assert(d >=  1);

y -= m < 3;
return 1 + (y + y/4 - y/100 + y/400 + T[m] + d) % 7;
}

int
dom_from_nth_dow_in_month(int y, int m, int nth, int dow) {
int dim, dom;

assert(y   >=  1);
assert(m   >=  1);
assert(m   <= 12);
assert(dow >=  1);
assert(dow <=  7);

dim = days_in_month(y, m);
if (nth > 0) {
dom = 1;
dom += (dow - ymd_to_dow(y, m, dom) + 7) % 7;
dom += --nth * 7;
if (dom <= dim)
return dom;
}
else if (nth < 0) {
dom = dim;
dom -= (ymd_to_dow(y, m, dom) - dow + 7) % 7;
dom -= ++nth * -7;
if (dom >= 1)
return dom;
}
return -1;
}

const struct test {
int year;
int month; /* Month of the year [1=Jan, 12=Dec] */
int nth;   /* Occurrence within month           */
int dow;   /* Day of the week [1=Mon, 7=Sun]    */
int dom;   /* Expected day of the month [1, 31] */
} tests[] =  {
{ 2014,  3,  1, 7,  2 },
{ 2014,  4, -1, 2, 29 },
{ 2014,  4, -2, 1, 21 },
{ 2014,  4, -5, 2,  1 },
{ 2014,  4,  1, 2,  1 },
{ 2014, 12,  4, 3, 24 },
};

int
main() {
int i, ntests;

ntests = sizeof(tests) / sizeof(*tests);
for (i = 0; i < ntests; i++) {
const struct test t = tests[i];

{
int dom = dom_from_nth_dow_in_month(t.year, t.month, t.nth, t.dow);

if (t.dom != dom) {
printf("dom_from_nth_dow_in_month(%d, %d, %d, %d))\n",
t.year, t.month, t.nth, t.dow);
printf("  got: %d\n", dom);
printf("  exp: %d\n", t.dom);
}
}
}
return 0;
}
1

Другие решения

Новый ответ на старый вопрос.

Используя эту бесплатную библиотеку дат с открытым исходным кодом:

http://howardhinnant.github.io/date_v2.html

2014, первое воскресенье марта — это будет 2014-03-02

#include "date.h"#include <iostream>

int
main()
{
using namespace date;
std::cout << year_month_day{sun[1]/mar/2014} << '\n';
}

какие выводы:

2014-03-02

Тип date::year_month_day имеет геттеры по имени year, month а также day, С ним довольно легко работать, и с полной документацией по ссылке выше.

2014, четвертая среда декабря — это будет 2014-12-24

using namespace date;
std::cout << year_month_day{wed[4]/dec/2014} << '\n';

2014-12-24

Но это не прошлой Среда декабря 2014 года, это:

std::cout << year_month_day{wed[last]/dec/2014} << '\n';

2014-12-31

Вот видео презентация библиотеки.

1

Хорошая работа шансен! Это может быть действительно полезно.
Но так как я могу свободно использовать boost — вот что я сделал до сих пор:

// DateFromWeekNumAndDay
// year     - Year YYYY.
// weekNum  - From 0 to 4.
// weekDay  - Week day starts from Sunday - 0 to Saturday - 6.
boost::gregorian::date DateFromWeekNumAndDay(boost::gregorian::date::year_type year, unsigned short weekNum, boost::date_time::weekdays weekDay)
{
boost::gregorian::date date(year, boost::gregorian::Apr, 1);
boost::gregorian::date::day_of_week_type d = date.day_of_week();

date += boost::gregorian::date_duration(weekNum * 7) + boost::gregorian::date_duration(weekDay - d);

return date;
}

Насколько я тестировал — все, кажется, работает просто отлично.
Я взял этот метод из этот сообщение. Так что спасибо пользователю KEBS за ссылку и большое спасибо пользователю Михаил Мельник для его образца функции «GetDateFromWeekNumber».

0
По вопросам рекламы [email protected]