Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

String to FILETIME

362 views
Skip to first unread message

Michael Tissington

unread,
Jan 26, 2009, 10:34:57 PM1/26/09
to
How can I parse the following string as a FILETIME ?

"2009-01-23T11:57:26-06:00"

Thanks.

Giovanni Dicanio

unread,
Jan 27, 2009, 5:11:23 AM1/27/09
to

"Michael Tissington" <nos...@nospam.com> ha scritto nel messaggio
news:%23VdQ%23ADgJ...@TK2MSFTNGP06.phx.gbl...

> How can I parse the following string as a FILETIME ?
>
> "2009-01-23T11:57:26-06:00"

I don't know if there exists a function to do that out of the box.

However, it should not be difficult to write one by yourself.

As guidelines, I would parse the given string and set the fields of a
SYSTEMTIME structure.
(Parsing that string is easy because it seems to me that the above string
fields are of fixed length, so you can just use constant integer indexes
into the string array to get the beginning and the end of each substring).

SYSTEMTIME Structure
http://msdn.microsoft.com/en-us/library/ms724950.aspx

Then, I would call SystemTimeToFileTime() API to convert that to a FILETIME:

SystemTimeToFileTime Function
http://msdn.microsoft.com/en-us/library/ms724948.aspx

HTH,
Giovanni

Giovanni Dicanio

unread,
Jan 27, 2009, 7:28:13 AM1/27/09
to

"Michael Tissington" <nos...@nospam.com> ha scritto nel messaggio
news:%23VdQ%23ADgJ...@TK2MSFTNGP06.phx.gbl...

> How can I parse the following string as a FILETIME ?
>
> "2009-01-23T11:57:26-06:00"

To add to what I previously wrote, unfortunately in this string there is a
specification of a time zone (e.g. "-06:00").

I've never done that with pure C++; however I've found that the .NET
framework offers very convenient classes (as usual!) to do this kind of
conversion and for parsing a string in the format you requested.

So, I developed a small C++/CLI routine to do that job. It uses the
System.DateTime.ParseExact() method to parse the input string, and the
System.DateTime.ToFileTime() method to convert the resulting DateTime object
to a Windows file time (represented as __int64).
I used this string to map your string format: "yyyy-MM-ddTHH:mm:sszzz" (note
the trailing "zzz" characters that represent the time zone specification).


<code language="C++/CLI">

/// <summary>
/// Converts a UTC date time string in a Windows file time.
/// </summary>
/// <param name="utc">Input string in UTC format, e.g.
2009-01-23T11:57:26-06:00</param>
/// <returns>The Windows file time corresponding to the input
string.</returns>
/// <exception cref="System.FormatException">When input string format is
wrong.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">The resulting file
time would represent
/// a date and time before 12:00 midnight January 1, 1601 C.E.
UTC.</exception>
__int64 UTCDateTimeToFileTime(String^ utc)
{
// Parse input string
String^ expectedFormat = "yyyy-MM-ddTHH:mm:sszzz";
System::DateTime ^ resultDateTime = System::DateTime::ParseExact(
utc,
expectedFormat,
System::Globalization::CultureInfo::InvariantCulture
);

// Convert it to Windows file time
return resultDateTime->ToFileTime();
}

</code>

You can use this function in code like this:

<code language="C++/CLI">

// *** TEST ***
int main(array<System::String ^> ^args)
{
String^ inputDate = "2009-01-23T11:57:26-06:00";
try
{
Console::WriteLine("{0} corresponds to file time {1}.",
inputDate, UTCDateTimeToFileTime(inputDate));
}
catch (System::FormatException^ ex)
{
Console::WriteLine("Error in parsing date time string:");
Console::WriteLine(ex->Message);
}

return 0;
}
</code>

The beauty of the C++/CLI extensions is that you can use the powerful and
rich .NET Framework library into C++ code.

I don't know if there is something "pure native" (i.e. not in the .NET
Framework, just pure native C++ code) to do that, but I've not found
anything (e.g. it seems to me that ATL/MFC class CTime does not support time
zone conversion...).

For the sake of completeness, I report the C# function I developed in the
beginning (in fact, I developed the C# function first, and then converted it
to C++/CLI - in fact, C# is more "natural" language to develop for the .NET
framework, IMHO):

<code language="C#">

/// <summary>
/// Converts a UTC date time string in a Windows file time.
/// </summary>
/// <param name="utc">Input string in UTC format, e.g.
2009-01-23T11:57:26-06:00</param>
/// <returns>The Windows file time corresponding to the input
string.</returns>
/// <exception cref="System.FormatException">When input string format is
wrong.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">The resulting file
time would represent
/// a date and time before 12:00 midnight January 1, 1601 C.E.
UTC.</exception>
static public long UTCDateTimeToFileTime(string utc)
{
// Parse input string
string expectedFormat = "yyyy-MM-ddTHH:mm:sszzz";
DateTime resultDateTime = DateTime.ParseExact(utc, expectedFormat,
CultureInfo.InvariantCulture);

// Convert it to Windows file time
return resultDateTime.ToFileTime();
}

</code>

And this is a working C# program to test that:

<code language="C#">

//////////////////////////////////////////////////////////////////////////
/// Shows how to convert an UTC date time to a Windows file time.
///
/// by Giovanni Dicanio
//////////////////////////////////////////////////////////////////////////

using System;
using System.Globalization;

namespace ConsoleApplication1
{
class Program
{

/// <summary>
/// Converts a UTC date time string in a Windows file time.
/// </summary>
/// <param name="utc">Input string in UTC format, e.g.
2009-01-23T11:57:26-06:00</param>
/// <returns>The Windows file time corresponding to the input
string.</returns>
/// <exception cref="System.FormatException">When input string
format is wrong.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">The
resulting file time would represent
/// a date and time before 12:00 midnight January 1, 1601 C.E.
UTC.</exception>
static public long UTCDateTimeToFileTime(string utc)
{
// Parse input string
string expectedFormat = "yyyy-MM-ddTHH:mm:sszzz";
DateTime resultDateTime = DateTime.ParseExact(utc,
expectedFormat, CultureInfo.InvariantCulture);

// Convert it to Windows file time
return resultDateTime.ToFileTime();
}


// *** Test ***
static void Main(string[] args)
{
string inputDate = "2009-01-23T11:57:26-06:00";
try
{
Console.WriteLine("{0} corresponds to file time {1}.",
inputDate, UTCDateTimeToFileTime(inputDate));
}
catch (System.FormatException ex)
{
Console.WriteLine("Error in parsing date time string:");
Console.WriteLine(ex.Message);
}

return;
}
}
}

</code>

HTH,
Giovanni

Giovanni Dicanio

unread,
Jan 27, 2009, 11:27:46 AM1/27/09
to
> I've never done that with pure C++; however I've found that the .NET
> framework offers very convenient classes (as usual!) to do this kind of
> conversion and for parsing a string in the format you requested.

I'm not sure if it is as easy as with .NET, but if you have a need of having
100% native C++ code and no dependecies with .NET framework, I found this
from Boost, that might help:

http://www.boost.org/doc/libs/1_37_0/doc/html/date_time/date_time_io.html

Giovanni


Tom Serface

unread,
Jan 27, 2009, 12:12:53 PM1/27/09
to
Take a look at:

http://msdn.microsoft.com/en-us/library/38wh24td(VS.80).aspx

It has some cool parsing functionality.

Tom

"Michael Tissington" <nos...@nospam.com> wrote in message
news:%23VdQ%23ADgJ...@TK2MSFTNGP06.phx.gbl...

Giovanni Dicanio

unread,
Jan 27, 2009, 12:42:42 PM1/27/09
to

"Tom Serface" <t...@nospam.camaswood.com> ha scritto nel messaggio
news:0514A9E3-50C6-4ABE...@microsoft.com...

> Take a look at:
>
> http://msdn.microsoft.com/en-us/library/38wh24td(VS.80).aspx
>
> It has some cool parsing functionality.

I've not used it, but does it support time zone specification?

Thanks,
Giovanni


Tom Serface

unread,
Jan 27, 2009, 2:16:00 PM1/27/09
to
Here is a routine I used to convert a date I had:

CTime MyApp::ConvertUTCDateTime(LPCTSTR szDateTime)
{
// Parse the start date from format 2008-04-03T16:03:52+08:00
CString cs = szDateTime;
int i = cs.Find(_T('T'));
if(i != -1) {
CString csDate = cs.Left(i);
CString csTime = cs.Mid(i+1);
i = csTime.ReverseFind(_T('+'));
if(i == -1)
i = csTime.ReverseFind(_T('-'));
else {
// Use GMT?
csTime = csTime.Left(i);
}
cs.Format(_T("%s %s"),csDate,csTime);
COleDateTime oTime;
if(oTime.ParseDateTime(cs)) {
SYSTEMTIME sTime;
oTime.GetAsSystemTime(sTime);
return CTime(sTime);
}
}
return CTime::GetCurrentTime();
}

It workerd for me and I think the ParseDateTime() functions accepts a lot of
different date/time formats so it's pretty handy.

Tom
"Giovanni Dicanio" <giovanniD...@REMOVEMEgmail.com> wrote in message
news:uAnOsaKg...@TK2MSFTNGP04.phx.gbl...

Giovanni Dicanio

unread,
Jan 27, 2009, 5:11:06 PM1/27/09
to

"Tom Serface" <t...@nospam.camaswood.com> ha scritto nel messaggio
news:%23e9X5OL...@TK2MSFTNGP06.phx.gbl...

> Here is a routine I used to convert a date I had:
>
> CTime MyApp::ConvertUTCDateTime(LPCTSTR szDateTime)
> {
> // Parse the start date from format 2008-04-03T16:03:52+08:00

[...]

Tom: analyzing your code, I think that this code is missing the time zone
specification (e.g. +08:00) in the conversion.
Of course, I can be wrong, so please correct me if I am missing something
(it's also late here :)

I tried your routine with the addition of this code (beacuse the OP
requested a conversion to FILETIME):

<code>

LPCTSTR szInputDate = _T("2009-01-23T11:57:26-06:00");
CTime t = Tom::ConvertUTCDateTime(szInputDate);
SYSTEMTIME sysTime;
ATLVERIFY(t.GetAsSystemTime(sysTime));
FILETIME fileTime;

SystemTimeToFileTime(&sysTime, &fileTime);

</code>

And I compared that with the routine I proposed (using C++/CLI and .NET
System.DateTime.ParseExact with proper format string):

<code>


__int64 UTCDateTimeToFileTime(String^ utc)
{
// Parse input string
String^ expectedFormat = "yyyy-MM-ddTHH:mm:sszzz";
System::DateTime ^ resultDateTime = System::DateTime::ParseExact(
utc,
expectedFormat,
System::Globalization::CultureInfo::InvariantCulture
);

// Convert it to Windows file time
return resultDateTime->ToFileTime();
}
</code>

and it seems to me that we get two different results.

e.g. with the input string:

2009-01-23T11:57:26-06:00

my routine returns this 64-bit integer value for FILETIME:

0x1c97d840cc28700

instead yours returns this:

0x1c980d29222a000

I can be wrong, but my idea is that your code is not considering the time
zone specification.

Actually, I kind of hope that I am wrong :) because your code has the
advantage of being pure C++ and not depending on .NET framework classes.

Thanks,
G


Tom Serface

unread,
Jan 27, 2009, 7:46:34 PM1/27/09
to
G, you are right. The code I pasted is not what I'm using. There is a
subtle difference, but I was mostly trying to strip that off before doing
the parsing. Since the GMT value is there it could be added into the mix,
but I didn't need that granularity for what I was doing. I don't know if
ParseDateTime() would like the +- or Z stuff from UTC. I suspect not.

CTime Mycode::ConvertUTCDateTime(LPCTSTR szDateTime)


{
// Parse the start date from format 2008-04-03T16:03:52+08:00

CString cs = szDateTime;
int i = cs.Find(_T('T'));
if(i != -1) {
CString csDate = cs.Left(i);
CString csTime = cs.Mid(i+1);
i = csTime.ReverseFind(_T('+'));
if(i == -1) {
i = csTime.ReverseFind(_T('-'));
}

if(i != -1) {

Michael Tissington

unread,
Jan 27, 2009, 8:06:35 PM1/27/09
to

I'm a little confused with what you are doing with the "+08:00"

Isn't this a time value that has to be subtracted from the "16:03:52" to
arrive at the UTC ?

Giovanni Dicanio

unread,
Jan 28, 2009, 2:46:17 AM1/28/09
to

"Michael Tissington" <nos...@nospam.com> ha scritto nel messaggio
news:OmP9rSOg...@TK2MSFTNGP03.phx.gbl...

>
> I'm a little confused with what you are doing with the "+08:00"
>
> Isn't this a time value that has to be subtracted from the "16:03:52" to
> arrive at the UTC ?

Yes, but probably subtle cases should be considedered.
For example: if you do the subtraction, and you get a negative number, then
it means that you should update also the day (i.e. you are on the previous
day).
But that would mean that you may check also the month value that could
change (e.g. when passing from 1 February to January 31th). And probably a
consideration about years having February with 28 days vs. 29 days should be
done, too.
(And I'm not sure if daylight time considerations should be made....)

This is why I proposed to give that job to an "out of the box" method like
System.DateTime.ParseExact().

Giovanni

Hans-J. Ude

unread,
Jan 28, 2009, 5:14:33 AM1/28/09
to
"Tom Serface" <t...@nospam.camaswood.com> wrote:

>Here is a routine I used to convert a date I had:
>
>CTime MyApp::ConvertUTCDateTime(LPCTSTR szDateTime)
>{
> // Parse the start date from format 2008-04-03T16:03:52+08:00
> CString cs = szDateTime;
> int i = cs.Find(_T('T'));
> if(i != -1) {
> CString csDate = cs.Left(i);
> CString csTime = cs.Mid(i+1);
> i = csTime.ReverseFind(_T('+'));
> if(i == -1)
> i = csTime.ReverseFind(_T('-'));
> else {
> // Use GMT?
> csTime = csTime.Left(i);
> }
> cs.Format(_T("%s %s"),csDate,csTime);
> COleDateTime oTime;
> if(oTime.ParseDateTime(cs)) {
> SYSTEMTIME sTime;
> oTime.GetAsSystemTime(sTime);
> return CTime(sTime);
> }
> }
> return CTime::GetCurrentTime();
>}

In the old days we'd simply written

int year, month, day;
int hour, minute, second;
int tz_hour, tz_minute;
char *p = "2009-01-23T11:57:26+06:00";

sscanf(p, "%d-%d-%dT%d:%d:%d%d:%d",
&year, &month, &day,
&hour, &minute, &second,
&tz_hour, &tz_minute );

That works with positive as negative TZ values as well. I'm not sure
about an official definition of that string format. If there are
differences it would fail. sscanf() is deprecated and there is also
unicode these days, so sscanf_s() or swscanf_s() would be the choice
today.

Hans

Tom Serface

unread,
Jan 28, 2009, 10:58:03 AM1/28/09
to
I think the aversion (I'm hearing) to this method or mine is that even
though the GMT value is retrievable it is not accounted for in the actual
time . I think it would be easy enough to change the time into it's raw
number add or subtract based on the GMT value, then change it back into a
CTime, but I haven't needed to do that so there may be more to it.

Tom

"Hans-J. Ude" <ne...@s237965939.online.de> wrote in message
news:gfb0o4po27a8t26a5...@4ax.com...

.rhavin grobert

unread,
Jan 28, 2009, 12:11:15 PM1/28/09
to
On 27 Jan., 13:28, "Giovanni Dicanio"
<giovanniDOTdica...@REMOVEMEgmail.com> wrote:
> "Michael Tissington" <nos...@nospam.com> ha scritto nel messaggionews:%23VdQ%23ADgJ...@TK2MSFTNGP06.phx.gbl...

>
> > How can I parse the following string as a FILETIME ?
>
> > "2009-01-23T11:57:26-06:00"
>
> To add to what I previously wrote, unfortunately in this string there is a
> specification of a time zone (e.g. "-06:00").

modify your FILETIME result by 600,000,000 ticks per second timediff
and you're done ;-)

Giovanni Dicanio

unread,
Jan 28, 2009, 1:16:17 PM1/28/09
to

".rhavin grobert" <cl...@yahoo.de> ha scritto nel messaggio
news:e0801223-9f1d-4afb...@t26g2000prh.googlegroups.com...

I think there could be subtle cases, too.

As I wrote already in this thread:

<cite>


Yes, but probably subtle cases should be considedered.
For example: if you do the subtraction, and you get a negative number, then
it means that you should update also the day (i.e. you are on the previous
day).
But that would mean that you may check also the month value that could
change (e.g. when passing from 1 February to January 31th). And probably a
consideration about years having February with 28 days vs. 29 days should be
done, too.
(And I'm not sure if daylight time considerations should be made....)

</cite>

Giovanni

Giovanni Dicanio

unread,
Jan 28, 2009, 1:26:33 PM1/28/09
to

"Giovanni Dicanio" <giovanniD...@REMOVEMEgmail.com> ha scritto nel
messaggio news:O%

> I think there could be subtle cases, too.

My bad, you are right .rhavin!

We can do the subtraction from FILETIME (__int64).

Thanks,
Giovanni


Giovanni Dicanio

unread,
Jan 28, 2009, 1:29:25 PM1/28/09
to

".rhavin grobert" <cl...@yahoo.de> ha scritto nel messaggio
news:e0801223-9f1d-4afb...@t26g2000prh.googlegroups.com...

I think that this idea of subtracting an amount based from time zone
difference from FILETIME value is good; probably you have nailed the problem
:)

Thanks,
Giovanni

Michael Tissington

unread,
Jan 28, 2009, 4:09:43 PM1/28/09
to
Thanks - this is what I ended up doing...

SYSTEMTIME st = {0};
LONG ltzHour;
LONG ltzMinute;
ULONGLONG ull;

sscanf(psz, "%d-%d-%dT%d:%d:%d%d:%d", &st.wYear, &st.wMonth, &st.wDay,
&st.wHour, &st.wMinute, &st.wSecond, &ltzHour, &ltzMinute);
SystemTimeToFileTime(&st, (LPFILETIME)&ull);

// Adjust for the tz
ull += ltzHour * (__int64)-10000000;

// Save the result into the FILETIME structure.
m_ftEarliest.dwLowDateTime = (DWORD) (ull & 0xFFFFFFFF);
m_ftEarliest.dwHighDateTime = (DWORD) (ull >> 32);

Tom Serface

unread,
Jan 28, 2009, 4:34:52 PM1/28/09
to
Thanks for posting the solution. I like that solution as well so long as
the formatting remains consistent. You may be interested in checking out
this version of sscanf...

http://msdn.microsoft.com/en-us/library/t6z7bya3(VS.80).aspx

Tom

"Michael Tissington" <nos...@nospam.com> wrote in message

news:%238AF$yYgJH...@TK2MSFTNGP05.phx.gbl...

0 new messages