Как реализовать алгоритм для преобразования «месяц-неделя-день-час» в «день года»? - PullRequest
0 голосов
/ 15 апреля 2020
enum months
{
    JAN = 1, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC
};

enum weeks
{
    first = 1, second, third, fourth, last
};

enum days
{
    sun = 1, mon, tue, wed, thu, fri, sat
};

enum hours
{
    zero = 1, one, two ..., twenty-three = 24
};

enum months month = get_month();

enum weeks week = get_week();

enum days day = get_day();

enum hours hour = get_hour();

uint16_t day_of_year = days_since_jan_1(month, week, day, hour);

Как реализовать days_since_jan_1 ?

1 Ответ

1 голос
/ 16 апреля 2020

как уже упоминалось, вам нужен год, чтобы выполнить этот расчет, чтобы решить, сколько дней вам нужно сосчитать за февраль.

Я попытался решить проблему, используя следующий фрагмент кода, используя Congruence Зеллера , поскольку он не зависит от функций даты и времени. Я попытался добавить некоторые комментарии, что я делаю, где и почему, я также провел некоторые тесты, и это, кажется, работает, но могут быть некоторые крайние / угловые случаи, о которых я не думал. Я уверен, что это не оптимальное решение, не стесняйтесь давать отзывы.

#include <stdio.h>

// defines the day offsets of each month in "normal" and "leap" year
static const int days_of_months[2][13] = {
    {0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
    {0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}
};

/* 
    Leap year is defined as: 
        * divisable by 4 except divisable by 100 OR
        * divisable by 400
*/
int year_is_leap(int year)
{
    return (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0));
}

// https://en.wikipedia.org/wiki/Zeller%27s_congruence
int get_day_of_the_week(int year, int month, int day)
{
    int h, q, m, K, J = 0; 

    q = day; 
    m = month;

    if (month < 3) 
    {
        m = month + 12;
        year -= 1;
    } 

    K = year % 100;
    J = year / 100;

    h = (q + (13*(m+1))/5 + K + K/4 + J/4 + 5*J) % 7;

    // remap to Sunday = 1 ... Saturday = 7
    return ((h+6)%7)+1;
}

int get_days_since_first_jan (int year, int month, int week, int day)
{
    int days_passed = 0, i = 0;

    // if date is in week 1, use given day of week to get the days of this month
    if (week == 1)
    {
        days_passed += day - get_day_of_the_week (year, month, 1) + 1; 
    }
    else 
    {
        //iterate over weeks
        for (i = week; i > 0; i --)
        { 
            // in week one, get the weekday of the first of the month, to get remaining days of this week for this month
            if (i == 1)
            {
                days_passed += 7 - (get_day_of_the_week (year, month, 1) - 1);
            }
            // in the given week, simply add the given days to it
            else if (i == week)
            {
                days_passed += day;
            }
            // for all other weeks, add 7 days
            else 
            {
                days_passed += 7;
            }
        }
    }

    // Add the offset of the given month in days
    days_passed += days_of_months[year_is_leap (year)][month];

    return days_passed;
}

int main(void)
{
    // 2020/1/31 -> 31
    printf("%d\n", get_days_since_first_jan(2020, 1, 5, 6));

    // 2020/2/28 -> 59
    printf("%d\n", get_days_since_first_jan(2020, 2, 5, 6));

    // 2020/4/15 -> 106
    printf("%d\n", get_days_since_first_jan(2020, 4, 3, 4));

    // 2020/8/17 -> 230
    printf("%d\n", get_days_since_first_jan(2020, 8, 4, 2));

    // 2021/3/1 -> 60
    printf("%d\n", get_days_since_first_jan(2021, 3, 1, 2));

    // 2021/3/1 -> 60
    printf("%d\n", get_days_since_first_jan(2021, 3, 1, 2));

    // 2021/3/9 -> 68
    printf("%d\n", get_days_since_first_jan(2021, 3, 2, 3));

    // 2028/1/1 -> 1
    printf("%d\n", get_days_since_first_jan(2028, 1, 1, 7));

    // 2028/8/29 -> 242
    printf("%d\n", get_days_since_first_jan(2028, 8, 5, 3));

    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...