2

I'm quite new to C++. I need to get the current year and store it in an int.

I've come to this solution:

std::time_t result = std::time(nullptr);
std::istringstream iss(ctime(&result));

iss.ignore(20);
int year;
iss >> year;

I find this solution a bit ugly, even if it works, as it doesn't seem very robust and it takes many steps to do not very much.

Would there be a better way to do it?

Jonas Daverio
  • 251
  • 2
  • 3
  • 7

5 Answers5

11

C++20, you can use std::chrono for such purpose.

P0355R7 Extending to Calendars and Time Zones

#include <iostream>
#include <format>
#include <chrono>
int main()
{
    const auto now = std::chrono::system_clock::now();
    std::cout << std::format("{:%Y}", now); // => 2021
}
yumetodo
  • 1,147
  • 7
  • 19
6

The conversion of time_t to string with a string parsing afterwards appears to me unnecessary complicated and error-prone. As already complained in @Ted's comment, this may introduce localization of text output which may make the parsing non-robust.

Together with std::time(), there are available

  • std::localtime()

    Converts given time since epoch as std::time_t value into calendar time, expressed in local time.

  • std::gmtime()

    Converts given time since epoch as std::time_t value into calendar time, expressed in Coordinated Universal Time (UTC).

Both return a pointer to a struct tm which contains among others a public member

int tm_year years since 1900

A small sample:

#include <ctime>
#include <iostream>

int main()
{
  std::time_t t = std::time(nullptr);
  std::tm *const pTInfo = std::localtime(&t);
  std::cout << "Current year: " << 1900 + pTInfo->tm_year << '\n';
}

Output:

Current year: 2019

Live Demo on coliru

Scheff's Cat
  • 19,528
  • 6
  • 28
  • 56
2
#include <ctime>
#include <iostream>
using namespace std;

int main()
{
time_t current_time;

current_time = time(NULL);
int a;
a = 1970 + current_time / 31537970; 
cout << a << " is the current year.";

return 0;
}
1

In short, the following get_this_year() function should work for you in a C++20 way.

It will return you an int for the current year.

// year.cpp

#include <chrono>
#include <iostream>

int get_current_year() {
  using namespace std::chrono;
  return static_cast<int>(
      year_month_day{time_point_cast<days>(system_clock::now())}.year());
}

int main() {
  int year = get_current_year();
  std::cout << year << std::endl; // 2022
}

This should compile with e.g. g++ -std=c++20 year.cpp.


But I also would like to expand it in a verbose way, explaining what happened for each step.

// year.cpp

#include <chrono>
#include <iostream>

int get_current_year() {
  using namespace std::chrono;
  auto now = system_clock::now();           // 1. get time_point for now
  auto today = time_point_cast<days>(now);  // 2. cast to time_point for today
  auto ymd = year_month_day(today);         // 3. convert to year_month_day 
  auto year = ymd.year();                   // 4. get year from year_month_day
  return static_cast<int>(year);            // 5. an explicit cast is required 
}

int main() {
  int year = get_current_year();
  std::cout << year << std::endl; // 2022
}

Now, even more verbosely, explicitly spelling out all the types -

// year.cpp

#include <chrono>
#include <iostream>

int get_current_year() {
  std::chrono::time_point<std::chrono::system_clock,
                          std::chrono::system_clock::duration>
      now = std::chrono::system_clock::now();
  std::chrono::time_point<std::chrono::system_clock, std::chrono::days> today =
      std::chrono::time_point_cast<std::chrono::days>(now);
  std::chrono::year_month_day ymd = std::chrono::year_month_day(today);
  std::chrono::year year = ymd.year();
  return static_cast<int>(year);
}

int main() {
  int year = get_current_year();
  std::cout << year << std::endl; // 2022
}

There are essentially 2 types of format to represent a point in time:

  1. serial-based - e.g. this time point is x seconds since an epoch (e.g. 1 Jan 1970)
  2. field-based - e.g. this time point is year/month/day

From the system clock we get a serial-based time point. We need to convert it to a field-based time point. Then from this field-based time point we extract the year.

aafulei
  • 2,085
  • 12
  • 27
0

Here's an easy way:

string timestamp_str = __TIMESTAMP__;
auto timestamp_tokens = split(timestamp_str, ' ');
std::cout << timestamp_tokens[timestamp_tokens.size() - 1] << std::endl;

The split() function splits the string by the delimiter 'space'. You may write a custom method to get the last token instead(the last token is year). You can get the implementation of split() from this link. Here's a sample implementation:

vector<string> split(string string_with_delim, char delim)
{
    auto i = 0;
    vector<string> result;

    auto pos = string_with_delim.find(delim);

    while(pos != string::npos)
    {
        string res = string_with_delim.substr(i, pos-i);
        result.push_back(res);
        i = ++pos;
        pos = string_with_delim.find(delim, pos);
    }

    result.push_back(string_with_delim.substr(i, string_with_delim.size()));
    return result;
}
argcv
  • 39
  • 6