0

I'm using std::chrono to add year, month, day etc in turn.

I assume that local time is 2023.2.28 UTC. My timezone is UTC+0800 and the date of my computer is correct.

#include <iostream>
#include <ctime>
#include <chrono>

using namespace std;
using namespace chrono;

int main (void)
{
    using years = duration<int, ratio<31556952>>;
    using months = duration<int, ratio<2629746>>;
    using weeks = duration< int, ratio<3600 * 24 * 7>>;
    using days = duration<int, ratio<3600 * 24>>;
    using hours = std::chrono::hours;
    using minutes = std::chrono::minutes;
    using seconds = std::chrono::seconds;
    
    // epoch: 1970.1.1 00:00:00 UTC
    //assume that localtime is: 2023.2.28 17:00:00 UTC
    
    system_clock::time_point total (seconds (0));
    years year (2023     - 1970);
    months month (2     - 1);
    days day (28     - 1);
    hours hour (17);
    minutes minute (0);
    seconds second (0);
    
    total += year;
    total += month;
    total += day;
    total += hour;
    total += minute;
    total += second;
    
    time_t UTC_current_time = system_clock::to_time_t (total);
    tm *from_localtime = localtime (&UTC_current_time);
    cout << "ctime()\n\t" << ctime (&UTC_current_time);
    cout << "localtime() and asctime()\n\t" << asctime (from_localtime);
    tm *from_gtime = gmtime (&UTC_current_time);
    cout << "gmtime() and asctime()\n\t" << asctime (from_gtime);
    
}

I think it should print Tue Feb 28 17:00:00 2023 or 8 hours added.

But the output is strange:

ctime()
    Tue Feb 28 07:56:42 2023
localtime() and asctime()
    Tue Feb 28 07:56:42 2023
gmtime() and asctime()
    Mon Feb 27 23:56:42 2023

I wonder why the first version it is not correct. Is there any secrets in std::chrono ?

Below are my trys:

I used to try another version using struct tm, it succeeded:

#include <iostream>
#include <ctime>
#include <chrono>

using namespace std;
using namespace chrono;

int main (void)
{
    tm total_tm = {};
    total_tm.tm_year = 2023 - 1900;
    total_tm.tm_mon = 2 - 1;
    total_tm.tm_mday = 28;
    total_tm.tm_hour = 17;
    
    //I learnt that mktime() won't be affected by timezone and DST.
    time_t total = mktime (&total_tm);
    
    cout << "ctime()\n\t" << ctime (&total);
    cout << "asctime()\n\t" << asctime (&total_tm);
}

The output is:

ctime()
    Tue Feb 28 17:00:00 2023
asctime()
    Tue Feb 28 17:00:00 2023

chatGPT told me to add them directly:

#include <iostream>
#include <chrono>
#include <ctime>

using namespace std;
using namespace chrono;

int main()
{
    // epoch: 1970.1.1 00:00:00 UTC
    // assume that localtime is: 2023.2.28 17:00:00 UTC
    system_clock::time_point total = system_clock::from_time_t (0);
    total += 31556952s * 53; // 53 years
    total += 2629746s * 1;   // 1 month
    total += 86400s * 27;    // 27 days
    total += 3600s * 17;     // 17 hours
    total += 60s * 0;        // 0 minutes
    total += 0s;             // 0 seconds
    
    time_t UTC_current_time = system_clock::to_time_t (total);
    cout << "ctime()\n\t" << ctime (&UTC_current_time);
    tm *from_gmtime = gmtime (&UTC_current_time);
    tm *from_localtime = localtime (&UTC_current_time);
    cout << "gmtime() and asctime()\n\t" << asctime (from_gmtime);
    cout << "localtime() and asctime()\n\t" << asctime (from_localtime);
    return 0;
}

But the output is more strange:

ctime()
    Tue Feb 28 07:56:42 2023
gmtime() and asctime()
    Tue Feb 28 07:56:42 2023
localtime() and asctime()
    Tue Feb 28 07:56:42 2023
barbyQAQ
  • 45
  • 5
  • I compiled them with `-std=c++11`.Since the `system_clock::time_point` use `nanoseconds` as duration, it will not be truncated. – barbyQAQ Feb 28 '23 at 13:08
  • I think you can find an explanation here: https://stackoverflow.com/questions/75135045/c-adding-years-and-days-using-date-h/75135967#75135967 – Frodyne Feb 28 '23 at 13:17
  • 1
    a year might have `31556952` seconds on average but you can't use that to calculate dates, you have to take into account leap years. The same goes for months, no month is `2629746` seconds long, it varies from month to month. If you have c++20 just use the c++20 chrono library – Alan Birtles Feb 28 '23 at 13:17
  • 1
    Asking ChatGPT about programming is like asking your drunk crazy uncle for a political analysis. The grammar may be correct and the words make superficial sense, but it's really just cluelessly rambling. – molbdnilo Feb 28 '23 at 13:23
  • @AlanBirtles I use `std::chrono::years` with `-std=c++20` to replace the `years` defined by myself. It has no effect. In fact, the`31556952` and other number come from the headers ``. – barbyQAQ Feb 28 '23 at 13:35
  • Epoch for `std::chrono::system_clock` is [unspecified](https://en.cppreference.com/w/cpp/chrono/system_clock) ergo you have to relay on `from_time_t`. Note there is HowardHinnant/date library which can help and was [incorporated into C++20](https://en.cppreference.com/w/cpp/chrono). – Marek R Feb 28 '23 at 13:36
  • @MarekR I learned that the default constructor of `system_clock::time_point` will set the variable to 0. I used to use `from_time_t(0)` to initial it and the result is same. – barbyQAQ Feb 28 '23 at 13:40
  • I think `month` can be a problem too. Note this is arbitrary unit. Can be 30,31,28,29 days long. – Marek R Feb 28 '23 at 13:43
  • @MarekR, nitpick: The link you have for `std::chrono::system_clock` says the epoch is _specified_, at least in the current standard. ;-) – Howard Hinnant Feb 28 '23 at 14:59

0 Answers0