#include "TimeUtils.h"

#include <chrono>
#include <sstream>
#include <iomanip>


int64_t TimeUtils::now()
{
    //	return std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count();
    return std::chrono::time_point_cast<std::chrono::seconds>(std::chrono::system_clock::now()).time_since_epoch().count();
}


int64_t TimeUtils::now_ms()
{
    return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
    //return std::chrono::time_point_cast<std::chrono::microseconds>(std::chrono::system_clock::now()).time_since_epoch().count();
}

std::string TimeUtils::now_datetime(char c1/* = '/'*/, char c2/* = ':'*/, char c3/* = ' '*/)
{
    std::stringstream ss;
    ss << "%Y" << c1 << "%m" << c1 << "%d" << c3 << "%H" << c2 << "%M" << c2 << "%S";
    std::string fmt = ss.str();
    ss.str("");
    auto t = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
    ss << std::put_time(std::localtime(&t), fmt.c_str());
    return ss.str();
}

std::string TimeUtils::now_date(char c1/* = '/'*/)
{
    std::stringstream ss;
    ss << "%Y" << c1 << "%m" << c1 << "%d";
    std::string fmt = ss.str();
    ss.str("");
    auto t = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
    ss << std::put_time(std::localtime(&t), fmt.c_str());
    return ss.str();
}


int64_t TimeUtils::datetime2ts(std::string s)
{
    // YYYY-mm-dd HH:MM:SS
    if (s.size() < 19) { return 0; }
    s[4] = s[7] = '-';
    s[10] = ' ';
    s[13] = s[16] = ':';
    std::tm t;
    std::stringstream ss(s);
    ss >> std::get_time(&t, "%Y-%m-%d %H:%M:%S");
    auto tp = std::chrono::system_clock::from_time_t(std::mktime(&t));
    return std::chrono::duration_cast<std::chrono::seconds>(tp.time_since_epoch()).count();
}
int64_t TimeUtils::datetime2tms(std::string s)
{
    if (s.size() < 19) { return 0; }
    s[4] = s[7] = '-';
    s[10] = ' ';
    s[13] = s[16] = ':';
    std::tm t;
    std::stringstream ss(s);
    ss >> std::get_time(&t, "%Y-%m-%d %H:%M:%S");
    auto tp = std::chrono::system_clock::from_time_t(std::mktime(&t));
    return std::chrono::duration_cast<std::chrono::milliseconds>(tp.time_since_epoch()).count();
}

std::string TimeUtils::ts2datetime(int64_t ts, std::string fmt /*= "%Y-%m-%d %H:%M:%S"*/)
{
    // std::localtime : 本地时区的时间
    // std::gmtime : 格林威治时间
    time_t t(ts);
    std::stringstream ss;
    ss << std::put_time(std::localtime(&t), fmt.c_str());
    return ss.str();
}

std::string TimeUtils::ts2date(int64_t ts)
{
    time_t t(ts);
    std::stringstream ss;
    ss << std::put_time(std::localtime(&t), "%Y-%m-%d");
    return ss.str();
}

std::string TimeUtils::duration_str(int64_t t)
{
    auto h = t / 3600;
    auto m = (t % 3600) / 60;
    auto s = (t % 3600) % 60;
    std::string str = std::to_string(s) + "秒";
    if (m > 0 || h > 0)
    {
        str = std::to_string(m) + "分" + str;
    }
    if (h > 0)
    {
        str = std::to_string(h) + "小时" + str;
    }
    return str;
}

int64_t TimeUtils::tick(std::function<void()> func)
{
    if (!func)
    {
        return 0;
    }
    auto start = std::chrono::steady_clock::now();
    func();
    auto end = std::chrono::steady_clock::now();
    return std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
}
