Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Converting the WhenChanged attribute (Generalized-Time) in LDAP to a DateTime in C#

Tags:

c#

datetime

ldap

I recently switch from using S.DS namespace (which uses ADSI) to the S.SD.Protocol namespace. The only problem is that ADSI handled the conversion of Generalized-Time to a DateTime for me. Now I'm getting back a value of "20070828085401.0Z" for the WhenChanged attribute. DateTime.Parse() will not convert this so is there another way?

like image 981
Shawn Avatar asked Apr 01 '11 19:04

Shawn


4 Answers

The format you are getting is close to the round trip date time pattern ("o") and universal sortable round trip date time pattern ("u") standard date time format strings as described here.

One kludgy solution would be to massage the string you get to fit the pattern and then use the "o" or "u" standard format string with ParseExact.

A better way would be to construct a custom format string that matches the data you are already getting. In the "How Standard Format Strings Work" section of the standard date time format strings page you'll see the full custom formatting strings equivalent to "o" and "u". That should give you a good start.


EDIT: Add code

string format = "yyyyMMddHHmmss.f'Z'";

string target = "20070828085401.0Z";

DateTime d = DateTime.ParseExact(target, format, CultureInfo.InvariantCulture);

In the comments lixonn observes that, using the format string above, ParseExact will not successfully parse a time string like 199412160532-0500.

It also won't parse a number of other valid strings such as times without the trailing 'Zulu' indicator (20070828085401.0); times without a fractional part (20070828085401Z) and times that represent minutes and seconds as a fractional hour (2007082808.90028Z).

The format string can be made slightly more forgiving by replacing the hard-coded 'Z' with the K custom specifier which will accept 'Z', an offset like -0500, and nothing. Whether that additional flexibility is a good thing will depend on your application.

Note that even with the K specifier Lixonn's string won't be parsed successfully since it lacks a fractional part to match the .f component of the format string.

like image 79
Frank Boyne Avatar answered Oct 08 '22 13:10

Frank Boyne


You'll have to use DateTime.ParseExact() specifying the exact format. You might have to play with the format a little bit but it would be something like this.

DateTime result;
CultureInfo provider = CultureInfo.InvariantCulture;
string format="yyyyMMddhhmmss.0Z";
result = DateTime.ParseExact(dateString, format, provider);
like image 37
Bala R Avatar answered Oct 08 '22 15:10

Bala R


You can use datetime's .strptime().

    import datetime

    # Since 0Z denotes UTC, you can get rid of it and apply the timezone 
    # later if you would like
    time_string = "20070828085401.0Z".split('.')[0]
    time_object = datetime.datetime.strptime(time_string, "%Y%m%d%H%M%S")

time_object should output as datetime.datetime(2007, 8, 28, 8, 54, 1). I believe it will be timezone naive, and equivalent to UTC time.

like image 31
MaryKN Avatar answered Oct 08 '22 14:10

MaryKN


// WIN32 FILETIME is a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (UTC).
// While the unix timestamp represents the seconds since January 1, 1970 (UTC).
private static long Win32FileTimeToUnixTimestamp(long fileTime)
{
    //return fileTime / 10000L - 11644473600000L;
    return DateTimeOffset.FromFileTime(fileTime).ToUnixTimeSeconds();
}

// The GeneralizedTime follows ASN.1 format, something like: 20190903130100.0Z and 20190903160100.0+0300
private static long GeneralizedTimeToUnixTimestamp(string generalizedTime)
{
    var formats = new string[] { "yyyyMMddHHmmss.fZ", "yyyyMMddHHmmss.fzzz" };
    return DateTimeOffset.ParseExact(generalizedTime, formats, System.Globalization.CultureInfo.InvariantCulture).ToUnixTimeSeconds();
}
like image 30
Eng.Fouad Avatar answered Oct 08 '22 13:10

Eng.Fouad