C++ - Saving time in a file, then comparing it with current time - c++

I would like to store/save time in a file. That's no issue, BUT:
What if a time zone changes? Or daylight time may differ.
How can I compare the saved time in a file with the current time? What if the time zone changes or daylight shifts.
Current time has to be always greater than saved time in order to continue with the program.
Thanks for any advice.

Unix timestamps do not change accross timezones
To avoid timezone changes & other problems with time you can probably use timestamps. In C++ they are available through chrono library.
Example and +/- related question
#include <iostream>
#include <chrono>
int main()
{
const auto p1 = std::chrono::system_clock::now();
std::cout << "seconds since epoch: "
<< std::chrono::duration_cast<std::chrono::seconds>(
p1.time_since_epoch()).count() << '\n';
}
Then if this is enough for you just save timestamp to file and compare with a new timestamp.
Probably you would like to have it in a human readable format. Some useful ways to do this in C++ can be found here

Related

How can I convert IANA time zone name to UTC offset at present in Ubuntu C/C++

In Python or Java you can get the UTC offset (at present time) given the IANA name of the timezone ("America/Los_Angeles" for instance). See Get UTC offset from time zone name in python for example.
How can you do the same using C/C++ on Ubuntu 14.04?
EDIT: Preferably in a thread-safe way (no environment variables).
You alluded to this fact, but it's important to note that the offset between UTC and the time in a time zone is not necessarily constant. If the time zone performs daylight saving (summer) time adjustments, the offset will vary depending on the time of year.
One way to find the offset is to take the time you're interested in, hand it to the localtime() function, then look at the tm_gmtoff field. Do this with the TZ environment variable set to the zone name you're interested in. Here's an example that does so for the current time:
#include <time.h>
#include <stdio.h>
int main()
{
setenv("TZ", "America/Los_Angeles", 1);
time_t t = time(NULL);
struct tm *tmp = localtime(&t);
printf("%ld\n", tmp->tm_gmtoff);
}
At the moment this prints -25200, indicating that Los Angeles is 25200 seconds, or 420 minutes, or 7 hours west of Greenwich. But next week (actually tomorrow) the U.S goes off of DST, at which point this code will start printing -28800.
This isn't guaranteed to work, since the tm_gmtoff field is not portable. But I believe all versions of Linux will have it. (You might have to compile with -D_BSD_SOURCE or something, or refer to the field as __tm_gmtoff. But in my experience it tends to work by default, as plain tm_gmtoff.)
The other way is to go back and forth with gmtime and mktime, as described in Sam Varshavchik's answer.
Addendum: You asked about not using environment variables. There is a way, but unfortunately it's even less standard. There are BSD functions tzalloc and localtime_rz which do the job, but they do not exist on Linux. Here's how the code looks:
timezone_t tz = tzalloc("America/Los_Angeles");
if(tz == NULL) return 1;
time_t t = time(NULL);
struct tm tm, *tmp = localtime_rz(tz, &t, &tm);
printf("%ld\n", tmp->tm_gmtoff);
For me this prints -28800 (because PDT fell back to PST just a few minutes ago).
If you had it, you could also use localtime_rz along with mktime in Sam Varshavchik's answer. And of course Howard Hinnant's library is pretty obviously thread-safe, not requiring mucking with TZ at all.
EDIT (OP): The code for localtime_rz and tzalloc can be downloaded from https://www.iana.org/time-zones and works on Ubuntu 14.04.
You could use this free open source C++11/14 library to do it like this:
#include "chrono_io.h"
#include "tz.h"
#include <iostream>
int
main()
{
using namespace date;
using namespace std::chrono;
auto zt = make_zoned("America/Los_Angeles", system_clock::now());
std::cout << zt.get_info().offset << '\n';
}
This currently outputs:
-25200s
Or you could format it differently like this:
std::cout << make_time(zt.get_info().offset) << '\n';
which currently outputs:
-07:00:00
The factory function make_zoned creates a zoned_time using the IANA name "America/Los_Angeles" and the current time from std::chrono::system_clock. A zoned_time has a member getter to get the information about the timezone at that time. The information is a type called sys_info which contains all kinds of useful information, including the current UTC offset.
The UTC offset is stored as a std::chrono::seconds. The header "chrono_io.h" will format durations for streaming. Or the make_time utility can be used to format the duration into hh:mm:ss.
The program above is thread-safe. You don't have to worry about some other process changing TZ out from under you, or changing the current time zone of the computer in any other way. If you want information about the current time zone, that is available too, just use current_zone() in place of "America/Los_Angeles".
If you wanted to explore other times, that is just as easy. For example beginning at Nov/6/2016 at 2am local time:
auto zt = make_zoned("America/Los_Angeles", local_days{nov/6/2016} + 2h);
The output changes to:
-28800s
-08:00:00
More information about this library was presented at Cppcon 2016 and can be viewed here:
https://www.youtube.com/watch?v=Vwd3pduVGKY
Use gmtime(), first, to convert the current epoch time into UTC time, then use mktime() to recalculate the epoch time, then compare the result to the real epoch time.
gmtime() calculates the struct tm in UTC, while mktime() assumes that the struct tm represents the current local calendar time. So, by making this round-about calculation, you indirectly figure out the current timezone offset.
Note that mktime() can return an error if struct tm cannot be convert to epoch time, which will happen during certain transitions between standard time and alternate time. It's up to you to figure out what that means, in your case.
The recipe looks something like this:
time_t t = time(NULL);
struct tm *tmp = gmtime(&t);
time_t t2 = mktime(tmp);
int offset = t - t2;
See the documentation of these library functions for more information.
To use a specific time zone, either set the TZ environment variable, or you can try using localtime_rz as in Steve Summit's answer. As mentioned, beware that mktime can sometimes return -1 for unconvertible times.

Convert a local time with timezone into UTC with ctime

I have been wracking my head crazy trying to figure this out with this API
My original implementation was something like:
// TimezonePtr is just a share_ptr to the timezone
std::tm getGMT(const std::tm& rawtime, TimezonePtr tz)
{
std::tm result = rawtime;
const auto loct = mktime_z(tz.get(), &result);
gmtime_r(&loct, &result);
return result;
}
However, this does not take into account DST. For example, if I feed it a date of Sep 28 2012 15:54:24 I get back Sep 28 2012 20:54:24, which is incorrect. It looks like I want to use localtime_rz, except that takes an epoch, which is driving me nuts because if I could get the epoch then I'd already have my answer. :(
How can I accomplish this?
mktime_z takes a struct tm as one of its arguments. If you don't know whether DST is in effect for the input date, you want to set the tm_isdst member of that tm to -1 to signify that the system should figure out whether DST is in effect for that date/time/timezone when you call mktime.
At least for me, this seems to work correctly (i.e., it correctly concludes that at least in my time zone, DST was in effect in September of 2012).
In addition to Jerry Coffin's correct (and up-voted) answer, I wanted to show how this computation could be done with a modern C++11/14 library (free and open source).
I've kept the API the same in the interest of making the code easy to compare:
template <class Duration>
auto
getGMT(date::local_time<Duration> rawtime, const date::time_zone* tz)
{
return tz->to_sys(rawtime);
}
This returns a std::chrono::time_point<system_clock, Duration> where Duration is the finer of the input Duration and seconds. If the ragtime doesn't have a unique mapping to UTC according to the indicated time zone, an exception will be thrown. Such an event can occur (for example) if rawtime is during a daylight saving transition and occurs twice, or not at all. If desired, there exists API for avoiding the exception if you want to "pre-decide" how you would like to map ambiguous and non-existent local times into UTC.
This function can be exercised like this:
#include "tz.h"
#include <iostream>
int
main()
{
using namespace date;
using namespace std::chrono_literals;
std::cout << getGMT(local_days{sep/28/2012} + 15h + 54min + 24s,
current_zone()) << " UTC\n";
std::cout << getGMT(local_days{sep/28/2012} + 15h + 54min + 24s,
locate_zone("America/New_York")) << " UTC\n";
}
This exercises the code twice:
With whatever the current time zone is for this computer.
With the time zone "America/New_York"
For me these are both the same time zone, resulting in the following output:
2012-09-28 19:54:24 UTC
2012-09-28 19:54:24 UTC
Not only is it simpler to use this library than the BSD ctime API,
but this API has type safety. For example the UTC time point and local time point are represented by different types, allowing the compiler to tell you if you accidentally use the wrong one. In contrast the BSD ctime API uses the same type (tm) for both local time and UTC.

C++ determine if the software has not been opened on the same day (Windows)

So I need to do some actions if the software has not been opened on the same day my plan is to store the number of days since the epoch for today's date in my database. Then when the software opens it will pull this number of days since the last epoch from the DB and then check that with today's number of days since the last epoch. Thus I will know if this is the same day or not.
I'm very inexperienced with C++ and I've been looking at the DateTime functions from "stdafx.h" however I've not been able to get the number of days since the last epoch.
So my goal in doing this would be to clear a database if this is the first time the software has been opened today. If it has already been opened today, then just continue on and do nothing.
I do not know how to go about this in C++. If it was python or C# or java I would have no trouble with this. So how would I go about this in C++?
Using the <chrono> standard header, it's quite easy to get the number of days since the clock's epoch.
For example:
#include <chrono>
#include <iostream>
int main() {
using days = std::chrono::duration<int, std::ratio<24 * 60 * 60>>;
auto days_since_epoch = std::chrono::duration_cast<days>(std::chrono::system_clock::now().time_since_epoch());
std::cout << days_since_epoch.count() << "\n";
}
I think the implementation is free to use whatever epoch, but if you only care about the difference in the number of days of successive calls, you should be fine.
Note that since we're essentially rounding down to the beginning of they day,
if your user opens your application once at 23:59 and then again one minute later, you'll perceive a calendar day to have passed.
+1 to melak47's answer. I just wanted to add (and this wouldn't fit in a comment), that his answer assumes the day changes in the UTC timezone, which might just be fine. This is a very good and efficient answer for many applications, including stackoverflow itself!
But in case you want the day change to happen at local midnight, here is a library that can help you do that, while still sticking with the nice <chrono> facilities. Indeed this is just a very minor tweak to melak47's answer:
#include "tz.h"
#include <chrono>
#include <iostream>
int
main()
{
using namespace std::chrono;
using namespace date;
auto tp = system_clock::now();
auto lp = current_zone()->to_local(tp);
auto days_since_epoch = duration_cast<days>(lp.time_since_epoch());
std::cout << days_since_epoch.count() << "\n";
}
It will give exactly the same answer as melak47's answer, except when the machine is set to a local timezone that differs from UTC, and UTC is currently already into the next day, or still on the previous day, compared to the local timezone.

Is there any simple way to get daylight saving time transition time under Linux in C/C++

I want to get the transition time for DST
Under Linux with giving time zone or TZ env.
My way is stupid, giving the start of the year and try every hour then check tm_isdst value of local time to get the transition time.
Is there some simple way to do this?
There is the source code in glibc, which you can browse here:
http://sourceware.org/git/?p=glibc.git;a=tree;f=timezone
Or you can use the timezone database here:
ftp://ftp.iana.org/tz/releases/tzdata2012c.tar.gz
Since you haven't given a particular timezone/location, I can't look up and give you the exact information for you.
You can also use boost_datetime.
#include <iostream>
#include <boost/date_time/local_time/local_time.hpp>
using namespace boost::local_time;
using namespace boost::posix_time;
int main()
{
tz_database tz_db;
tz_db.load_from_file("/path_to_boost/boost/libs/date_time/data/date_time_zonespec.csv");
time_zone_ptr zone = tz_db.time_zone_from_region("America/New_York");
ptime t1 = zone->dst_local_start_time(2013);
ptime t2 = zone->dst_local_end_time(2013);
std::cout << t1 << std::endl;
std::cout << t2 << std::endl;
}
Some related SO links:
c++ How to find the time in foreign country taking into account daylight saving?
How do you get the timezone (offset) for a location on a particular date?
But as RedX said earlier, politics may change time zones. So actually your original solution has the advantage of being automatically updated with the underlying OS. Also, you can improve your existing solution by using binary search.

how to get timezone

i m new to c.I want to FTP to a system and get the timezone of that system.in c++
There is no way in the FTP standard to do this. You could try uploading a new (small) file and check its date-time as reported by FTP, compared to current local time.
New answer for old question.
Rationale for revisiting this: We have better tools now.
This free, open-source, portable library will get the current time zone setting in terms of the IANA time zone database. On Windows it will convert the Windows timezone into an IANA time zone. Fully documented.
Here's how you print out the name of the current time zone:
#include "tz.h"
#include <iostream>
int
main()
{
std::cout << date::current_zone()->name() << '\n';
}
For me this currently outputs:
America/New_York
You can convert a std::chrono::system_clock to a local time and print it out:
std::cout << date::make_zoned(date::current_zone(),
std::chrono::system_clock::now()) << '\n';
which just output for me:
2016-07-16 19:24:00.447015 EDT
See the github wiki for many more examples.