Reputation: 13892
Is there a good equivalent implementation of strptime()
available for Windows? Unfortunately, this POSIX function does not appear to be available.
Open Group description of strptime - summary: it converts a text string such as "MM-DD-YYYY HH:MM:SS"
into a tm struct
, the opposite of strftime()
.
Upvotes: 41
Views: 70080
Reputation: 11
To my surprise, if not unbelievable, after at least 50 years of digital data processing there still seems no acceptable solution for a 'strptime()' method being available.
The following features describe what should be implemented to be acceptable:
Very helpful additional features are:
None of the above presented solutions do fulfill the first four features although they are reasonable to my opinion. Using the standard C++ library <chrono> might make the 'strptime' function obsolete, but for me this library is quite confusing and not easy to use.
For those reasons I designed the following two implementions being consistent to each other and providing all above mentioned features.
They are published on github within a repository named
Both functions amoung others are provided by just two files (LibOb_strptime.h and LibOb_strptime.c).
The only 'cost' are additional pointer parameters to transfer time zone and language data, but they all can be set to 0 in case just the conventional functionality is sufficient. The functions intentionally do not use the system 'locale', which is explained in the documentation.
For C++ programmers the class cTime strongly related to this 'strptime' implementaion might be of interest.
Upvotes: 0
Reputation: 1
This is a copy-and-paste-capable C example of the answer @amwinter posted, although I did not use sscanf()
- the *scanf()
family of functions is IMO too perverse to do robust parsing with:
(headers and error checking omitted to keep the example short enough to prevent a vertical scroll bar from getting created)
// format will be YYYYmmddHHMMSSZ
const char *notAfter = getNotAfterStringFromX509Cert( x509 );
struct tm notAfterTm = { 0 };
#ifdef _WIN32
char buffer[ 8 ];
memset( buffer, 0, sizeof( buffer ) );
strncpy( buffer, notAfter, 4 );
notAfterTm.tm_year = strtol( buffer, NULL, 10 ) - 1900;
memset( buffer, 0, sizeof( buffer ) );
strncpy( buffer, notAfter + 4, 2 );
notAfterTm.tm_mon = strtol( buffer, NULL, 10 ) - 1;
memset( buffer, 0, sizeof( buffer ) );
strncpy( buffer, notAfter + 6, 2 );
notAfterTm.tm_mday = strtol( buffer, NULL, 10 );
memset( buffer, 0, sizeof( buffer ) );
strncpy( buffer, notAfter + 8, 2 );
notAfterTm.tm_hour = strtol( buffer, NULL, 10 );
memset( buffer, 0, sizeof( buffer ) );
strncpy( buffer, notAfter + 10, 2 );
notAfterTm.tm_min = strtol( buffer, NULL, 10 );
memset( buffer, 0, sizeof( buffer ) );
strncpy( buffer, notAfter + 12, 2 );
notAfterTm.tm_sec = strtol( buffer, NULL, 10 );
time_t result = mktime( ¬AfterTm );
This is a really simple case, where the input string is in a format known exactly, so it's extremely easy to parse.
Upvotes: 0
Reputation: 1
There is a version of strptime() for windows available at https://github.com/p-j-miller/date-time . The same location includes a matching strftime() function and a comprehensive test program. This also works under Linux if you need to create code that works on both OS's.
Upvotes: -1
Reputation: 1218
Assuming you are using Visual Studio 2015 or above, you can use this as a drop-in replacement for strptime:
#include <time.h>
#include <iomanip>
#include <sstream>
extern "C" char* strptime(const char* s,
const char* f,
struct tm* tm) {
// Isn't the C++ standard lib nice? std::get_time is defined such that its
// format parameters are the exact same as strptime. Of course, we have to
// create a string stream first, and imbue it with the current C locale, and
// we also have to make sure we return the right things if it fails, or
// if it succeeds, but this is still far simpler an implementation than any
// of the versions in any of the C standard libraries.
std::istringstream input(s);
input.imbue(std::locale(setlocale(LC_ALL, nullptr)));
input >> std::get_time(tm, f);
if (input.fail()) {
return nullptr;
}
return (char*)(s + input.tellg());
}
Just be aware that for cross platform applications, std::get_time
wasn't implemented until GCC 5.1, so switching to calling std::get_time
directly may not be an option.
Upvotes: 31
Reputation: 121
One alternative is to use GetSystemTime
and send the time information to a function that parses it according to your format using vsnprintf_s
. In the
example below there is one function that creates a time string with milli second
precision. It then sends the string to a function that formats it according to the desired format:
#include <string>
#include <cstdio>
#include <cstdarg>
#include <atlstr.h>
std::string FormatToISO8601 (const std::string FmtS, ...) {
CStringA BufferString;
try {
va_list VaList;
va_start (VaList, FmtS);
BufferString.FormatV (FmtS.c_str(), VaList);
} catch (...) {}
return std::string (BufferString);
}
void CreateISO8601String () {
SYSTEMTIME st;
GetSystemTime(&st);
std::string MyISO8601String = FormatToISO8601 ("%4u-%02u-%02uT%02u:%02u:%02u.%03u", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
}
Upvotes: -1
Reputation: 3139
If you don't want to port any code or condemn your project to boost, you can do this:
sscanf
struct tm
(subtract 1 from month and 1900 from year -- months are 0-11 and years start in 1900)mktime
to get a UTC epoch integerJust remember to set the isdst
member of the struct tm
to -1, or else you'll have daylight savings issues.
Upvotes: 36
Reputation: 20596
This does the job:
#include "stdafx.h"
#include "boost/date_time/posix_time/posix_time.hpp"
using namespace boost::posix_time;
int _tmain(int argc, _TCHAR* argv[])
{
std::string ts("2002-01-20 23:59:59.000");
ptime t(time_from_string(ts));
tm pt_tm = to_tm( t );
Notice, however, that the input string is YYYY-MM-DD
Upvotes: 15
Reputation: 400562
An open-source version (BSD license) of strptime()
can be found here: http://cvsweb.netbsd.org/bsdweb.cgi/src/lib/libc/time/strptime.c?rev=HEAD
You'll need to add the following declaration to use it:
char *strptime(const char * __restrict, const char * __restrict, struct tm * __restrict);
Upvotes: 15