/******************************************************** * ██████╗ ██████╗████████╗██╗ * ██╔════╝ ██╔════╝╚══██╔══╝██║ * ██║ ███╗██║ ██║ ██║ * ██║ ██║██║ ██║ ██║ * ╚██████╔╝╚██████╗ ██║ ███████╗ * ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝ * Geophysical Computational Tools & Library (GCTL) * * Copyright (c) 2022 Yi Zhang (yizhang-geo@zju.edu.cn) * * GCTL is distributed under a dual licensing scheme. You can redistribute * it and/or modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either version 2 * of the License, or (at your option) any later version. You should have * received a copy of the GNU Lesser General Public License along with this * program. If not, see . * * If the terms and conditions of the LGPL v.2. would prevent you from using * the GCTL, please consider the option to obtain a commercial license for a * fee. These licenses are offered by the GCTL's original author. As a rule, * licenses are provided "as-is", unlimited in time for a one time fee. Please * send corresponding requests to: yizhang-geo@zju.edu.cn. Please do not forget * to include some description of your company and the realm of its activities. * Also add information on how to contact you by electronic and paper mail. ******************************************************/ #include "utc_time.h" const int DaysInMonth[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; const std::string MonthName[13] = {"Null", "Jan.", "Feb.", "Mar.", "Apr."," May", "Jun.", "Jul.", "Aug.", "Sep.", "Oct.", "Nov.", "Dec."}; // Function returns true if the given year is a leap year and returns false otherwise. bool gctl::is_leap_year(int year) { if (year < 1) { throw std::invalid_argument("[GCTL_SEIMIC] Invalid date input for gctl::is_leap_year(...)"); } return year % 4 == 0 && ( year % 100 != 0 || year % 400 == 0 ); } // Compute the month and day corresponding to the Julian day within the given year. void gctl::month_and_day(int year, int julian_day, int &month, int &day ) { if (year < 1 || julian_day > 366) { throw std::invalid_argument("[GCTL_SEIMIC] Invalid date input for gctl::month_and_day(...)"); } if (!is_leap_year(year) && julian_day > 365) { throw std::invalid_argument("[GCTL_SEIMIC] Invalid date input for gctl::month_and_day(...)"); } bool month_found = false; month = 1; // Loop through the months, subtracting the days in this month // from the Julian day, until the month is found where the // remaining days is less than or equal to the total days in the month. while (!month_found) { // Calculate the days in this month by looking it up in the array. Add one if it is a leap year. int days_this_month = DaysInMonth[month]; if (month == 2 && is_leap_year(year)) ++days_this_month; if (julian_day <= days_this_month) month_found = true; // Done! else { julian_day -= days_this_month; ++ month; } } day = julian_day; return; } // Compute the Julian day void gctl::julian_day(int year, int month, int day, int &julian_day) { if (year < 1 || month < 1 || month > 12 || day < 1) { throw std::invalid_argument("[GCTL_SEIMIC] Invalid date input for gctl::julian_day(...)"); } if (day > DaysInMonth[month] && !(month == 2 && is_leap_year(year) && day < 30)) { throw std::invalid_argument("[GCTL_SEIMIC] Invalid date input for gctl::julian_day(...)"); } julian_day = day; for (size_t i = 0; i < month; i++) { julian_day += DaysInMonth[i]; } if (month > 2 && is_leap_year(year)) { julian_day++; } return; } void gctl::decimal_year2date(double deci_year, int &year, int &month, int &day) { year = floor(deci_year); int julian_day; if (is_leap_year(year)) { julian_day = round(366.0*(deci_year - year)); julian_day = std::max(std::min(julian_day, 366), 1); } else { julian_day = round(365.0*(deci_year - year)); julian_day = std::max(std::min(julian_day, 365), 1); } month_and_day(year, julian_day, month, day); return; } gctl::UTC_TIME::UTC_TIME() { year = 1900; month = 1; day = 1; julday = 1; hour = 0; mint = 0; sec = 0; msec = 0; } gctl::UTC_TIME::UTC_TIME(int y, int m, int d, int h, int mt, int s, int ms) { set_time(y, m, d, h, mt, s, ms); } gctl::UTC_TIME::UTC_TIME(int y, int jd, int h, int mt, int s, int ms) { set_time(y, jd, h, mt, s, ms); } gctl::UTC_TIME::UTC_TIME(std::string t_str) { set_time(t_str); } void gctl::UTC_TIME::set_time(int y, int m, int d, int h, int mt, int s, int ms) { if (h < 0 || h > 23 || mt < 0 || mt > 59 || s < 0 || s > 59 || ms < 0 || ms > 999) { throw std::invalid_argument("[GCTL_SEISMIC] Invalid time parameters for gctl::UTC_TIME::set_time(...)"); } if (y < 1900 || m < 1 || m > 12 || d < 1 || d > 31) { throw std::invalid_argument("[GCTL_SEISMIC] Invalid date parameters for gctl::UTC_TIME::set_time(...)"); } if (d > DaysInMonth[m]) { if (is_leap_year(y) && m == 2 && d == 29){} else throw std::invalid_argument("[GCTL_SEISMIC] Invalid date parameters for gctl::UTC_TIME::set_time(...)"); } //h %= 24; mt %= 60; s %= 60; ms %= 1000; year = y; month = m; day = d; hour = h; mint = mt; sec = s; msec = ms; julian_day(year, month, day, julday); return; } void gctl::UTC_TIME::set_time(int y, int jd, int h, int mt, int s, int ms) { if (h < 0 || h > 23 || mt < 0 || mt > 59 || s < 0 || s > 59 || ms < 0 || ms > 999) { throw std::invalid_argument("[GCTL_SEISMIC] Invalid time parameters for gctl::UTC_TIME::set_time(...)"); } if (y < 1900) { throw std::invalid_argument("[GCTL_SEISMIC] Invalid date parameters for gctl::UTC_TIME::set_time(...)"); } if (jd > 365) { if (is_leap_year(y) && jd == 366){} else throw std::invalid_argument("[GCTL_SEISMIC] Invalid date parameters for gctl::UTC_TIME::set_time(...)"); } //h %= 24; mt %= 60; s %= 60; ms %= 1000; year = y; julday = jd; hour = h; mint = mt; sec = s; msec = ms; month_and_day(year, julday, month, day); return; } void gctl::UTC_TIME::set_time(std::string t_str) { int y, m, d, h, mt, s, ms; if (7 != sscanf(t_str.c_str(), "%d-%d-%dT%d:%d:%d.%d", &y, &m, &d, &h, &mt, &s, &ms)) { throw std::invalid_argument("[GCTL_SEISMIC] Invalid time string for gctl::UTC_TIME::set_time(...)"); } if (h < 0 || h > 23 || mt < 0 || mt > 59 || s < 0 || s > 59 || ms < 0 || ms > 999) { throw std::invalid_argument("[GCTL_SEISMIC] Invalid time parameters for gctl::UTC_TIME::set_time(...)"); } if (y < 1900 || m < 1 || m > 12 || d < 1 || d > 31) { throw std::invalid_argument("[GCTL_SEISMIC] Invalid date parameters for gctl::UTC_TIME::set_time(...)"); } if (d > DaysInMonth[m]) { if (is_leap_year(y) && m == 2 && d == 29){} else throw std::invalid_argument("[GCTL_SEISMIC] Invalid date parameters for gctl::UTC_TIME::set_time(...)"); } year = y; month = m; day = d; hour = h; mint = mt; sec = s; msec = ms; julian_day(year, month, day, julday); return; } void gctl::UTC_TIME::set_rdseed_time(std::string t_str) { sscanf(t_str.c_str(), "%d,%d,%d:%d:%d.%d", &year, &julday, &hour, &mint, &sec, &msec); msec = round((double) msec/10); month_and_day(year, julday, month, day); return; } void gctl::UTC_TIME::set_to_now() { struct timeval tv; //struct timezone tz; //gettimeofday(&tv, &tz); gettimeofday(&tv, nullptr); std::tm cur_t = *gmtime(&tv.tv_sec); year = cur_t.tm_year + 1900; month = cur_t.tm_mon + 1; day = cur_t.tm_mday; hour = cur_t.tm_hour; mint = cur_t.tm_min; sec = cur_t.tm_sec; msec = tv.tv_usec/1000; julian_day(year, month, day, julday); return; } void gctl::UTC_TIME::add_duration(double s) { if (s < 0) { throw std::invalid_argument("[GCTL_SEIMIC] Invalid time duration for gctl::UTC_TIME::add_duration(...)"); } msec += round(1000*(s - floor(s))); sec += msec/1000; msec %= 1000; int t = floor(s); sec += t%60; mint += sec/60; sec %= 60; t = t/60; mint += t%60; hour += mint/60; mint %= 60; t = t/60; hour += t%24; julday += hour/24; hour %= 24; t = t/24; julday += t; while (julday > 366) { if (!is_leap_year(year) && julday == 365) break; if (is_leap_year(year)) {julday -= 366; year++;} else {julday -= 365; year++;} } month_and_day(year, julday, month, day); return; } void gctl::UTC_TIME::round_up_to(time_unit tu) { if (tu == Second) { if (msec != 0) { msec = 0; add_duration(1); } return; } else if (tu == Mintue) { if (msec != 0 || sec != 0) { msec = 0; add_duration(60 - sec); } return; } else if (tu == Hour) { if (msec != 0 || sec != 0 || mint != 0) { sec = 0; msec = 0; add_duration((60 - mint)*60); } return; } else if (tu == Day) { if (msec != 0 || sec != 0 || mint != 0 || hour != 0) { mint = 0; sec = 0; msec = 0; add_duration((24 - hour)*3600); } return; } else if (tu == Month || tu == Year) { throw std::invalid_argument("[GCTL_SEISMIC] Invalid parameter for gctl::UTC_TIME::round_up_to(...)"); } else return; } double gctl::UTC_TIME::diff_sec(const UTC_TIME &t) const { double d = sec - t.sec + 0.001*(msec - t.msec) + 60*(mint - t.mint) + 3600*(hour - t.hour) + 24*3600*(julday - t.julday) + 365*24*3600*(year - t.year); if (year > t.year) { for (int i = t.year; i < year; i++) { if (is_leap_year(i)) d += 24*3600; } } if (year < t.year) { for (int i = year; i < t.year; i++) { if (is_leap_year(i)) d -= 24*3600; } } return d; } std::string gctl::UTC_TIME::time_str(bool symbolic) const { double f_sec = 1.0*sec + 0.001*msec; std::stringstream ss; ss << std::fixed << std::setprecision(3) << f_sec; std::string s_sec = ss.str(); if (symbolic) return MonthName[month] + " " + std::to_string(day) + " " + std::to_string(year) + " " + std::to_string(hour)+":"+std::to_string(mint)+":"+ s_sec; return std::to_string(year)+"-"+std::to_string(month)+"-"+std::to_string(day)+"T"+std::to_string(hour)+":"+std::to_string(mint)+":"+s_sec; } std::string gctl::UTC_TIME::rdseed_time_str() const { double f_sec = 1.0*sec + 0.001*msec; std::stringstream ss; ss << std::fixed << std::setprecision(4) << f_sec; std::string s_str = ss.str(); if (sec < 10) s_str = "0" + s_str; std::string jday_str = std::to_string(julday); if (julday < 10) jday_str = "00" + jday_str; else if (julday < 100) jday_str = "0" + jday_str; std::string h_str = std::to_string(hour); if (hour < 10) h_str = "0" + h_str; std::string m_str = std::to_string(mint); if (mint < 10) m_str = "0" + m_str; return std::to_string(year)+"."+jday_str+"."+h_str+"."+m_str+"."+s_str; } bool gctl::operator==(const gctl::UTC_TIME &ta, const gctl::UTC_TIME &tb) { if (ta.year != tb.year || ta.julday != tb.julday || ta.hour != tb.hour || ta.mint != tb.mint || ta.sec != tb.sec || ta.msec != tb.msec) { return false; } return true; } bool gctl::operator!=(const gctl::UTC_TIME &ta, const gctl::UTC_TIME &tb) { if (ta.year != tb.year || ta.julday != tb.julday || ta.hour != tb.hour || ta.mint != tb.mint || ta.sec != tb.sec || ta.msec != tb.msec) { return true; } return false; } bool gctl::operator<(const gctl::UTC_TIME &ta, const gctl::UTC_TIME &tb) { if (tb.year < ta.year) return false; else if (tb.year > ta.year) return true; if (tb.julday < ta.julday) return false; else if (tb.julday > ta.julday) return true; if (tb.hour < ta.hour) return false; else if (tb.hour > ta.hour) return true; if (tb.mint < ta.mint) return false; else if (tb.mint > ta.mint) return true; if (tb.sec < ta.sec) return false; else if (tb.sec > ta.sec) return true; if (tb.msec <= ta.msec) return false; else return true; } bool gctl::operator<=(const gctl::UTC_TIME &ta, const gctl::UTC_TIME &tb) { if (tb.year < ta.year) return false; else if (tb.year > ta.year) return true; if (tb.julday < ta.julday) return false; else if (tb.julday > ta.julday) return true; if (tb.hour < ta.hour) return false; else if (tb.hour > ta.hour) return true; if (tb.mint < ta.mint) return false; else if (tb.mint > ta.mint) return true; if (tb.sec < ta.sec) return false; else if (tb.sec > ta.sec) return true; if (tb.msec < ta.msec) return false; else return true; }