Date Time Format String only for Milliseconds - c#

for a Project i parse timestamps from filenames and each has its own format. I get the files from a partner company, so the naming of the files is non negotiable. The problem now is, that besides one, every filename has a nice time format that can easily be transferred to a c# date time format string to be parsed into a DateTime object. The one that differs, strictly uses milliseconds since initialization as it's timestamp similar to
+4311123234_12345 M.txt where the numbers after the underscore are said milliseconds.
In this example the milliseconds would be 12345 but a filename could also be +4311123234_123423402345802345 M.txt where 123423402345802345 would be said milliseconds. To me only the milliseconds part is relevant and is extracted from the filename. I now want a string such as "yyyy" (for year typically) where this number is then parsed to a DateTime Object via the TryParseExact method. It is not important from when the milliseconds are counted, since it is just used for sorting so for all i care they can be the milliseconds elapsed since 01.01.1900 00:00:00.
I did a google search but came to the conclusion, that such a date time format string doesn't really exist. I know that there is ss.fffff but since i do not know how many digits the millisecond timestamp has, i would have to generate a seperate formatstring with the according number of 'f's. This is also no option, because the format string should be a user input.
Right now i coupled it to a special keyword, so that when the input is keyword the time will not be parsed by a timeformatstring but simply by the milliseconds that i got from parsing the section in the filename to a long.
It works fine, but it really isn't ideal in my opinion...
What i forgot to say was, that the string containing the timestamp is extracted from the filename via Regex CaptureGroups, so in the code example the timestampstring is in cc[0]
private static void CheckForValidMatch(SortedList<DateTime, string> files, string file, Match match,string dateTimeFormat,int groupNumber)
{
Group group = match.Groups[groupNumber];
CaptureCollection cc = group.Captures;
DateTime dateTime;
if (cc.Count == 0)
Debug.WriteLine("group did not capture anything");
else
{
if (dateTimeFormat.Equals("keyword"))
{
if (long.TryParse(cc[0].ToString(),out var result))
{
dateTime = new DateTime(result);
files.Add(dateTime, file);
}
return;
}
if (!DateTime.TryParseExact(cc[0].ToString(),dateTimeFormat,DateTimeFormatInfo.CurrentInfo,DateTimeStyles.AssumeLocal, out dateTime))
Debug.WriteLine("parsing the date time failed");
else
{
files.Add(dateTime, file);
}
}
}
Is there a way to make this more elegant, or does someone know a formatstring only for milliseconds?
Thanks in advance!

Don't expect to parse it directly as a datetime. Instead, keep a constant epoch DateTime value for the base date, parse the file name as a long, and then do this:
var FileDate = epoch.AddMilliseconds(parsedLongValue);
So we get this:
private static void CheckForValidMatch(SortedList<DateTime, string> files, string file, Match match,string dateTimeFormat,int groupNumber)
{
var cc = match.Groups[groupNumber].Captures;
if (cc.Count == 0)
{
Debug.WriteLine("group did not capture anything");
return;
}
DateTime dateTime;
if (dateTimeFormat == "keyword")
{
// I don't know your epoch date, but Jan 1, 1970 is common (it's the unix epoch)
const DateTime epoch = new DateTime(1970, 1, 1);
if (long.TryParse(cc[0].ToString(),out var result))
{
dateTime = epoch.AddMilliseconds(result);
}
else
{
Debug.WriteLine($"parsing the date time for {dateTimeormat} failed");
return;
}
}
else if (!DateTime.TryParseExact(cc[0].ToString(),dateTimeFormat,DateTimeFormatInfo.CurrentInfo,DateTimeStyles.AssumeLocal, out dateTime))
{
Debug.WriteLine("parsing the date time failed");
return;
}
files.Add(dateTime, file);
}

Related

Convert time duration from String to TimeSpan

I have a string that contains day of the week, time and duration. E.g. Monday,10:00 AM,45m
The duration could be in either of the following formats:
45m
1h45m
1h
Now I need to convert this into a date with time for both the start of the event and end of the event based on the duration.
I managed to convert this piece "Monday,10:00 AM" into the upcoming date and time for whatever the day of the week is so now I have a datetime as let's say "05/30/2022 10:00:00 AM".
Now I need to create a datetime object for the end time of the event by adding e.g. "45m" to the previous datetime. I don't know the format of the duration piece but it will be one of three from the list above.
How do I convert this into a standard timespan to add to the previous time? Is the above format a standard format that perhaps has a built in way to parse? It's coming from an API.
I have tried this and it works but I'm not sure how to detect and handle the formats.
\\split the original string so now I have duration
\\when I have just the hour duraton e.g. 1h
t = TimeSpan.ParseExact(durationString, "h\\h", CultureInfo.InvariantCulture);
var finalDate = dt.Add(t);
\\when I have just the minute format e.g. 45m
t = TimeSpan.ParseExact(durationString, "m\\m", CultureInfo.InvariantCulture);
Use a ParseExact method overload that accepts an array of formats.
var values = new string[] { "45m", "1h45m", "1h" };
var formats = new string[] { #"m\m", #"h\hm\m", #"h\h" };
foreach (var value in values)
{
var ts = TimeSpan.ParseExact(value, formats, CultureInfo.InvariantCulture);
Console.WriteLine(ts);
}
You can use REGEX to check for matching patterns:
using System.Text.RegularExpressions;
Regex HourOnly = new Regex("^[0-9]+h$");
Regex MinuteOnly = new Regex("^[[0-9]+m");
Regex HourAndMinute = new Regex("^[0-9]+h[0-9]+m$");
List<string> conditions = new List<string>();
string Condition1 = "Monday,10:00 AM,45m";
string Condition2 = "Monday,10:00 AM,1h45m";
string Condition3 = "Monday,10:00 AM,1h";
conditions.Add(Condition1);
conditions.Add(Condition2);
conditions.Add(Condition3);
foreach(string condition in conditions)
{
if (HourOnly.IsMatch(condition.Split(',').Last()))
{
Console.WriteLine($"Hour only: {condition}");
}
else if (HourAndMinute.IsMatch(condition.Split(',').Last()))
{
Console.WriteLine($"Hour and minute: {condition}");
}
else if (MinuteOnly.IsMatch(condition.Split(',').Last()))
{
Console.WriteLine($"Minute only: {condition}");
}
}
Granted users can enter 99999h99999m but if you are reasonably sure that won't happen the above regex should suit you just fine.
Here is some additional documentation to aid you on your quest: https://learn.microsoft.com/en-us/dotnet/standard/base-types/regular-expression-language-quick-reference

How to parse a timespan in order to add it to a datetime?

I've got a string in the following format: 05/06/2019|1330|60
The output I'm looking for is: 05/06/2019T14:30:00
I'm attempting to parse out the TimeSpan portion right now:
public static string getProcedureEndingDateTime (string input) {
//05/06/2019|1330|60
string myDate = input.Split ( '|' ) [0];
DateTime myDateTime = DateTime.Parse (myDate);
string myTime = input.Split('|')[1];
string hours = myTime.Substring(0,2);
string minutes = myTime.Substring(2,2);
TimeSpan myTimeSpan = TimeSpan.Parse($"{hours}:{minutes}");
myDateTime.Add(myTimeSpan);
return myDateTime.ToString();
}
But right now, getting the following output:
To get the above output I'm calling my function like so:
Console.WriteLine (getProcedureEndingDateTime("05/06/2019|1330|60"));
How do I parse the string "1330" into a TimeSpan?
No need to us a Timespan here, just call ParseExact instead with a proper format to do it in one line.
var myDateTime = DateTime.ParseExact("05/06/2019|1330|60", "dd/MM/yyyy|HHmm|60", CultureInfo.InvariantCulture);
Console.WriteLine(myDateTime.ToString());
//this gives 2019-06-05 1:30:00 PM, format depends on your PC's locale
I don't know what the 60 part is, you can adjust the format or substring it out beforehand.
The problem is because Add() returns a new DateTime instance, which means you're currently discarding it. Store it, and return that from your function instead, like so:
var adjusted = myDateTime.Add(myTimeSpan);
return adjusted.ToString();
Try using the numeric values as exactly that, numbers.
Also, the other issue with your code is the DateTime.Add() method doesn't add to that DateTime variable. Instead it returns a new variable, which you are ignoring.
Try this:
public static string getProcedureEndingDateTime (string input) {
string[] parts = input.Split('|');
string myDate = parts[0];
DateTime myDateTime = DateTime.Parse (myDate);
string myTime = parts[1];
if (!int.TryParse(myTime.Substring(0,2), out int hours))
hours = 0;
if (!int.TryParse(myTime.Substring(2,2), out int minutes))
minutes = 0;
TimeSpan myTimeSpan = new TimeSpan(hours, minutes, 0);
myDateTime += myTimeSpan;
return myDateTime.ToString();
}
Assuming the date shown is May 6th (and not June 5th), and also assuming the 60 represents a time zone offset expressed in minutes west of GMT, and also assuming you want the corresponding UTC value, then:
public static string getProcedureEndingDateTime (string input) {
// example input: "05/06/2019|1330|60"
// separate the offset from the rest of the string
string dateTimeString = input.Substring(0, 15);
string offsetString = input.Substring(16);
// parse the DateTime as given, and parse the offset separately, inverting the sign
DateTime dt = DateTime.ParseExact(dateTimeString, "MM/dd/yyyy|HHmm", CultureInfo.InvariantCulture);
TimeSpan offset = TimeSpan.FromMinutes(-int.Parse(offsetString));
// create a DateTimeOffset from these two components
DateTimeOffset dto = new DateTimeOffset(dt, offset);
// Convert to UTC and return a string in the desired format
DateTime utcDateTime = dto.UtcDateTime;
return utcDateTime.ToString("MM/dd/yyyy'T'HH:mm:ss", CultureInfo.InvariantCulture);
}
A few additional points:
Not only is the input format strange, but so is your desired output format. It is strange to see a T separating the date and time and also see the date in the 05/06/2019 format. T almost always means to use ISO 8601, which requires year-month-day ordering and hyphen separators. I'd suggest either dropping the T if you want a locale-specific format, or keep the T and use the standard format. Don't do both.
In ISO 8601, it's also a good idea to append a Z to UTC-based values. For DateTime values, the K specifier should be used for that. In other words, you probably want the last line above to be:
return utcDateTime.ToString("yyyy-MM-dd'T'HH:mm:ssK", CultureInfo.InvariantCulture);
// outputs: "2019-05-06T14:30:00Z"
You might want to not format a string here, but instead return the DateTime or DateTimeOffset value. It's usually better to create a string only at the time of display.
Don't forget that the DateTime struct is immutable. In your question you were ignoring the return value of the Add method.

How to get the desired output by modifying string after removing / from string

I have a string like this:
30/04/2018 o/p=300418
01/03/2017 o/p=010317
10/11/2018 o/p=101118
12/11/2123 o/p=121123
1/1/2018 o/p =010118
code tried but can't get the last one 1/1/2018
string a = "31/04/2018";
string b = a.Replace("/","");
b = b.Remove(4, 2);
You should parse to a DateTime and then use the ToString to go back to a string. The following works with your given input.
var dateStrings = new []{"30/04/2018", "01/03/2017","10/11/2018","12/11/2123","1/1/2018"};
foreach(var ds in dateStrings)
{
Console.WriteLine(DateTime.ParseExact(ds, "d/M/yyyy", System.Globalization.CultureInfo.InvariantCulture).ToString("ddMMyy"));
}
The only change I made is to the first date as that is not a valid date within that month (April has 30 days, not 31). If that is going to be a problem then you should change it to TryParse instead, currently I assumed your example was faulty and not your actual data.
Your structure varies, all of the examples above use two digit month and day, while the bottom only uses a single digit month and day. Your current code basically will replace the slash with an empty string, but when you remove index four to two your output would deviate.
The simplest approach would be:
var date = DateTime.Parse("...");
var filter = $"o/p = {date:MMddyyyy}";
Obviously you may have to validate and ensure accuracy of your date conversion, but I don't know how your applications works.
If you can reasonably expect that the passed in dates are actual dates (hint: there are only 30 days in April) you should make a function that parses the string into DateTimes, then uses string formats to get the output how you want:
public static string ToDateTimeFormat(string input)
{
DateTime output;
if(DateTime.TryParse(input, out output))
{
return output.ToString("MMddyy");
}
return input; //parse fails, return original input
}
My example will still take "bad" dates, but it will not throw an exception like some of the other answers given here (TryParse() vs Parse()).
There is obviously a small bit of overhead with parsing but its negligible compared to all the logic you would need to get the proper string manipulation.
Fiddle here
Parse the string as DateTime. Then run ToString with the format you desire.
var a = "1/1/2018";
var date = DateTime.Parse(a);
var result = date.ToString("ddMMyyyy");
You can use ParseExact to parse the input, then use ToString to format the output.
For example:
private static void Main()
{
var testData = new List<string>
{
"31/04/2018",
"01/03/2017",
"10/11/2018",
"12/11/2123",
"1/1/2018",
};
foreach (var data in testData)
{
Console.WriteLine(DateTime.ParseExact(data, "d/m/yyyy", null).ToString("ddmmyy"));
}
GetKeyFromUser("\nDone! Press any key to exit...");
}
Output
You didn't specify whether these are DateTime values or just strings that look like date time values. I'll assume these are DateTime values.
Convert the string to a DateTime. Then use a string formatter. It's important to specify the culture. In this case dd/mm/yyyy is common in the UK.
var culture = new CultureInfo("en-GB");//UK uses the datetime format dd/MM/yyyy
var dates = new List<string>{"30/04/2018", "01/03/2017","10/11/2018","12/11/2123","1/1/2018"};
foreach (var date in dates)
{
//TODO: Do something with these values
DateTime.Parse(date, culture).ToString("ddMMyyyy");
}
Otherwise, running DateTime.Parse on a machine with a different culture could result in a FormatException. Parsing dates and times in .NET.

String was not recognized as a valid DateTime. ParseExact - Just Date

I've tried with several different format strings but I can't get it to parse a date like:
date = "10/16/13";
DateTime endDate = DateTime.ParseExact(date, "M-dd-yy", CultureInfo.InvariantCulture);
What am I missing?!
For it to parse the date your format needs to be the same. Change "M-dd-yy" to "M/dd/yy" Assuming that the month is a single digit and the day is always 2 digits.
Here you go this should work just fine. You just need to be aware that it will set a default time of 12:00 am because you are not specifying the time in your string.
class Program
{
static void Main(string[] args)
{
string date = "10/16/13";
//This is usually the safer way to go
DateTime result;
if(DateTime.TryParse(date, out result))
Console.WriteLine(result);
//I think this is what you were trying to accomplish
DateTime result2 = Convert.ToDateTime(date, CultureInfo.InvariantCulture);
Console.ReadKey();
}
}

DateTime.TryParseExact method for string comparison

Hey how can you do a string comparison match for a given date, DateTime.TryParseExact seems like the sensible option but I am not sure how to construct the arguement in the below method:
public List<Dates> DateEqualToThisDate(string dateentered)
{
List<Dates> date = dates.Where(
n => string.Equals(n.DateAdded,
dateentered,
StringComparison.CurrentCultureIgnoreCase)).ToList();
return hiredate;
}
If you know the format of the date/time exactly (i.e. it never changes, and does not depend on the culture or locale of the user), then you can use DateTime.TryParseExact.
For example:
DateTime result;
if (DateTime.TryParseExact(
str, // The string you want to parse
"dd-MM-yyyy", // The format of the string you want to parse.
CultureInfo.InvariantCulture, // The culture that was used
// to create the date/time notation
DateTimeStyles.None, // Extra flags that control what assumptions
// the parser can make, and where whitespace
// may occur that is ignored.
out result)) // Where the parsed result is stored.
{
// Only when the method returns true did the parsing succeed.
// Therefore it is in an if-statement and at this point
// 'result' contains a valid DateTime.
}
The format string can be a fully specified custom date/time format (such as dd-MM-yyyy), or a general format specifier (such as g). For the latter, the culture matters as to how the date is formatted. For example, in the Netherlands dates are written as 26-07-2012 (dd-MM-yyyy) whereas in the US dates are written as 7/26/2012 (M/d/yyyy).
However, this all only works when your string str contains only the date you want to parse. If you have a bigger string with all sorts of unwanted characters around the date, then you'll have to find the date in there first. This can be done using a regular expression, which is a whole other topic in itself. Some general information about regular expressions (regex) in C# can be found here. A regular expression reference is here. For example, a date similar to d/M/yyyy can be found using the regex \d{1,2}\/\d{1,2}\/\d{4}.
Another way of doing it is to convert your date from string to DateTime. If it is possible I would keep DateAdded as DateTime.
Bellow is a code that runs in LINQPad
public class Dates
{
public string DateAdded { get; set; }
}
List<Dates> dates = new List<Dates> {new Dates {DateAdded = "7/24/2012"}, new Dates {DateAdded = "7/25/2012"}};
void Main()
{
DateEqualToThisDate("7/25/2012").Dump();
}
public List<Dates> DateEqualToThisDate(string anything)
{
var dateToCompare = DateTime.Parse(anything);
List<Dates> hireDates = dates.Where(n => DateTime.Parse(n.DateAdded) == dateToCompare).ToList();
return hireDates;
}

Categories

Resources