Date/Time parsing in C++ - c++

While doing the data/time parsing in c++ (converting a string in any format to a date), i found the following useful methods
1) strptime() - here the %d, %m etc can have either 1 or 2 characters. The function will take care of that. As a result of this it will enforce that we use a separator between two conversion specifiers. Ex: Its not valid to give %d%m it has be to %d/%m or any other separator. Also this does not support timezones.
2) Boost date IO - here the %d, %m has to have 2 characters. Now, the input string i get is not guaranteed to have this. As a result, its not possible to use this successfully. However, this does seem to support timezone, but not sure. because it says for inputs it does support timezone
So i am planning to use both in conjunction to determine the date. But i would like to get one where i can take into account the timezone as well. But none seems to be supporting that.
Does anybody have a suggestion?
Rgds,
AJ

#AJ: Added another answer so the code gets formatted
#include <stdio.h>
#include <sys/time.h>
#include <time.h>
int
main(void)
{
struct tm tm[1] = {{0}};
strptime("Tue, 19 Feb 2008 20:47:53 +0530", "%a, %d %b %Y %H:%M:%S %z", tm);
fprintf(stdout, "off %ld\n", tm->tm_gmtoff);
return 0;
}
And a run looks like (glibc 2.10.1):
freundt#clyde:pts/28:~/temp> ./test
off 19800

Depends on the libc version, I'd say, and of course what you mean by `taking into account': Is it supposed to read the additional info and then ignore it, is it supposed to store the parsed info in the tm struct, or is it meant to convert to system/environment time?
glibc 2.10.1's strptime() does time zones, from the info page
`%z'
The offset from GMT in ISO 8601/RFC822 format.
`%Z'
The timezone name.
_Note:_ Currently, this is not fully implemented. The format
is recognized, input is consumed but no field in TM is set.

As you noticed strptime doesn't directly support timezones. All it does is read formatted timezone-less data into a tm structure. You'll have to parse an optional timezone indicator yourself (unless it's fixed), and then set TZ and use mktime to convert into a time_t. If you set tm.is_dst to -1 you can even ask that mktime try to figure out the DST for you automatically.
Alternately you could construct your own parser using steams (boost supports a few formats, but may not be general enough). Again like above you can use mktime to compose a time_t.

Related

Parsing a date and time from a string in the current system format on Windows

I need to parse a string that is supposed to consist of a date and time in the system's current date/time format settings. I can use, for example, std::get_time(), but the problem is that I don't know what date/time format is set in the system.
I have found several ways to get the date/time format using:
GetLocaleInfo/GetLocaleInfoEx with LOCALE_SSHORTDATE and LOCALE_SSHORTDATE
or std::time_get<char>::dateorder()
but in this way, I get "incompatible format" with functions that parse date/time (std::get_time()) and it needs to be converted:
GetLocaleInfo() gives me "MM/dd/yyyy H:mm:ss", and this needs to be converted to something like "%m/%d/%Y %H:%M:%S".
std::time_get<char>::dateorder() gives a more accurate order in date format:
std::time_get<char>::dmy
std::time_get<char>::mdy
std::time_get<char>::ymd
std::time_get<char>::ydm
but it is still necessary to define the separator and the time format.
In general, I don't mind manual conversion, but I'm wondering if there is a more direct way that gives the system date/time format that is compatible with the date/time parsing functions.
std::get_time uses the std::time_get facet.
std::time_get uses the POSIX strptime interface for its flags.
The POSIX strptime specification states that:
%x The date, using the locale's date format.
%X The time, using the locale's time format.
Whether or not this will actually work in your environment is another matter. However, it is worth giving this a try.

unable to get fraction of seconds using strptime()

I am receiving a datetime in YYYY-MM-DDThh:mm:ss[.S+][Z|+-hh:mm] this format. and i m trying to copy that value using strptime as shown below
struct tm time = {0};
char *pEnd = strptime(datetime, "%Y-%m-%dT%H:%M:%S%Z", &time);
But I can't copy the fraction of seconds as strptime doesn't support it in C++.
So what should i do?
I found a solution using gettimeofday(). but I am already getting date and time in 'datetime' so please help me to find soluntion for it...I can use poco also . but even their we take local time.
You can remove the "S" component from the string before parsing with strptime, then use it however you like later (it won't fit anywhere in a Standard struct tm - there's no sub-second fields). Just datetime.find('.') and go from there, or use a regexp if you prefer - both tedious but not rocket science.
In C++11 you can use the the high precision timing objects in <chrono>, see the answers to this question.

What is the right way to convert into UNIX timestamp from the date and time in C/C++?

I have a lot of dates with time in this format:
day.mon.year - hour:min:sec
And I need to convert this dates with time into Unix timestamp.
I used tm structure, but I can't fill those fields:
tm_wday
tm_yday
And I don't must I fill those field, because I don't know do this field have any effect to the value of Unix timestamp.
Help me to choose rigth way to calculate Unix timestamp.
P.S. Dates with time aren't current, they can be date of the 20-th century or future dates (to 2038 year).
P.P.S. I use OS Windows.
POSIX has a formula for exactly what you want:
http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_15
tm_sec + tm_min*60 + tm_hour*3600 + tm_yday*86400 +
(tm_year-70)*31536000 + ((tm_year-69)/4)*86400 -
((tm_year-1)/100)*86400 + ((tm_year+299)/400)*86400
This works whenever you have a broken-down time in GMT, even if the underlying system's mktime, etc. functions do not use the same format time_t as "Unix timestamps".
If your original time is in local time, you can use mktime and gmtime to convert it to GMT using the system's notion of timezone rules. If you want to apply your own timezone offset rules, just do that manually before using the above formula.
If you are on unix, mktime() will get the second part of the timestamp. It ignores the tm_wday and tm_yday fields.

date and time manipulation in c++

So, I want to do a class Delivery like this:
class Delivery{
private:
string recipient;
time_t date;
}
So, the date is time_t. The thing I want to do is let the user type the delivery date. Maybe the delivery is made today, maybe tomorrow, maybe next month. I could've made the date attribute string date instead of time_t. Why I didn't do that? Because, I have a list of deliveries and I want to sort the deliveries and then to print the deliveries that were made in a certain period. For example, print the deliveries made from 12.03.2013 until 25.08.2013.
The question is: how can I let the user set the date? I searched the Internet but I didn't found any useful functions. Is there a way to solve this problem?
Assuming you read the input into a string named time_string in the format 01/01/13:
struct tm tm;
strptime(time_string, "%D", &tm);
time_t t = mktime(&tm);
If you include the full year, e.g. 01/01/2013, replace strptime(time_string, "%D", &tm); with strptime(time_string, "%m/%d/%Y", &tm);. %m is the month, %d the day, and %Y the full year, e.g. 2013 instead of 13. Also note that if time_string is an std::string instead of a C-style string, you need to replace time_string with time_string.c_str() in the call to strptime.
Sources: https://stackoverflow.com/a/11213640/2097780 and http://publib.boulder.ibm.com/infocenter/zos/v1r12/index.jsp?topic=%2Fcom.ibm.zos.r12.bpxbd00%2Fstrptip.htm.
Working on date/time involves using the struct tm and time_t data structures.
To convert time_t to struct tm, there are a few differnt functions, such as localtime(), gmtime(), etc.
To convert from struct tm to time_t, you use mktime().
Obviously, you'll also need to write some code that reads year, month, day and perhaps hours and minutes from the user as integer values, then fill in a struct tm with the relevant values, and call mktime() to convert it to "seconds since 1 jan 1970" in a time_t value.
All functions to do this are declared in <ctime>
Given that you are using C++, you might want to consider using: Boost DateTime.

C++ Convert time ET to CET or something else

I'm parsing files with date and time in it.
Let's say i have the date and time in the following format:
2009/07/18 10:48:39 CET (value in txt-file)
This is in ET:
2009/07/18 4:48:39 ET (could also be the value i parsed)
Is there a solution to convert between the times/dates? Maybe boost?
Couldn't find helpful infos in the boost docs.
Let's say i want to from CET to ET or ET to EST or CET to EST in c++, what would you do?
strftime allows you to print out a struct tm* object using datetime formatting characters (%Y, %m, %d, etc).
What you could do is load a struct tm* object up by parsing your input data (assuming it's regular, this shouldn't require a lot of code), then modify the individual parts of the tm struct with some custom logic based on your timezone conversion (add hour, then check if you need to update day based on new hour value), then print this datetime value in the format you'd like via strftime. Not nearly as simple as the strptime/strftime functions available in php, but a solution nonetheless.
I recommend https://github.com/google/cctz
Also note that "CET" and "ET" are not real time zone identifiers. They may be abbreviations for some time zone, but they do not uniquely identity an actual time zone. If you have some control over the data in the file, you should change "CET" and "ET" to numeric UTC offset values, such as those produced by %z from strftime() (and cctz::Format()). A numeric UTC offset and the Y/M/D H:M:S fields will let you correctly parse out the exact time instant.