/*
    TessesFramework a library to make C++ easier for me, used in CrossLang:
   https://git.tesses.org/tesses50/crosslang Copyright (C) 2026 Mike Nolan

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

#include "TessesFramework/Date/Date.hpp"
#include "../HowardHinnant_date/date.h"
#include "TessesFramework/Http/HttpUtils.hpp"
#if defined(__FreeBSD__)
#include <sys/time.h>
#endif
#include <iomanip>
#include <iostream>
#include <sstream>
using namespace std::chrono;
using namespace date;
namespace Tesses::Framework::Date {
int GetTimeZone() {

#if defined(__SWITCH__) || defined(_WIN32) || defined(GEKKO) || defined(__PS2__)
    return (int)(-_timezone);
#elif defined(__FreeBSD__)
    struct timeval tv;
    struct timezone tz;
    gettimeofday(&tv, &tz);
    return (tz.tz_minuteswest / 60);
#else
    return (int)(-timezone);
#endif
}
bool TimeZoneSupportDST() {
#if defined(__SWITCH__) || defined(_WIN32) || defined(GEKKO) || defined(__PS2__)
    return _daylight == 1;
#elif defined(__FreeBSD__)
    struct timeval tv;
    struct timezone tz;
    gettimeofday(&tv, &tz);
    return tz.tz_dsttime != 0;
#else
    return daylight == 1;
#endif
}
DateTime::DateTime() {}
static int64_t div_floor(int64_t a, int64_t b) {
    int64_t v = a / b;
    if (a < 0 && (a % b) != 0)
        v--;
    return v;
}
void DateTime::FromEpochNoConvert(int64_t gmt) {

    auto epoch = date::sys_days{date::January / 1 / 1970};
    epoch += date::days(div_floor(gmt, 86400));

    // date::days<int64_t> sys_days_since_epoch = date::days<int64_t>(gmt);

    // Convert sys_days to year_month_day
    date::year_month_day ymd = date::year_month_day(epoch);
    int64_t secs = gmt % 86400;
    if (secs < 0)
        secs += 86400;

    second = secs % 60;
    secs /= 60;
    minute = secs % 60;
    secs /= 60;
    hour = secs % 24;

    day = (int)(unsigned)ymd.day();
    month = (int)(unsigned)ymd.month();
    year = (int)ymd.year();
}
DateTime::DateTime(int64_t epoch) {
    this->isLocal = false;
    this->FromEpochNoConvert(epoch);
}
void DateTime::Set(int64_t epoch) {
    this->isLocal = false;
    this->FromEpochNoConvert(epoch);
}
void DateTime::Set(int year, int month, int day, int hour, int minute,
                   int seconds, bool isLocal) {
    this->year = year;
    this->month = month;
    this->day = day;
    this->hour = hour;
    this->minute = minute;
    this->second = seconds;
    this->isLocal = isLocal;
}
DateTime::DateTime(int year, int month, int day, int hour, int minute,
                   int seconds, bool isLocal) {
    this->year = year;
    this->month = month;
    this->day = day;
    this->hour = hour;
    this->minute = minute;
    this->second = seconds;
    this->isLocal = isLocal;
}
int DateTime::Year() const { return this->year; }
int DateTime::Month() const { return this->month; }
int DateTime::Day() const { return this->day; }
int DateTime::Hour() const { return this->hour; }
int DateTime::Minute() const { return this->minute; }
int DateTime::Second() const { return this->second; }
bool DateTime::IsLocal() const { return this->isLocal; }
int DateTime::DayOfWeek() const {
    date::year_month_day ymd(date::year(year), date::month((uint32_t)month),
                             date::day((uint32_t)day));
    date::sys_days d = ymd;
    date::year_month_weekday ymw(d);
    return ymw.weekday().c_encoding() % 7;
}
void DateTime::SetToLocal() {
    if (this->isLocal)
        return;
    auto local = this->ToEpochNoConvert();
    local += GetTimeZone();
    if (TimeZoneSupportDST()) {

        auto epoch = date::sys_days{date::January / 1 / 1970};
        epoch += date::days(div_floor(local, 86400));

        bool isDST = false;

        date::year_month_day ymd(epoch);

        auto month = (unsigned)ymd.month();

        if (month > 3 && month < 11) {
            isDST = true;
        } else if (month == 3) {
            auto day = (unsigned)ymd.day();
            if (day > 14)
                isDST = true;
            else if (day >= 8 && day <= 14) {
                date::year_month_weekday ymw(epoch);
                auto dow = ymw.weekday().c_encoding();
                auto secondSunday = day - dow;
                if (secondSunday < 8)
                    secondSunday += 7;

                if (day > secondSunday)
                    isDST = true;
                else if (day == secondSunday) {
                    int64_t secs = local % 86400;
                    if (secs < 0)
                        secs += 86400;

                    secs /= 3600;
                    auto _hours = secs % 24;
                    if (_hours >= 2)
                        isDST = true;
                }
            }
        } else if (month == 11) {
            auto day = (unsigned)ymd.day();
            if (day >= 1 && day <= 7) {
                date::year_month_weekday ymw(epoch);
                auto dow = ymw.weekday().c_encoding();
                int32_t firstSunday = (int32_t)day - (int32_t)dow;
                if (firstSunday < 1)
                    firstSunday += 7;

                if (day < firstSunday)
                    isDST = true;
                else if (day == firstSunday) {
                    int64_t secs = local % 86400;
                    if (secs < 0)
                        secs += 86400;

                    secs /= 3600;
                    auto _hours = secs % 24;
                    if (_hours <= 1)
                        isDST = true;
                }
            }
        }

        if (isDST)
            local += 3600;
    }
    this->isLocal = true;
    this->FromEpochNoConvert(local);
}
DateTime DateTime::ToLocal() const {
    DateTime dt = *this;
    dt.SetToLocal();
    return dt;
}
void DateTime::SetToUTC() {
    if (!this->isLocal)
        return;
    auto local = this->ToEpochNoConvert();
    local -= GetTimeZone();
    if (TimeZoneSupportDST()) {
        {
            auto epoch = date::sys_days{date::January / 1 / 1970};
            epoch += date::days(div_floor(local, 86400));

            bool isDST = false;

            date::year_month_day ymd(epoch);

            auto month = (unsigned)ymd.month();

            if (month > 3 && month < 11) {
                isDST = true;
            } else if (month == 3) {
                auto day = (unsigned)ymd.day();
                if (day > 14)
                    isDST = true;
                else if (day >= 8 && day <= 14) {
                    date::year_month_weekday ymw(epoch);
                    auto dow = ymw.weekday().c_encoding();
                    auto secondSunday = day - dow;
                    if (secondSunday < 8)
                        secondSunday += 7;

                    if (day > secondSunday)
                        isDST = true;
                    else if (day == secondSunday) {
                        int64_t secs = local % 86400;
                        if (secs < 0)
                            secs += 86400;

                        secs /= 3600;
                        auto _hours = secs % 24;
                        if (_hours >= 2)
                            isDST = true;
                    }
                }
            } else if (month == 11) {
                auto day = (unsigned)ymd.day();
                if (day >= 1 && day <= 7) {
                    date::year_month_weekday ymw(epoch);
                    auto dow = ymw.weekday().c_encoding();
                    int32_t firstSunday = (int32_t)day - (int32_t)dow;
                    if (firstSunday < 1)
                        firstSunday += 7;

                    if (day < firstSunday)
                        isDST = true;
                    else if (day == firstSunday) {
                        int64_t secs = local % 86400;
                        if (secs < 0)
                            secs += 86400;

                        secs /= 3600;
                        auto _hours = secs % 24;
                        if (_hours <= 1)
                            isDST = true;
                    }
                }
            }

            if (isDST)
                local -= 3600;
        }
    }
    this->isLocal = false;
    this->FromEpochNoConvert(local);
}
DateTime DateTime::ToUTC() const {
    DateTime dt = *this;
    dt.SetToUTC();
    return dt;
}
int64_t DateTime::ToEpoch() const {
    if (this->isLocal) {
        DateTime dt = this->ToUTC();
        return dt.ToEpochNoConvert();
    }
    return this->ToEpochNoConvert();
}
int64_t DateTime::ToEpochNoConvert() const {
    date::year y = (date::year)year;
    date::month m = (date::month)month;
    date::day d = (date::day)day;
    date::year_month_day ymd(y, m, d);
    std::chrono::duration hr =
        hours(this->hour) + minutes(this->minute) + seconds(this->second);
    date::sys_days sd = ymd;
    auto res = sd - date::sys_days{date::January / 1 / 1970};
    return (res.count() * 86400) + hr.count(); // bad
}
DateTime DateTime::NowUTC() {
    DateTime theTime((int64_t)time(NULL));
    return theTime;
}
void DateTime::SetToNowUTC() { this->Set((int64_t)time(NULL)); }
void DateTime::SetYear(int y) { this->year = y; }
void DateTime::SetMonth(int m) { this->month = m; }
void DateTime::SetDay(int d) { this->day = d; }
void DateTime::SetHour(int h) { this->hour = h; }
void DateTime::SetMinute(int m) { this->minute = m; }
void DateTime::SetSecond(int s) { this->second = s; }
void DateTime::SetLocal(bool local) { this->isLocal = local; }
void DateTime::SetToNow() {
    int64_t local = (int64_t)time(NULL);
    local += GetTimeZone();
    if (TimeZoneSupportDST()) {

        auto epoch = date::sys_days{date::January / 1 / 1970};
        epoch += date::days(div_floor(local, 86400));

        bool isDST = false;

        date::year_month_day ymd(epoch);

        auto month = (unsigned)ymd.month();

        if (month > 3 && month < 11) {
            isDST = true;
        } else if (month == 3) {
            auto day = (unsigned)ymd.day();
            if (day > 14)
                isDST = true;
            else if (day >= 8 && day <= 14) {
                date::year_month_weekday ymw(epoch);
                auto dow = ymw.weekday().c_encoding();
                auto secondSunday = day - dow;
                if (secondSunday < 8)
                    secondSunday += 7;

                if (day > secondSunday)
                    isDST = true;
                else if (day == secondSunday) {
                    int64_t secs = local % 86400;
                    if (secs < 0)
                        secs += 86400;

                    secs /= 3600;
                    auto _hours = secs % 24;
                    if (_hours >= 2)
                        isDST = true;
                }
            }
        } else if (month == 11) {
            auto day = (unsigned)ymd.day();
            if (day >= 1 && day <= 7) {
                date::year_month_weekday ymw(epoch);
                auto dow = ymw.weekday().c_encoding();
                int32_t firstSunday = (int32_t)day - (int32_t)dow;
                if (firstSunday < 1)
                    firstSunday += 7;

                if (day < firstSunday)
                    isDST = true;
                else if (day == firstSunday) {
                    int64_t secs = local % 86400;
                    if (secs < 0)
                        secs += 86400;

                    secs /= 3600;
                    auto _hours = secs % 24;
                    if (_hours <= 1)
                        isDST = true;
                }
            }
        }

        if (isDST)
            local += 3600;
    }
    this->isLocal = true;
    this->FromEpochNoConvert(local);
}
DateTime DateTime::Now() {
    DateTime dt;
    dt.SetToNow();
    return dt;
}

const char *weekday_short[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
const char *months_short[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
                              "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
const char *weekday_long[] = {"Sunday",   "Monday", "Tuesday", "Wednesday",
                              "Thursday", "Friday", "Saturday"};
const char *months_long[] = {"January",   "Febuary", "March",    "April",
                             "May",       "June",    "July",     "August",
                             "September", "October", "November", "December"};
bool DateTime::TryParseHttpDate(std::string txt, DateTime &dt) {
    // Mon, 24 Jul 2018 11:00:00 GMT
    auto split = Http::HttpUtils::SplitString(txt, ", ", 2);
    if (split.size() != 2)
        return false;
    bool validDay = false;
    for (size_t i = 0; i < 7; i++) {
        std::string_view d = weekday_short[i];
        if (d == split[0])
            validDay = true;
    }
    if (!validDay)
        return false;
    // DAY MON YEAR HH:MM:SS GMT
    split = Http::HttpUtils::SplitString(split[1], " ", 5);
    if (split.size() != 5)
        return false;
    if (split[4] != "GMT")
        return false;
    int day = 0;
    int mon = 0;
    int year = 0;
    int hour = 0;
    int minute = 0;
    int second = 0;

    try {
        day = std::stoi(split[0]);
        if (day < 1 && day > 31)
            return false;

    } catch (std::exception &ex) {
        return false;
    }
    for (int i = 0; i < 12; mon++) {
        std::string_view d = months_short[i];
        if (d == split[1]) {
            mon = i + 1;
            break;
        }
    }
    if (mon == 0)
        return false;
    try {
        year = std::stoi(split[2]);

    } catch (std::exception &ex) {
        return false;
    }
    split = Http::HttpUtils::SplitString(split[3], ":", 3);
    if (split.size() != 3)
        return false;
    try {
        hour = std::stoi(split[0]);

        minute = std::stoi(split[1]);

        second = std::stoi(split[2]);

    } catch (std::exception &ex) {
        return false;
    }

    dt.day = day;
    dt.month = mon;
    dt.year = year;
    dt.hour = hour;
    dt.minute = minute;
    dt.second = second;
    return true;
}
std::string DateTime::ToHttpDate() const {
    auto utc = this->ToUTC();
    std::string weekday = weekday_short[utc.DayOfWeek()];
    std::string month = months_short[utc.month - 1];
    std::stringstream strm(std::ios_base::out);
    strm << weekday << ", " << std::setfill('0') << std::setw(2) << utc.day;
    strm << " " << month << " " << std::setfill('0') << std::setw(4)
         << utc.year;
    strm << " " << std::setfill('0') << std::setw(2) << utc.hour;
    strm << ":" << std::setfill('0') << std::setw(2) << utc.minute;
    strm << ":" << std::setfill('0') << std::setw(2) << utc.second;
    strm << " GMT";

    return strm.str();
}
std::string DateTime::ToString() const { return ToString("%Y/%m/%d %H:%M:%S"); }

std::string DateTime::ToString(std::string fmt) const {
    auto weekday = this->DayOfWeek();

    std::string text = "";
    for (size_t i = 0; i < fmt.size(); i++) {
        if (fmt[i] == '%') {
            i++;
            if (i < fmt.size())
                switch (fmt[i]) {
                case 'a':
                    text.append(weekday_short[weekday]);
                    break;
                case 'A':
                    text.append(weekday_long[weekday]);
                    break;
                case 'S':
                    text.append(Http::HttpUtils::LeftPad(std::to_string(second),
                                                         2, '0'));
                    break;
                case 'm':
                    text.append(Http::HttpUtils::LeftPad(std::to_string(month),
                                                         2, '0'));
                    break;
                case 'd':
                    text.append(
                        Http::HttpUtils::LeftPad(std::to_string(day), 2, '0'));
                    break;
                case 'e':
                    text.append(
                        Http::HttpUtils::LeftPad(std::to_string(day), 2, ' '));
                    break;
                case 'M':
                    text.append(Http::HttpUtils::LeftPad(std::to_string(minute),
                                                         2, '0'));
                    break;
                case 'H':
                    text.append(
                        Http::HttpUtils::LeftPad(std::to_string(hour), 2, '0'));
                    break;
                case 'F':
                    text.append(
                        Http::HttpUtils::LeftPad(std::to_string(year), 4, '0'));
                    text.push_back('-');
                    text.append(Http::HttpUtils::LeftPad(std::to_string(month),
                                                         2, '0'));
                    text.push_back('-');
                    text.append(
                        Http::HttpUtils::LeftPad(std::to_string(day), 2, '0'));
                    break;
                case 'D':
                    text.append(Http::HttpUtils::LeftPad(std::to_string(month),
                                                         2, '0'));
                    text.push_back('/');
                    text.append(
                        Http::HttpUtils::LeftPad(std::to_string(day), 2, '0'));
                    text.push_back('/');
                    text.append(Http::HttpUtils::LeftPad(
                        std::to_string(year % 100), 2, '0'));
                    break;
                case 'y':
                    text.append(Http::HttpUtils::LeftPad(
                        std::to_string(year % 100), 2, '0'));
                    break;
                case 'r': {
                    auto hours = hour % 12;
                    if (hours == 0)
                        hours = 12;
                    text.append(Http::HttpUtils::LeftPad(std::to_string(hours),
                                                         2, '0'));
                    text.push_back(':');
                    text.append(Http::HttpUtils::LeftPad(std::to_string(minute),
                                                         2, '0'));
                    text.push_back(':');
                    text.append(Http::HttpUtils::LeftPad(std::to_string(second),
                                                         2, '0'));
                    text.append(hour >= 12 ? " PM" : " AM");
                } break;
                case 'R': {
                    text.append(
                        Http::HttpUtils::LeftPad(std::to_string(hour), 2, '0'));
                    text.push_back(':');
                    text.append(Http::HttpUtils::LeftPad(std::to_string(minute),
                                                         2, '0'));
                } break;
                case 'T': {

                    text.append(
                        Http::HttpUtils::LeftPad(std::to_string(hour), 2, '0'));
                    text.push_back(':');
                    text.append(Http::HttpUtils::LeftPad(std::to_string(minute),
                                                         2, '0'));
                    text.push_back(':');
                    text.append(Http::HttpUtils::LeftPad(std::to_string(second),
                                                         2, '0'));

                }

                break;
                case 'u': {
                    int dow = weekday + 6;
                    dow %= 7;
                    text.append(std::to_string(dow + 1));
                } break;
                case 'w': {

                    text.append(std::to_string(weekday));
                } break;
                case 'c': {
                    text.append(weekday_short[weekday]);
                    text.push_back(' ');
                    text.append(months_short[month]);
                    text.push_back(' ');
                    text.append(
                        Http::HttpUtils::LeftPad(std::to_string(day), 2, '0'));
                    text.push_back(' ');
                    text.append(
                        Http::HttpUtils::LeftPad(std::to_string(hour), 2, '0'));
                    text.push_back(':');
                    text.append(Http::HttpUtils::LeftPad(std::to_string(minute),
                                                         2, '0'));
                    text.push_back(':');
                    text.append(Http::HttpUtils::LeftPad(std::to_string(second),
                                                         2, '0'));
                    text.push_back(' ');
                    text.append(
                        Http::HttpUtils::LeftPad(std::to_string(year), 4, '0'));

                } break;
                case 'C':
                    text.append(Http::HttpUtils::LeftPad(
                        std::to_string(year / 100), 2, '0'));
                    break;
                case 'Y':
                    text.append(
                        Http::HttpUtils::LeftPad(std::to_string(year), 4, '0'));
                    break;
                case 'p':
                    text.append(hour >= 12 ? "PM" : "AM");
                    break;
                case 'I': {
                    auto hours = hour % 12;
                    if (hours == 0)
                        hours = 12;
                    text.append(Http::HttpUtils::LeftPad(std::to_string(hours),
                                                         2, '0'));
                } break;
                case 'h':
                case 'b':
                    text.append(months_short[month - 1]);
                    break;
                case 'B':
                    text.append(months_long[month - 1]);
                    break;
                case '%':
                    text.push_back('%');
                    break;
                case 'n':
                    text.push_back('\n');
                    break;
                case 't':
                    text.push_back('\t');
                    break;
                }
        } else {
            text.push_back(fmt[i]);
        }
    }
    return text;
}
TimeSpan::TimeSpan() { this->totalSeconds = 0; }
TimeSpan::TimeSpan(int64_t totalSeconds) { this->totalSeconds = totalSeconds; }
TimeSpan::TimeSpan(int hours, int minutes, int seconds)
    : TimeSpan(0, hours, minutes, seconds) {}
TimeSpan::TimeSpan(int days, int hours, int minutes, int seconds) {
    this->totalSeconds = (int64_t)days * 86400;
    this->totalSeconds += (int64_t)hours * 3600;
    this->totalSeconds += (int64_t)minutes * 60;
    this->totalSeconds += (int64_t)seconds;
}
void TimeSpan::Set(int days, int hours, int minutes, int seconds) {
    this->totalSeconds = (int64_t)days * 86400;
    this->totalSeconds += (int64_t)hours * 3600;
    this->totalSeconds += (int64_t)minutes * 60;
    this->totalSeconds += (int64_t)seconds;
}
void TimeSpan::Set(int hours, int minutes, int seconds) {
    this->totalSeconds = (int64_t)hours * 3600;
    this->totalSeconds += (int64_t)minutes * 60;
    this->totalSeconds += (int64_t)seconds;
}

void TimeSpan::SetDays(int d) {
    Set(d, this->Hours(), this->Minutes(), this->Seconds());
}
void TimeSpan::SetHours(int h) {
    Set(this->Days(), h, this->Minutes(), this->Seconds());
}
void TimeSpan::SetMinutes(int m) {
    Set(this->Days(), this->Hours(), m, this->Seconds());
}
void TimeSpan::SetSeconds(int s) {
    Set(this->Days(), this->Hours(), this->Minutes(), s);
}

int TimeSpan::Days() const { return (int)(this->totalSeconds / 86400); }
int TimeSpan::Hours() const { return (int)((this->totalSeconds / 3600) % 24); }
int TimeSpan::Minutes() const { return (int)((this->totalSeconds / 60) % 60); }
int TimeSpan::Seconds() const { return (int)(this->totalSeconds % 60); }

int64_t TimeSpan::TotalSeconds() const { return this->totalSeconds; }
int64_t TimeSpan::TotalMinutes() const { return this->totalSeconds / 60; }
int64_t TimeSpan::TotalHours() const { return this->totalSeconds / 3600; }

void TimeSpan::AddSeconds(int64_t seconds) { this->totalSeconds += seconds; }
void TimeSpan::AddMinutes(int64_t minutes) {
    this->totalSeconds += minutes * 60;
}
void TimeSpan::AddHours(int64_t hours) { this->totalSeconds += hours * 3600; }
void TimeSpan::AddDays(int64_t days) { this->totalSeconds += days * 86400; }

void TimeSpan::SetTotalSeconds(int64_t totalSeconds) {
    this->totalSeconds = totalSeconds;
}
void TimeSpan::SetTotalMinutes(int64_t totalMinutes) {
    this->totalSeconds = totalMinutes * 60;
}
void TimeSpan::SetTotalHours(int64_t totalHours) {
    this->totalSeconds = totalHours * 3600;
}

std::string TimeSpan::ToString(bool slim) const {
    std::string str = {};
    if (this->totalSeconds < 0)
        str += "-";
    if (slim && this->totalSeconds > -36000 && this->totalSeconds < 36000) {
        // 0:00
        // 00:00
        // 0:00:00
        if (this->totalSeconds <= -3600 || this->totalSeconds >= 3600) {
            // hours must force multi digit minutes
            str += std::to_string(this->Hours());
            str += ":";
            str += Http::HttpUtils::LeftPad(std::to_string(this->Minutes()), 2,
                                            '0');
        } else {
            str += std::to_string(this->Minutes());
        }

        str += ":";
        str +=
            Http::HttpUtils::LeftPad(std::to_string(this->Seconds()), 2, '0');
    } else {
        // 00:00:00
        // 0.00:00:00

        if (this->totalSeconds <= -86400 || this->totalSeconds >= 86400) {
            str += std::to_string(this->Days());
            str += ".";
        }

        str += Http::HttpUtils::LeftPad(std::to_string(this->Hours()), 2, '0');
        str += ":";
        str +=
            Http::HttpUtils::LeftPad(std::to_string(this->Minutes()), 2, '0');
        str += ":";
        str +=
            Http::HttpUtils::LeftPad(std::to_string(this->Seconds()), 2, '0');
    }
    return str;
}

bool TimeSpan::TryParse(std::string text, TimeSpan &span) {
    if (text.empty())
        return false;
    bool negative = text[0] == '-';
    int64_t totalSeconds = 0;

    try {

        std::string colonPart = text.substr(negative ? 1 : 0);
        auto res = Http::HttpUtils::SplitString(colonPart, ":");

        if (res.size() < 2 || res.size() > 3)
            return false;
        std::string hour = res[0];
        size_t index = hour.find('.');
        if (index != std::string::npos) {
            totalSeconds += std::stoll(hour.substr(0, index)) * 86400;
            hour = hour.substr(index + 1);
        }

        if (res.size() == 2) {
            // mm:ss

            totalSeconds += std::stoll(hour) * 60;
            totalSeconds += std::stoll(res[1]);
        } else if (res.size() == 3) {
            totalSeconds += std::stoll(hour) * 3600;
            totalSeconds += std::stoll(res[1]) * 60;
            totalSeconds += std::stoll(res[2]);
        } else
            return false;

    } catch (...) {
        return false;
    }

    if (negative)
        totalSeconds = -totalSeconds;

    span.SetTotalSeconds(totalSeconds);
    return true;
}
} // namespace Tesses::Framework::Date
