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
Related
::tm tm{0, 0, 0, 29, 10, 2022 - 1900, 0, 0}; // 10 for November
auto time_t = ::mktime(&tm);
cout << "milliseconds = " << time_t * 1000 << endl;
Above code outputs 1669660200000, which is equivalent to 2022 November 29, 00:00:00. But it is in local timezone. How to get the UTC time for the aforementioned date?
A modern c++17 way with thread-safety will be appreciated.
There's a nit picky weak point in your solution (besides the thread safety issue): The members of tm are not guaranteed to be in the order you are assuming.
The tm structure shall contain at least the following members, in any order.
Using C++17 you can use this C++20 chrono preview library. It is free, open-source and header-only. Your program would look like:
#include "date/date.h"
#include <chrono>
#include <iostream>
int
main()
{
using namespace std;
using namespace chrono;
using namespace date;
sys_time<milliseconds> tp = sys_days{2022_y/11/29};
cout << "milliseconds = " << tp.time_since_epoch().count() << '\n';
}
And the output would be:
milliseconds = 1669680000000
One of the nice advantages of using this library is that it will easily port to C++20. The C++20 version looks like:
#include <chrono>
#include <iostream>
int
main()
{
using namespace std;
using namespace chrono;
sys_time<milliseconds> tp = sys_days{2022y/11/29};
cout << "milliseconds = " << tp.time_since_epoch() << '\n';
}
And outputs:
milliseconds = 1669680000000ms
Demo:
One old school C-style way is to first get the timezone difference and offset it with the value in the question.
static const auto TIMEZONE_OFFSET = [] (const ::time_t seconds)
{ // This method is to be called only once per execution
::tm tmGMT = {}, tmLocal = {};
::gmtime_r(&seconds, &tmGMT); // ::gmtime_s() for WINDOWS
::localtime_r(&seconds, &tmLocal); // ::localtime_s() for WINDOWS
return ::mktime(&tmGMT) - ::mktime(&tmLocal);
}(10000);
::tm tm{0, 0, 0, 29, 10, 2022 - 1900}; // set fields 1 by 1 as the order is not guaranteed
cout << " start of day = " << (::mktime(&tm) - TIMEZONE_OFFSET) << endl;
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;
}
I made two functions that are to calculate beginning timestamp of the day (i.e. at 00:00:00 of the day) and the hour (starting from 1 and up to 24) of a given epoch timestamp.
#include <cstdint>
#include <ctime>
const uint8_t FIRST_HOUR = 0x01; // 01, 02, ..., 24
const uint32_t SECS_PER_HOUR = 3600; // 3600 secs per hour
uint32_t CalcDaiBaseTimestamp(uint32_t in_ts) {
time_t ts = in_ts;
struct tm timeinfo = *localtime(&ts);
timeinfo.tm_hour = 0;
timeinfo.tm_min = 0;
timeinfo.tm_sec = 0;
time_t tmp_base_ts = mktime(&timeinfo);
return (uint32_t)tmp_base_ts;
}
void CalcDaiBaseTimestampAndHour(uint32_t in_ts,
uint32_t& base_ts,
uint8_t& hour_nth) {
base_ts = CalcDaiBaseTimestamp(in_ts);
hour_nth = (in_ts - base_ts) / SECS_PER_HOUR + FIRST_HOUR;
}
CalcDaiBaseTimestampAndHour is invoked from multiple threads.
The code is compiled with g++ (Ubuntu 4.8.4-2ubuntu1~14.04.4) 4.8.4 and the program runs on Ubuntu 14.04 x64.
Most of time my program works well, but I have sometimes observed some "weird" result as shown below:
(timestamp: 1554459477.500) -> (base: 1553990400, hour_nth: 131)
While the correct result should be:
(timestamp: 1554459477.500) -> (base: 1554422400 / hour_nth: 11)
Because:
1554459477.500 = 2019-04-05 10:17:57.500
base_ts = 2019-04-05 00:00:00 = 1554422400
hour_nth = 11
Since the issue happens sometimes so I would suppose that the reason could be thread-safety of some ctime - related functions.
What could cause the "weird" results? Please help me troubleshoot this! If the reason is actually thread-safety of the ctime - related functions then how could I work around this (with some C++ 11 standard library e.g.)?
Could you please show me how to work around this using the date library?
Reference link: https://github.com/HowardHinnant/date
Code:
#include "date/date.h"
#include <iomanip>
#include <iostream>
int
main()
{
using namespace std::chrono;
using namespace date;
using dsec = duration<double>;
sys_time<dsec> tp{dsec{1554459477.500}};
std::cout << std::setprecision(3) << std::fixed
<< tp.time_since_epoch().count()
<< " = " << round<milliseconds>(tp) << '\n';
sys_seconds base_ts = floor<days>(tp);
std::cout << "base_ts = " << base_ts << " = "
<< base_ts.time_since_epoch().count() << '\n';
auto hour_nth = floor<hours>(tp - base_ts) + hours{1};
std::cout << "hour_nth = " << hour_nth.count() << '\n';
}
Output:
1554459477.500 = 2019-04-05 10:17:57.500
base_ts = 2019-04-05 00:00:00 = 1554422400
hour_nth = 11
Notes:
There exist no thread safety issues here.
As long as you don't need time zone support, "date/date.h" is a single-header, header-only library.
Everything above is UTC.
Documentation: https://howardhinnant.github.io/date/date.html
I want to convert a string in the format of "20160907-05:00:54.123" into milliseconds.
I know that strptime is not available in Windows and I want to run my program in both windows and linux. I can't use third party libraries as well.
I can tokenize the string and convert it. But is there a more elegant way like using the strptime to do so?
What about std::sscanf?
#include <iostream>
#include <cstring>
int main() {
const char *str_time = "20160907-05:00:54.123";
unsigned int year, month, day, hour, minute, second, miliseconds;
if (std::sscanf(str_time, "%4u%2u%2u-%2u:%2u:%2u.%3u", &year, &month,
&day, &hour, &minute, &second,&miliseconds) != 7)
{
std::cout << "Parse failed" << std::endl;
}
else
{
std::cout << year << month << day << "-" << hour << ":"
<< minute << ":" << second << "." << miliseconds
<< std::endl;
}
}
Output (ideone):
201697-5:0:54.123.
However, you should make sure the input is valid (for example, day can be in the range of [0,99]).
Too bad about no 3rd party libraries, because here is one (MIT license) that is just a single header, runs on linux and Windows, and handles the milliseconds seamlessly:
#include "date.h"
#include <iostream>
#include <sstream>
int
main()
{
date::sys_time<std::chrono::milliseconds> tp;
std::istringstream in{"20160907-05:00:54.123"};
date::parse(in, "%Y%m%d-%T", tp);
std::cout << tp.time_since_epoch().count() << '\n';
}
This outputs:
1473224454123
Error checking is done for you. The stream will fail() if the date is invalid.
date::sys_time<std::chrono::milliseconds> is a type alias for std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds>. I.e. it is from the family of system_clock::time_point, just milliseconds precision.
Fully documented:
https://howardhinnant.github.io/date/date.html
Doesn't get much more elegant than this.
Given the format of your string, it is fairly easy to parse it as follows (although a regex or get_time might be more elegant):
tm t;
t.tm_year = stoi(s.substr(0, 4));
t.tm_mon = stoi(s.substr(4, 2));
t.tm_mday = stoi(s.substr(6, 2));
t.tm_hour = stoi(s.substr(9, 2));
t.tm_min = stoi(s.substr(12, 2));
t.tm_sec = 0;
double sec = stod(s.substr(15));
Finding the time since the epoch can be done with mktime:
mktime(&t) + sec * 1000
Note that the fractional seconds need to be handled differently - unfortunately, tm has only integer seconds.
(See the full code here.)
Edit
As Mine and Panagiotis Kanavos correctly note in the comments, Visual C++ apparently supports get_time for quite a while, and it's much shorter with it (note that the fractional seconds need to be handled the same way, though).
I have a project about cars with GPS. I need to return the start and the finish moment for each car.
So we have:
time_t x, y;
Because I will use later them for a transformation.
I have a problem. I read from an external file data in this format:
auto1
1439467747492
auto1
1439467748512
...etc.
auto1->name of the car;
1439467747492->the moment in time of the car
I tried to get the first position of the first moment and the last moment for each car. This is the code in C++:
long test = momenti[choice1]/1000;
time_t x = test;
cout << " Momentul initial:\n " << ctime(&x) << endl;
long test1 = momentf[choice1] / 1000;
time_t y = test1;
cout << " Momentul final:\n " << ctime(&y) << endl;
I receive the same date for every car. Is something like momenti[i]=momentf[i]
What did I do wrong?
It is not good. According epoch converter we should get this : GMT: Thu, 13 Aug 2015 12:09:07 GMT
Here is how you can get this output with C++11/14 and using this free, open source date library which extends the C++ <chrono> library to handle dates.
#include "date.h"
#include <chrono>
#include <iostream>
int
main()
{
using namespace std::chrono;
using namespace std;
using namespace date;
using time_point = std::chrono::time_point<system_clock, milliseconds>;
auto tp = time_point{1439467747492ms};
auto dp = floor<days>(tp);
auto time = make_time(tp - dp);
auto ymd = year_month_day{dp};
cout << "GMT: " << weekday{dp} << ", " << ymd.day() << ' ' << ymd.month()
<< ' ' << ymd.year() << ' ' << time << " GMT\n";
}
Output:
GMT: Thu, 13 Aug 2015 12:09:07.492 GMT
I threw in the fractional seconds for fun, and it seemed a shame to waste them (the C lib won't give them to you). If you really don't want them, it is easy to fix:
auto time = make_time(floor<seconds>(tp) - dp);
Now the output is:
GMT: Thu, 13 Aug 2015 12:09:07 GMT
You need C++14 for the 1439467747492ms above. If you only have C++11 you can sub in this instead: milliseconds{1439467747492}. If you only have C++03, then you are 13 years behind the times and stuck with ctime. ;-)
The chrono solution will offer you greater type safety, more flexibility, and greater performance.
If i can fix and the latitude and longitude problem would be great lol
If you can translate latitude and longitude into an IANA timezone name (and there are tools to do this), I've got a IANA timezone database parser for you which interoperates with <chrono> and "date.h".
#include <iostream>
#include <cstring>
#include <time.h>
using namespace std;
int main()
{
long test = 1439467747492;
time_t x = test;
cout << ctime( &x ) << endl;
return 0;
}
Produces
Tue Sep 18 20:15:32 1990