See the original problem on HackerRank.
        
        Solutions
This problem seems convoluted but it can be solved very easily if decomposed in terms of simple predicates:
- if the year is 1918, we can directly return the day26.09.1918
- otherwise we can check if the year is leap. In this case we return 12.09and the year
- if the year is not leap, we just return 13.09and the year
To determine if a year is leap, we have to apply either the Julian - if the year is less than 1918 - or the Gregorian rule - otherwise.
Here is an implementation in C++:
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
 | bool isLeapGregorian(int year)
{
    return year%400 == 0 || 
           (year%4==0 && year%100!=0);
}
bool isLeapJulian(int year)
{
    return year%4==0;
}
bool isLeap(int year)
{
    return year < 1918 ? isLeapJulian(year) : isLeapGregorian(year);
}
string dayOfProgrammer(int year) 
{
    if (year == 1918)
        return "26.09.1918";
    
    if (isLeap(year))
        return string("12.09.") + to_string(year);
    return string("13.09.") + to_string(year);
}
int main()
{
    int year; cin >> year;
    cout << dayOfProgrammer(year);
}
 | 
 
An alternative solution consists in calculating the number of days in February:
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
 | // ...other functions are the same as before...
bool is1918(int year)
{
    return year == 1918;
}
int main() 
{
    int y; cin >> y;
    auto daysInFebruary = is1918(y) ? (28-13) : (isLeap(y) ? 29 : 28);
    int day = 256 - 31 - daysInFebruary - 31 - 30 - 31 - 30 - 31 - 31;
    printf("%02d.%02d.%04d", day, 9, y);
}
 | 
 
A step forward with this exercise is making the solution a bit more flexible. What if we want to add more rules?
An idea: we put the rules into a vector and we try them in order. The first successful rule just breaks the loop.
Here is a possible implementation using optional:
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
 | optional<int> asDefault([[maybe_unused]]int year)
{
    return 28;
}
optional<int> asLeap(int year)
{
    return isLeap(year) ? optional{29} : nullopt;
}
optional<int> as1918(int year)
{
    return year == 1918 ? optional{28-13} : nullopt;
}
int main()
{
    int year = 2016;
    vector rules = {as1918, asLeap, asDefault};
    
    auto daysInFebruary = 0;
    for (auto rule : rules)
    {
        if (auto res = rule(year); res)
        {
            daysInFebruary = *res;
            break;
        }
    }
    
    int day = 256 - 31 - daysInFebruary - 31 - 30 - 31 - 30 - 31 - 31;
    printf("%02d.%02d.%04d", day, 9, year);
}
 | 
 
You can split asLeap. For example:
| 1
2
3
4
5
6
7
8
9
 | optional<int> asLeapJulian(int year)
{
    return (year < 1918 && year%4 == 0) ? optional{29} : nullopt;
}
optional<int> asLeapGregorian(int year)
{
    return (year > 1918 && (year%400 == 0 || (year%4==0 && year%100!=0))) ? optional{29} : nullopt;
}
 | 
 
The rules are just pointer to functions. Note that thanks to automatic deduction of class templates (since C++17) we can omit tedious details about the type of vector.