Coming dates in C++ - c++

I have the following code, with which I get today's date. I would like to know if from this code I can obtain the date 6 and 12 months later. Or how can I get these dates?
Thank you!
#include <iostream>
#include <ctime>
using namespace std;
int main() {
time_t hoy = time(0);
char* fecha = ctime(&hoy);
cout << "La fecha es: " << fecha << endl;
}
I try to make a program with which the user planned the fertilization period of certain plants, among other things, that is why I try to make the program print the date of the next 6 and 12 months, from today (well, from the day in which the user registers a plant). So far I have not succeeded. :(

If you want 6 months from a given date, counting months and not days, the solution is to split the date and increment manually the months and years. Then you will have to adjust for year wrapping and month wrapping as well.
These functions are defined in C89/C99 so not specific to Posix.
The biggest advantage of this solution is that you don't have to link against any external library. It should be available with your compiler on Linux, Mac and even on Windows/MS Visual Studio.
#include <time.h>
#include <stdint.h>
#include <stdio.h>
time_t add_months( time_t from_date, uint32_t months ) {
// Split date
struct tm* tmptr = ::gmtime( &from_date );
if ( tmptr == nullptr ) return 0;
struct tm date = *tmptr;
// Save original date
struct tm org = date;
// Add months/years
uint32_t years = months/12;
months = months % 12;
date.tm_year += years;
date.tm_mon += months;
// Correct for year wrap
if ( date.tm_mon>11 ) {
date.tm_mon -= 12;
date.tm_year += 1;
}
// Convert back to time_t
time_t dt = mktime( &date );
// Check for end of month wrap
// eg Jan/30 -> Mar/02 -> Feb/28
if ( date.tm_mday != org.tm_mday ) {
dt -= date.tm_mday * 86400;
}
return dt;
}
int main() {
time_t now = time(nullptr);
time_t later = add_months( now, 6 );
struct tm* tmptr = ::gmtime( &now );
if ( tmptr!=nullptr ) {
printf( "Now: %s\n", asctime(tmptr));
}
tmptr = ::gmtime( &later );
if ( tmptr!=nullptr ) {
printf( "Later: %s\n", asctime(tmptr));
}
}
Result:
Program stdout
Now: Thu Jan 6 01:47:07 2022
Later: Wed Jul 6 01:47:07 2022
Godbolt: https://godbolt.org/z/vE4xhsP3E

Since it seems that you only need a rough approximation of the future date for your use-case, you can probably get by with simply assuming that every month has about 30.4 days in it, and calculating a number of seconds into the future based on that. You can then use ctime() to generate a new date-string for that future time:
#include <stdio.h>
#include <time.h>
int main(int argc, const char ** argv)
{
const time_t now = time(NULL);
// Assuming every month has ~30.4 days; that's not really true
// but it's close enough for plant fertilization purposes, I think
const time_t ROUGHLY_ONE_MONTH_IN_SECONDS = (30*24*60*60) + (10*60*60);
for (int i=0; i<=12; i++)
{
const time_t then = (now+(i*ROUGHLY_ONE_MONTH_IN_SECONDS));
printf("In %i months, the approximate date/time will be: %s", i, ctime(&then));
}
return 0;
}
Note that for an exact answer you'd need to take the varying lengths of months into account, plus leap years and God-only-knows-what-else, and in that case you'd probably be better off using a modern date/time library instead.

I would use struct tm and convert your time_t using gmtime.
Then you can add 6 or 12 to tm_mon (don't forget to handle the overflow by adding 1 to tm_year), and convert back to time_t with mktime

Try Boost date time library? Easy to use,doesnot have to learn time conversions or anything else,focus on what you want to do.
#include "boost/date_time/gregorian/gregorian.hpp"
#include <iostream>
#include <string>
int
main(int argc, char* argv[])
{
using namespace boost::gregorian;
try {
//Read ISO Standard(CCYYMMDD) and output ISO Extended
std::string ud("20011009"); //2001-Oct-09
date d1(from_undelimited_string(ud));
std::cout << "date is="<<to_iso_extended_string(d1) << std::endl;
{
boost::gregorian::months monthObj(6);
date d2(d1 + monthObj);
std::cout << "date 6 month later is=" << to_iso_extended_string(d2) << std::endl;
}
{
boost::gregorian::months monthObj(12);
date d2(d1 + monthObj);
std::cout << "date 12 month later is=" << to_iso_extended_string(d2) << std::endl;
}
}
catch (std::exception& e) {
std::cout << " Exception: " << e.what() << std::endl;
}
return 0;
}

Related

How to correctly read and increment dates in c++ using localtime and mktime?

I am struggling to execute a simple task. I want to take a date parameter from the command line argument and increment it several times by 1 day. The basic program should:
read the command line argument as the starting date, and
loop several times, incrementing that date by 1 day every time.
I convert the char* command line argument to a struct tm, then convert the struct tm to a time_t and add 60 * 60 * 24 = 1 day to it. I convert it back to struct tm to print it.
Here is the code:
#include <iostream>
#include <cstdlib>
#include <string>
#include "time.h"
int main(int argc, char *argv[])
{
char* start_date;
tm tm_start_date = {}; // solution: needs initialization
start_date = argv[1];
strptime(start_date, "%Y-%m-%d", &tm_start_date); // YYYY-MM-DD
char ch_stmt_date[11] = "";
time_t t_stmt_date = 0;
tm tm_stmt_date = {}; // solution: needs initialization;
tm_stmt_date = tm_start_date;
// time_t -> tm localtime_r(time_t, tm)
// tm -> time_t mktime(tm) returns time_t
std::cout << "start_date: " << start_date << " / tm_start_date: " << std::to_string(1900 + tm_start_date.tm_year) + std::to_string(tm_start_date.tm_mon + 1) +
std::to_string(tm_start_date.tm_mday) << std::endl;
// increment by 1 day per iteration
for (int i=0; i<5; i++)
{
// tm -> t_time
t_stmt_date = mktime(&tm_stmt_date);
std::cout << "t_stmt_date: " << t_stmt_date << std::endl;
// + 1 day
t_stmt_date += 60*60*24;
std::cout << "t_stmt_date: " << t_stmt_date << std::endl;
// time_t -> tm
localtime_r(&t_stmt_date, &tm_stmt_date);
strftime (ch_stmt_date, 11, "%Y-%m-%d", &tm_stmt_date);
std::cout << "ch_stmt_date: " << ch_stmt_date << std::endl;
}
return EXIT_SUCCESS;
}
The start date is correctly read and parsed into the struct tm.
However, subsequently I get one of two behaviors of the program:
Either I get a -1 on the first call of t_stmt_date = mktime(&tm_stmt_date); and a value of t_stmt_date: 86399 (1970-01-02) in the output. The rest of the loop then works correctly and iterates 5 times, incrementing 1970-01-02 by 1 day.
Or, the same code using the same command line parameter parses a nonsensical value on the first call of t_stmt_date = mktime(&tm_stmt_date); in the loop which is not a valid date, which, however is also correctly incremented by 60*60*24 on each of the 5 loops.
At this point I am desperate to understand the issue. I am working on Ubuntu 20.04 using gcc.
Thanks for your help.
Edit: Initializing the struct tm did the trick!
[NOTE]
You explicitly mention "using localtime and mktime" in the question's title, but I wasn't sure though after reading the rest of the text if that was mandatory, or you just needed to get a task done.
If you cannot use other libraries, just let me know and I'll remove this answer.
You could use std::chrono and Howard Hinnant's date library (C++11 onwards, header-only).
Or, should you be able to use a C++20 compiler, you would only need std::chrono.
[Demo]
#include <chrono>
#include <iostream> // cout
#include <sstream> // istringstream
#include <string>
#include "date/date.h"
int main()
{
namespace ch = std::chrono;
namespace dt = date;
const std::string start_date{"2022-01-31"}; // date
std::istringstream iss{ start_date }; // to string stream
dt::sys_days start_day{}; // to a time point with a day duration
dt::from_stream(iss, "%Y-%m-%d", start_day);
for (auto day{start_day}, end_day{start_day + dt::days{3}};
day < end_day;
day += dt::days{1}) // with which we can do date arithmetic
{
std::cout << dt::format("%Y-%m-%d\n", day);
}
}
// Outputs:
//
// 2022-01-31
// 2022-02-01
// 2022-02-02

From xs:dateTime to std::chrono::timepoint [duplicate]

Consider a historic date string of format:
Thu Jan 9 12:35:34 2014
I want to parse such a string into some kind of C++ date representation, then calculate the amount of time that has passed since then.
From the resulting duration I need access to the numbers of seconds, minutes, hours and days.
Can this be done with the new C++11 std::chrono namespace? If not, how should I go about this today?
I'm using g++-4.8.1 though presumably an answer should just target the C++11 spec.
std::tm tm = {};
std::stringstream ss("Jan 9 2014 12:35:34");
ss >> std::get_time(&tm, "%b %d %Y %H:%M:%S");
auto tp = std::chrono::system_clock::from_time_t(std::mktime(&tm));
GCC prior to version 5 doesn't implement std::get_time. You should also be able to write:
std::tm tm = {};
strptime("Thu Jan 9 2014 12:35:34", "%a %b %d %Y %H:%M:%S", &tm);
auto tp = std::chrono::system_clock::from_time_t(std::mktime(&tm));
New answer for old question. Rationale for the new answer: The question was edited from its original form because tools at the time would not handle exactly what was being asked. And the resulting accepted answer gives a subtly different behavior than what the original question asked for.
I'm not trying to put down the accepted answer. It's a good answer. It's just that the C API is so confusing that it is inevitable that mistakes like this will happen.
The original question was to parse "Thu, 9 Jan 2014 12:35:34 +0000". So clearly the intent was to parse a timestamp representing a UTC time. But strptime (which isn't standard C or C++, but is POSIX) does not parse the trailing UTC offset indicating this is a UTC timestamp (it will format it with %z, but not parse it).
The question was then edited to ask about "Thu Jan 9 12:35:34 2014". But the question was not edited to clarify if this was a UTC timestamp, or a timestamp in the computer's current local timezone. The accepted answer implicitly assumes the timestamp represents the computer's current local timezone because of the use of std::mktime.
std::mktime not only transforms the field type tm to the serial type time_t, it also performs an offset adjustment from the computer's local time zone to UTC.
But what if we want to parse a UTC timestamp as the original (unedited) question asked?
That can be done today using this newer, free open-source library.
#include "date/date.h"
#include <iostream>
#include <sstream>
int
main()
{
using namespace std;
using namespace date;
istringstream in{"Thu, 9 Jan 2014 12:35:34 +0000"};
sys_seconds tp;
in >> parse("%a, %d %b %Y %T %z", tp);
}
This library can parse %z. And date::sys_seconds is just a typedef for:
std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>
The question also asks:
From the resulting duration I need access to the numbers of seconds, minutes, hours and days.
That part has remained unanswered. Here's how you do it with this library.
#include "date/date.h"
#include <chrono>
#include <iostream>
#include <sstream>
int
main()
{
using namespace std;
using namespace date;
istringstream in{"Thu, 9 Jan 2014 12:35:34 +0000"};
sys_seconds tp;
in >> parse("%a, %d %b %Y %T %z", tp);
auto tp_days = floor<days>(tp);
auto hms = hh_mm_ss<seconds>{tp - tp_days};
std::cout << "Number of days = " << tp_days.time_since_epoch() << '\n';
std::cout << "Number of hours = " << hms.hours() << '\n';
std::cout << "Number of minutes = " << hms.minutes() << '\n';
std::cout << "Number of seconds = " << hms.seconds() << '\n';
}
floor<days> truncates the seconds-precision time_point to a days-precision time_point. If you subtract the days-precision time_point from tp, you're left with a duration that represents the time since midnight (UTC).
The type hh_mm_ss<seconds> takes any duration convertible to seconds (in this case time since midnight) and creates a {hours, minutes, seconds} field type with getters for each field. If the duration has precision finer than seconds this field type will also have a getter for the subseconds. Prior to C++17, one has to specify that finer duration as the template parameter. In C++17 and later it can be deduced:
auto hms = hh_mm_ss{tp - tp_days};
Finally, one can just print out all of these durations. This example outputs:
Number of days = 16079d
Number of hours = 12h
Number of minutes = 35min
Number of seconds = 34s
So 2014-01-09 is 16079 days after 1970-01-01.
Here is the full example but at milliseconds precision:
#include "date/date.h"
#include <chrono>
#include <iostream>
#include <sstream>
int
main()
{
using namespace std;
using namespace std::chrono;
using namespace date;
istringstream in{"Thu, 9 Jan 2014 12:35:34.123 +0000"};
sys_time<milliseconds> tp;
in >> parse("%a, %d %b %Y %T %z", tp);
auto tp_days = floor<days>(tp);
hh_mm_ss hms{tp - tp_days};
std::cout << tp << '\n';
std::cout << "Number of days = " << tp_days.time_since_epoch() << '\n';
std::cout << "Number of hours = " << hms.hours() << '\n';
std::cout << "Number of minutes = " << hms.minutes() << '\n';
std::cout << "Number of seconds = " << hms.seconds() << '\n';
std::cout << "Number of milliseconds = " << hms.subseconds() << '\n';
}
Output:
2014-01-09 12:35:34.123
Number of days = 16079d
Number of hours = 12h
Number of minutes = 35min
Number of seconds = 34s
Number of milliseconds = 123ms
This library is now part of C++20, but is in namespace std::chrono and found in the header <chrono>.
This is rather C-ish and not as elegant of a solution as Simple's answer, but I think it might work. This answer is probably wrong but I'll leave it up so someone can post corrections.
#include <iostream>
#include <ctime>
int main ()
{
struct tm timeinfo;
std::string buffer = "Thu, 9 Jan 2014 12:35:00";
if (!strptime(buffer.c_str(), "%a, %d %b %Y %T", &timeinfo))
std::cout << "Error.";
time_t now;
struct tm timeinfo2;
time(&now);
timeinfo2 = *gmtime(&now);
time_t seconds = difftime(mktime(&timeinfo2), mktime(&timeinfo));
time(&seconds);
struct tm result;
result = *gmtime ( &seconds );
std::cout << result.tm_sec << " " << result.tm_min << " "
<< result.tm_hour << " " << result.tm_mday;
return 0;
}
Cases covered (code is below):
since a give date until now
long int min0 = getMinutesSince( "2005-02-19 12:35:00" );
since the epoch until now
long int min1 = getMinutesSince1970( );
between two date+hours (since the epoch until a given date)
long int min0 = getMinutesSince1970Until( "2019-01-18 14:23:00" );
long int min1 = getMinutesSince1970Until( "2019-01-18 14:27:00" );
cout << min1 - min0 << endl;
Complete code:
#include <iostream>
#include <chrono>
#include <sstream>
#include <string>
#include <iomanip>
using namespace std;
// ------------------------------------------------
// ------------------------------------------------
long int getMinutesSince1970Until( string dateAndHour ) {
tm tm = {};
stringstream ss( dateAndHour );
ss >> get_time(&tm, "%Y-%m-%d %H:%M:%S");
chrono::system_clock::time_point tp = chrono::system_clock::from_time_t(mktime(&tm));
return
chrono::duration_cast<chrono::minutes>(
tp.time_since_epoch()).count();
} // ()
// ------------------------------------------------
// ------------------------------------------------
long int getMinutesSince1970() {
chrono::system_clock::time_point now = chrono::system_clock::now();
return
chrono::duration_cast<chrono::minutes>( now.time_since_epoch() ).count();
} // ()
// ------------------------------------------------
// ------------------------------------------------
long int getMinutesSince( string dateAndHour ) {
tm tm = {};
stringstream ss( dateAndHour );
ss >> get_time(&tm, "%Y-%m-%d %H:%M:%S");
chrono::system_clock::time_point then =
chrono::system_clock::from_time_t(mktime(&tm));
chrono::system_clock::time_point now = chrono::system_clock::now();
return
chrono::duration_cast<chrono::minutes>(
now.time_since_epoch()-
then.time_since_epoch()
).count();
} // ()
// ------------------------------------------------
// ------------------------------------------------
int main () {
long int min = getMinutesSince1970Until( "1970-01-01 01:01:00" );
cout << min << endl;
long int min0 = getMinutesSince1970Until( "2019-01-18 14:23:00" );
long int min1 = getMinutesSince1970Until( "2019-01-18 14:27:00" );
if ( (min1 - min0) != 4 ) {
cout << " something is wrong " << endl;
} else {
cout << " it appears to work !" << endl;
}
min0 = getMinutesSince( "1970-01-01 01:00:00" );
min1 = getMinutesSince1970( );
if ( (min1 - min0) != 0 ) {
cout << " something is wrong " << endl;
} else {
cout << " it appears to work !" << endl;
}
} // ()

C++ get start of this current year in unixtime

I'm looking for a way to retrieve the start of the current year as a unix timestamp.
For example if we're on 2017-10-16 the unix timestamp is 1523318400. I have to retrieve 1483228800 (2017-01-01) instead. And it must work for the next years too of course.
There are functions to add and subtract a number of months, days, minutes and seconds from a time_t, which can be used to calculate the the time_t for a point in the past, but it looks quite awkward to find the correct number of units to remove. (cpp reference : time_point). I also looked at original C function mktime. However, whilst creating a time_t and then a struct tm*, the issue is correctly generating a timezone correct version.
So my solution is something like this....
int getYear(time_t now)
{
struct tm * tnow = std::gmtime(&now);
return tnow->tm_year + 1900;
}
std::time_t calculateYear( int currentYear )
{
int epochYear = currentYear - 1970;
int leapYears = (epochYear + 1) / 4;
time_t result = epochYear * 24 * 60 * 60 * 365;
result += leapYears * 24 * 60 * 60;
return result;
}
The code is good for years between 1970 (first time_t value) and 2100, which is not a leap year from a 100 year rule.
The number of leap years is strange, as whilst 2012 is a leap year, it is 2013 which is the first year beginning to count it.
You could use Howard Hinnant's free, open-source C++11/14/17 date/time library. It would be as simple as this:
#include "date/date.h"
date::sys_seconds
start_of_year(date::sys_seconds t)
{
using namespace date;
return sys_days{year_month_day{floor<days>(t)}.year()/jan/1};
}
You could use it like this:
#include <iostream>
int
main()
{
using date::operator<<;
using namespace std::chrono_literals;
std::cout << start_of_year(date::sys_seconds{1523318400s}) << '\n';
}
This outputs:
1514764800s
Note that this is not the answer you said you wanted. However it is correct. You can debug this discrepancy with this library as well:
std::cout << date::sys_seconds{1523318400s} << '\n';
This outputs:
2018-04-10 00:00:00
instead of 2017-10-16. You can find the Unix Time stamp for 2017-10-16 with:
using namespace date::literals;
std::cout << date::sys_seconds{date::sys_days{2017_y/10/16}}.time_since_epoch() << '\n';
which outputs:
1508112000s
And:
std::cout << start_of_year(date::sys_seconds{1508112000s}).time_since_epoch() << '\n';
will output:
1483228800s
You can also use this library to find the current year:
date::year
current_year()
{
using namespace date;
using namespace std::chrono;
return year_month_day{floor<days>(system_clock::now())}.year();
}
And you could rewrite (or overload) start_of_year to take a date::year instead of (or in addition to) date::sys_seconds:
date::sys_seconds
start_of_year(date::year y)
{
using namespace date;
return sys_days{y/jan/1};
}
And now you can write:
int
main()
{
using date::operator<<;
std::cout << start_of_year(current_year()).time_since_epoch() << '\n';
}
which currently outputs:
1483228800s

Valid Date function using <ctime> mktime

I wanted a function that would take three inputs of day, month, year and tell me whether it is valid or not. Then using the example on http://www.cplusplus.com/reference/ctime/mktime/
I tried to implement my function:
bool ValidDate(int d, int m, int y)
{
struct tm *timeinfo;
time_t rawtime;
time (&rawtime);
timeinfo = localtime(&rawtime);
timeinfo->tm_year = y - 1900;
timeinfo->tm_mon = m - 1;
timeinfo->tm_mday = d;
if (mktime(timeinfo) == -1 )
return false;
else return true;
}
The problem is that the function is returning not as i want it to.
e.g im checking like
if (ValidDate(4,13,2010)) // out put is valid
std::cout << "valid\n";
else std::cout << "Invalid\n";
ValidDate(4,22,2010) // valid
ValidDate(344,13,2010) //valid
ValidDate(4,133,2010) //valid
ValidDate(31,12, 1920) //invalid
ValidDate(31,9,2010) //valid
ValidDate(4,9,2010) //valid
Why? thanks.
EDIT:
all dates entered were invalid except 31,12,1920 and 4,9,2010 and non of the outputs were correct.
mktime return is as follow :
Time since epoch as a std::time_t object on success or -1 if time cannot be represented as a std::time_t object.
std::time_t is defined as follow :
Arithmetic type capable of representing times.
Although not defined, this is almost always a integral value holding the number of seconds (not counting leap seconds) since 00:00, Jan 1 1970 UTC, corresponding to POSIX time.
So 31/12/1920 cannot be represented into a std::time_t as it is before the epoch.
As for the other invalid dates that are reported as valid, mktime also states :
The values in [the parameter] are permitted to be outside their normal ranges.
Here is the example taken from cppreference :
#include <iostream>
#include <iomanip>
#include <ctime>
int main()
{
std::time_t t = std::time(NULL);
std::tm tm = *std::localtime(&t);
std::cout << "Today is " << std::put_time(&tm, "%c %Z") <<'\n';
tm.tm_mon -= 100; // tm_mon is now outside its normal range
std::mktime(&tm);
std::cout << "100 months ago was " << std::put_time(&tm, "%c %Z") << '\n';
}
Output is :
Today is Wed Dec 28 09:56:10 2011 EST
100 months ago was Thu Aug 28 10:56:10 2003 EDT

C++: Converting date-time between timezones keeping precision

Consider the input: 2014-04-14T16:28:07.023 (no time-zone, milliseconds precision)
I parsed it and I have the parts as numbers.
The input is always considered to be in UTC
I want to display it as local time
I want to keep the milliseconds precision when displaying
I have C++98 and boost 1.51.
I inspected high_resolution_clock and system_clock, but was unable to produce the final plot for the problem yet.
As requested in the comments to post as an answer, here is how it can be done without Boost:
#include <iostream>
#include <stdlib.h>
#include <time.h>
int main() {
int year, month, day, hour, minute, second, millisecond;
if (std::cin >> year >> month >> day >> hour >> minute >> second >> millisecond) {
struct tm utc;
utc.tm_year = year;
utc.tm_mon = month;
utc.tm_mday = day;
utc.tm_hour = hour;
utc.tm_min = minute;
utc.tm_sec = second;
utc.tm_isdst = 0;
time_t time = timegm(&utc);
if (time == (time_t) -1)
abort();
struct tm *local = localtime(&time);
if (localtime == NULL)
abort();
year = local->tm_year;
month = local->tm_mon;
day = local->tm_mday;
hour = local->tm_hour;
minute = local->tm_min;
second = local->tm_sec;
std::cout << year << ' ' << month << ' ' << day << ' ' << hour << ' ' << minute << ' ' << second << ' ' << millisecond << std::endl;
}
}
Note that the millisecond variable is read from input, and written to output, without any modification.
This uses the non-standard timegm function, but the documentation for that function contains a more portable implementation that you could include, if you want.
I have a solution which will be sufficient for me, but I don't know if it is the best approach in general or not. I'm about to use boost::posix_time::ptime and boost::date_time's c_local_adjustor:
#include <iostream>
#include <boost/date_time.hpp>
#include <boost/date_time/c_local_time_adjustor.hpp>
int main()
{
typedef boost::posix_time::ptime TP;
typedef boost::date_time::c_local_adjustor<TP> local_adj;
TP tUTC(boost::gregorian::date(2014,4,13),boost::posix_time::millisec(23));
TP tLocal(local_adj::utc_to_local(tUTC));
std::cout << boost::posix_time::to_simple_string(tUTC) << std::endl;
std::cout << boost::posix_time::to_simple_string(tLocal) << std::endl;
return 0;
}
Will print:
2014-Apr-13 00:00:00.023000
2014-Apr-13 02:00:00.023000
I did'nt use using namespace to show where is what. The ptime class has accessors to every detail I need. The c_local_adjustor does not have local_to_utc method, but it can be worked around.
(I got nowhere with chrono, I was able to do only circles in the documentation.)