#pragma once
#include <string>

class Date {
    int y, m, day;
    static std::string Date_ToString(int date, int format) {
        std::string str = std::to_string(date);
        if (format == 1) {
            if (str.size() < 2)
                str = '0' + str;
        } else {
            while (str.size() < 4) {
                str = '0' + str;
            }
        }
        return str;
    }
    static int JulianDay(const Date & date) {
        int a = floor((14 - date.m) / 12);
        int Y = date.y + 4800 - a;
        int M = date.m + 12 * a - 3;
        return date.day + floor((153 * M + 2) / 5)
        + 365 * Y + floor(Y / 4) - floor(Y / 100)
        + floor(Y / 400) - 32045;
    }

 public:
    explicit Date(int y, int m, int day) {
        this -> y = y;
        this -> m = m;
        this -> day = day;
    }
    int DaysLeft(const Date & date) const {
        int J = JulianDay(*this);
        int JN = JulianDay(date);
        return JN - J;
    }
    bool IsLeap() const {
        if ((y % 4 == 0 && y % 100 != 0) || (y % 400 == 0))
            return true;
        else
            return false;
    }
    Date DaysLater(int days) const {
        int J = JulianDay(*this) + days;
        int y = 4716, j = 1401, m = 2, n = 12, r = 4, p = 1461;
        int v = 3, u = 5, s = 153, w = 2, B = 274277, C = -38;
        int f = J + j + (((4 * J + B) / 146097) * 3) / 4 + C;
        int e = r * f + v;
        int g = (e % p) / r;
        int h = u * g + w;
        int D = (h % s) / u + 1;
        int M = (h / s + m) % n + 1;
        int Y = e / p - y + (n + m - M) / n;
        return Date(Y, M, D);
    }
    std::string ToString() const {
        return Date_ToString(day, 1) + '.'
        + Date_ToString(m, 1) + '.'
        + Date_ToString(y, 2);
    }
};