How to parse string with long milliseconds (nanoseconds) part to DateTime? - c#

I'm trying to figure-out the right string format of the following given date-time literal:
18-JUN-13 12.17.36.000000000
Using MSDN, I managed to composed the following format:
"d'-'MMM'-'y'T'h'.'m'.'s'.'fff"
But when using the DateTime.ParseExact, the parsing fails with a FormatException: String was not recognized as a valid DateTime.
My code:
DateTime.ParseExact("18-JUN-13 12.17.36.000000000", "d'-'MMM'-'y'T'h'.'m'.'s'.'fff", null);

You can use
dd-MMM-yy hh.mm.ss.fffffff
with english based culture like InvariantCulture for example. I'm on mobile right now, so I can't try it :(
AFAIK, milliseconds part parsing limit is 7, that's why you can't parse your string without manipulate it. You can use it like;
var dt = DateTime.ParseExact("18-JUN-13 12.17.36.0000000",
"dd-MMM-yy HH.mm.ss.fffffff",
CultureInfo.InvariantCulture);
Looks like that's why probably we have The "fffffff" custom format as top character of milliseconds. From docs;
Although it is possible to display the ten millionths of a second
component of a time value, that value may not be meaningful. The
precision of date and time values depends on the resolution of the
system clock. On the Windows NT 3.5 (and later) and Windows Vista
operating systems, the clock's resolution is approximately 10-15
milliseconds.
You asked;
How would you have manipulate the string?
Well, one way to get last index of comma and substring it to 8 index after that like;
string s = "18-JUN-13 12.17.36.000000000";
var dateString = s.Substring(0, s.LastIndexOf(".") + 8);

You have a bunch of single quotes in there which isn't a correct format. Try this
DateTime.ParseExact("18-JUN-13 12.17.36.000000000", "d-MMM-yTh.m.s.fff", null);

Related

DateTime.UtcNow.ToString("yyyy/MM/dd HH:mm:ss") gives different formats for different users

I assumed that ToString("yyyy/MM/dd HH:mm:ss") will force the string to be formatted with '/', but I can see that every device gets different formats. How can I force it to be saved with '/'?
Good example-
2021/10/06 18:05:53
Strange examples I see in my DB from different users-
2021-10-06 23:48:37
2021.10.12 12:41:42
2021. 10. 06 19:17:23 ('.'+ space after)
2021.10.13 19.18.16
One solution is to replace every -, . and . to /, but this only solves the strange examples I found. What if there are others?
/ in a format string means "the culture-specific date separator". If you want the literal forward-slash, quote it (and the colons, to avoid the use of a custom time separator):
ToString("yyyy'/'MM'/'dd HH':'mm':'ss")
Alternatively - and probably better - use the invariant culture. Not only will that use / as the date separator, but you won't need to worry about a culture having a different default calendar. (It'll always use the Gregorian calendar, which is presumably what you want.)
Even better, use an ISO-8601 format - you're already using a "slightly unusual for humans" format of year-first, so you might as well go the whole hog and go with the standard format for dates and times.
Sample code:
String text = dateTimeValue.ToString(
"yyyy-MM-dd'T'HH:mm:ss",
CultureInfo.InvariantCulture);
This is also the sortable standard date/time format so you can simplify the code significantly:
String text = dateTimeValue.ToString("s");
(That format always uses the invariant culture.)
That's if you really need to format the string at all, though. If you're saving it in a database, I'd advise you to:
Use an appropriate type in the database, e.g. DATETIME
Store it using a parameter (specifying the value just as a DateTime), not formatted text
If you do both of these, you'll avoid oddities like this.
Another solution that I can think of is creating a new function that creates a date
DateTime date= DateTime.UtcNow;
And extracting manually and splitting the date to a few strings (year,month,day,hour,month,seconds)
string year = date.Year.ToString(); string month = date.Month.ToString();...
and building a string out of it in the right format,
string newDate= year + "/" + month + "/" + day + " "+ hour+":"+ minute+ ":"+seconds;
that way I can be sure it's always one format that I'll decide on
How about storing the date as a number, eg unix time - DateTimeOffset.UtcNow.ToUnixTimeSeconds() or (DateTime.UtcNow - DateTime.UnixEpoch).TotalSeconds - it's a lot simpler and cheaper to store a number than a string
Also wanted to point out that the only date I've
seen you store so far is UtcNow (as written in your answer) - fire base does appear to have a solution for that in that you can send ServerValue.TIMESTAMP and it will cause fb to store the unix time as the server sees it.
My take away from this (never used fb) is that that's how they store dates so perhaps it makes sense to follow :)

Unable to convert DateTime from SQL Server to C# DateTime

I wrote a program in C# that uses dates. It takes the value from a SQL Server table. I was using Windows 7 and the program worked fine. I had this line of code:
DateTime fechaOperacion = Convert.ToDateTime(reader["FechaOperacion"]);
The reader returned a date in a 24h format and I was able to convert that to a DateTime variable.
Now I did a system upgrade to Windows 10 and that same line of code is throwing the following error:
String was not recognized as a valid DateTime. there is an unknown word starting at index 20.
And now the reader returns a.m. / p.m. format, and at index 20 there is a.m or p.m.
I have tried the following things:
Rephrasing the line of code to:
Convert.ToDateTime(reader["FechaOperacion"], System.Globalization.CultureInfo.InvariantCulture)
reader.GetDateTime(reader.GetOrdinal("FechaOperacion"));
Convert the culture to 24h format
System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo(1033);
But none of that seems to work, I don't know what else to do.
Ultimately, the underlying problem here is storing a value that represents a date/time as textual data (meaning, some kind of [n][var]char({max|n}), or at a push: [n]text). This has multiple problems:
it takes more space
it cannot be sorted correctly / efficiently
it cannot be indexed correctly / efficiently
it cannot be filtered correctly / efficiently
it leads to parsing errors between client and server
it has all sorts of localization and internationalization problems
What you should have is a datetime / date / time / etc column. This is then stored as a number (not a string) that requires zero parsing and will work reliably without any conversion problems.
Note: it could be that you are storing it correctly but formatting it inside the select statement of your query. In which case, just don't do that; return the date-time raw, and let the receiving client worry about how to display it.
Depending on your actual format, you can define a suitable format list and do a conversion like below
string[] mfs = { "MM/dd/yyyy HH:mm:ss", "MM/dd/yyyy h:mm:ss tt"};
var dat = DateTime.ParseExact("04/23/1945 8:45:22 PM", mfs,
System.Globalization.CultureInfo.InvariantCulture,
System.Globalization.DateTimeStyles.None);

Short Time with DateTime.ParseExact

I’m trying to parse a time. I’ve seen this question asked/answered here many times but not for this specific scenario. Here’s my code:
var time1 = DateTime.ParseExact("919", "Hmm", CultureInfo.InvariantCulture);
also
var time2 = DateTime.ParseExact("919", "Hmm", null);
both of these throw the same
"String was not recognized as a valid DateTime"
What I want is 9:19 AM.
For further info I also need to parse “1305” as 1:05 PM, this is working fine.
It seems to me I’m using the correct format. What am I overlooking?
I'm not sure there is any format that can handle this. The problem is that "H" can be either one digit or two, so if there are two digits available, it will grab both - in this case parsing it as hour 91, which is clearly invalid.
Ideally, you'd change the format to HHmm - zero-padding the value where appropriate - so "0919" would parse fine. Alternatively, use a colon in the format, to distinguish between the hours and the minutes. I don't believe there's any way of making DateTime parse a value of "919" as you want it to... so you'll need to adjust the string somehow before parsing it. (We don't have enough context to recommend a particular way of doing that.)
Yes, your format is right but since H specifier might be 2 character, ParseExact method try to parse 91 as an hour, which is an invalid hour, that's why you get FormatException in both case.
I connected to microsoft team about this situation 4 months ago. Take a look;
DateTime conversion from string C#
They suggest to use 2 digit form in your string or insert a date separator between them.
var time1 = DateTime.ParseExact("0919", "Hmm", CultureInfo.InvariantCulture);
or
var time1 = DateTime.ParseExact("9:19", "H:mm", CultureInfo.InvariantCulture);
You cant exclude the 0 prefix to the hour. This works
var time1 = DateTime.ParseExact("0919", "Hmm", CultureInfo.InvariantCulture);
Perhaps you want to just prefix 3-character times with a leading zero before parsing.
Much appreciated for all the answers. I don’t have control of the text being created so the simplest solution for me seemed to be prefixing a zero as opposed to adding a colon in the middle.
var text = "919";
var time = DateTime.ParseExact(text.PadLeft(4, '0'), "Hmm", null);

TimeSpan.Parse Parsing Issue

I am trying to parse time using TimeSpan.Parse method; However i get an unexpected result as i am trying to parse this 00:00:45.748 which supposed to be
0 Hours
0 Minutes
45 Seconds
748 Milliseconds
TimeSpan.Parse("00:00:45.748")
Result :
00:00:45.7480000
I want to know why it reads the milliseconds as 7480000 instead of 748 ?
The result you are showing is that of displaying a TimeSpan in a textual format.
By default it will show the full range.
The string you have shown actually shows that the parse was successful and you got the right result.
If you want to format the TimeSpan, use ToString with an appropriate TimeSpan format string (.NET 4.0 and above).
There are custom and standard format strings for TimeSpan.
In your case, it looks like you are looking for:
myTimeSpan.ToString("hh:mm:ss.FFF")
As additional to Oded's answer;
From TimeSpan.Parse Method (String)
ff - Optional fractional seconds, consisting of one to seven decimal
digits.
You can use The "FFF" Custom Format Specifier
Like;
TimeSpan ts = TimeSpan.Parse("00:00:45.748");
Console.WriteLine(ts.ToString(#"hh\:mm\:ss\.FFF"), CultureInfo.InvariantCulture);
Output will be;
00:00:45.748
For more informations, take a look at Standard TimeSpan Format Strings and Custom TimeSpan Format Strings
00:00:45.7480000 == 00:00:45.748
The difference is simply the number of decimal places on the milliseconds
This will format your output as desired:
var ts = TimeSpan.Parse("00:00:45.748");
Console.WriteLine(string.Format("{0:dd\\:hh\\:mm\\:ss\\.fff}", ts));
The fff is the number of decimal places you want to display (this can be from 1 to 7). See http://msdn.microsoft.com/en-us/library/ee372287.aspx
Note that this will require .NET 4.0 or above

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

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?
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.
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);
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.
// 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();
}

Categories