DateTime with offset Parse in NodaTime - c#

If I have a string like "2020-12-15T12:10:00.202-08:00" how can I parse this into NodaTime.LocalDateTime
or ZonedDateTime directly, rather than doing something like:
LocalDateTime.FromDateTime(DateTime.Parse("2020-12-15T12:10:00.202"))
And similarly for the other NodaTime types like LocalDate, Instant etc.
my end goal is to take the offset/timezone and change it to another
Help is appreciated.
I believe I need to work with modifying the pattern:
Var pattern = LocalDateTimePattern.CreateWithInvariantCulture("yyyy-MM-dd'T'HH:mm:ss.fff");
but I tried to add a z at the end for the timezone and that appears to be incorrect
even saw another post that mentions make it the full 9 digits:
static readonly ZonedDateTimePattern ParsePatternA =
ZonedDateTimePattern.CreateWithInvariantCulture("uuuu'-'MM'-'dd'T'HH':'mm':'ss.fffffffffz", DateTimeZoneProviders.Tzdb);

The value you've got there is logically an OffsetDateTime. Fortunately the pattern is simple ISO-8601, so you don't need to create any kind of custom pattern.
I'd strongly advise you to parse directly to the type that the value logically represents, then perform any conversions if you need to.
using NodaTime;
using NodaTime.Text;
string text = "2020-12-15T12:10:00.202-08:00";
OffsetDateTimePattern pattern = OffsetDateTimePattern.ExtendedIso;
ParseResult<OffsetDateTime> parseResult = pattern.Parse(text);
if (parseResult.Success)
{
OffsetDateTime value = parseResult.Value;
Console.WriteLine($"Successfully parsed: {value}");
// If you really need to convert to LocalDateTime...
LocalDateTime local = value.LocalDateTime;
Console.WriteLine($"Local value: {local}");
}
else
{
Console.WriteLine($"Unable to parse value: {parseResult.Exception.Message}");
}

Related

Get DateTime from FileName

I have a file named test-2000_01_02-10_12_14.xml.
How do I only get the date from the file?
I was able to get the date if the file has this name: 2000_01_02-10_12_14
with this (b is a StorageFile):
DateTime dateVal;
bool parsed = DateTime.TryParseExact(b.DisplayName,
"yyyy_MM_dd-H_mm_ss",
System.Globalization.CultureInfo.InvariantCulture,
System.Globalization.DateTimeStyles.None,
out dateVal);
I then tried to change yyyy_MM_dd-H_mm_ss to something like this *-yyyy_MM-dd-H-mm_ss but it does not seem to be the solution
There are a boatload of ways to do this, it really rather depends on how regular the naming of your files is - is there always some junk text followed by a hyped, then the year?
Post up another 10 different examples if you want more tailored advice. Here's a way for the one you've posted:
DateTime.TryParseExact(
Path.GetFileNameWithoutExtension(b.DisplayName.Substring(b.DisplayName.IndexOf('-')+1)),
"yyyy_MM_dd-H_mm_ss",
System.Globalization.CultureInfo.InvariantCulture,
System.Globalization.DateTimeStyles.None,
out dateVal
);
This uses Substring with only one argument (no length) to remove everything after the first hyphen up to the end of the string, and GetFileNameWithoutExtension to remove the .xml - this effectively turns anythinghere-2000_01_01-00_00_00.xml into 2000_01_01-00_00_00 ready for parsing
I could also have gone for a .Remove("last index of period") type thing but it does get a bit messy because you have to subtract the start Index of the hyphen etc
MJWill's comment about splitting on hyphen is also a good one - you could split then take the [1] and [2] indexes and join then back together for parsing..
Lastly don't forget that the file itself might have a created date that is already a good candidate for the date of creation rather than the filename (which might be mangled by humans) so long as it hasn't been transmitted somewhere and re-saved. Take a look at the FileInfo.CreationTime property for that - https://learn.microsoft.com/en-us/dotnet/api/system.io.fileinfo?view=netframework-4.8
First, we have to extract (match) the datetime part from a file name:
using System.Text.RegularExpressions;
...
// Aggravated task: dots and minuses within file's name
string source = #"bla-bla-bla-test.me-2000_01_02-10_12_14.xml";
string datetime = Regex.Match(
Path.GetFileNameWithoutExtension(source),
"[0-9]{4}_[0-9]{2}_[0-9]{2}-[0-9]{2}_[0-9]{2}_[0-9]{2}$").Value;
Then we can parse it
if (DateTime.TryParseExact(
datetime,
"yyyy_MM_dd-H_m_s",
CultureInfo.InvariantCulture,
DateTimeStyles.AssumeLocal,
out DateTime result) {
// result is the parsed date
}
else {
// File doesn't contain valid date and time
}
I would suggest you to use regular expression assuming that your file name will be always following the same format you can do something like this:
var pattern = #"\d{4}_\d{2}_\d{2}-\d{2}_\d{2}_\d{2}";
var fileName = "test-2000_01_02-10_12_14.xml";
var match = new Regex(pattern);
var result = match.Match(fileName);
if (result.Success)
{
DateTime.TryParseExact(result.Value,
"yyyy_MM_dd-HH_mm_ss",
System.Globalization.CultureInfo.InvariantCulture,
System.Globalization.DateTimeStyles.None,
out DateTime dateVal);
}

How to format a string with a custom dynamic format

I know that string.Format and ToString() can apply formatting to a string,
In my case i have a string with the value (typically it will have a string representation of a data but can have string representations of other base datatypes) and i have another string that represents the desired format. These values are coming from a database, what i need is to apply one to the other
I'm not even sure this is possible at all, so any pointers are welcome. I haven't been able to apply any version of ToString or Format. because these require that you declare on the spot what format you want and mine are dynamic
Is there some formatting method like the tryParse (in the sense that it would try any possible formatting for the data it is given?
EDIT: some examples as requested:
stringInput = "Jan 31 2012"; //string representation of a date
inputFormat="dd/MM/yyyy, HH mm"
outputString = "31/Jan/2015, 00:00";
stringInput = "100"; //string representation of a number
inputFormat="D6"
outputString = "000100";
string.Format(string, string) takes 2 string arguments so you can take them from db and apply them directly:
string formatToApply = "{0} and some text and then the {1}";
string firstText = "Text";
string secondText = "finsh.";
// suppose that those strings are from db, not declared locally
var finalString = string.Format(formatToApply, firstText, secondText);
// finalString = "Text and some text and then the finish."
However, there is a great risk to have wrong number of specifiers or wrong number of arguments. If you have a call like this, it will throw an exception:
var finalString = string.Format(formatToApply, firstText);
//An unhandled exception of type 'System.FormatException' occurred in mscorlib.dll;
//Additional information: Index (zero based) must be greater than or
//equal to zero and less than the size of the argument list.
So wrap your call into a try/catch/ (maybe) finally to handle this situation accordingly to your needs.
Later Edit after desired examples were posted:
First example: you might want to take advantage of DateTime class from C# which knows to format its output values. So you need first to convert stringInput into a DateTime:
var inputDateTime = DateTime.Parse(stringInput);
var outputString = inputDateTime.ToString(inputFormat);
Second example: again, you might want to take advantage of Double class and conversion occurs again:
var inputDouble = Double.Parse(stringInput);
var outputString = inputDouble.ToString(inputFormat);
In summary of those two examples, you need to know the type of input string, type which you specified in your comments ("string representation of a date"). Knowing this you can take advantage of each specific class and its ability to format output strings. Otherwise it would be difficult to design yourself some kind of general formatter. A simple method might look like this:
public string GetFormattedString(string inputString, string inputFormat, string type)
{
switch (type)
{
case "double":
var inputDouble = Double.Parse(inputString);
return inputDouble.ToString(inputFormat);
break;
case "datetime":
var inputDateTime = DateTime.Parse(inputString);
return inputDateTime.ToString(inputFormat);
break;
case "...": // other types which you need to support
default: throw new ArgumentException("Type not supported: " + type);
}
}
This switch is only an idea of how the logic may occur but you will need to handle errors for Parse methods and for ToString methods and if you have many types to support is better to take advantage of some design patterns like Factory.

How can I parse out a date from string using a regular expression?

I am trying to parse out a DateTime from a string using a regular expression. My issue is that I have a list of strings which need to be sorted by their date in descending order. I want to find a regex that will get the date from the strings. They all look similar but I am not sure how to do it. All help is much appreciated.
This is what the string looks like:
sdfsad[10/16/2014 at 9:52 AM by AJOHNSON]sdfsadf
And I have a list that all have the same type of format.
This is the regex I have so far:
[0-9].[/][0-9].[0-9].*[at]
If all of your lines take this form:
sdfsad[10/16/2014 at 9:52 AM by AJOHNSON]sdfsadf
Then I would suggest using a regular expression to grab everything from the [ to the space before by, and then pass that string to DateTime.ParseExact or DateTime.TryParseExact.
The regex to extract that bit of text should be straightforward, and using the DateTime parser to get the date and time will be easier than trying to do it with a regular expression.
Use a regular expression to extract the components that interest you (date and time), create a datetime from these components and sort each line depending on the date time. you can use a temporary data class in order to help you create the structure you want
public class DataWithTimestamp
{
public string line {get;set;}
public DateTime stamp {get;set;}
public DataWithTimestamp(string data)
{
stamp = regex.extract(pattern); // not the correct syntax, set it here
line = data;
}
}
and in your code change your lines to the class, sort on the
var allLines = File.ReadAllLines("file.txt");
var sortedLines = allLines
.Select(s => new DataWithTimestamp(s))
.OrderBy(data => data.stamp)
.Select(data => data.line);
EDIT: this regex should work:
\[(?<date>[\d\/]+) at (?<time>[\d:]+).*\]
find the catpured groups date and time then ParseExact them into the correct DateTime

How can I format string values using a mask in a generic way?

Background: We have a system that receives data from another backend system. We handle the displaying of that data, and we have our own XML templates to control how certain things are displayed (i.e. we have our own column templates to dictate what the column headers are, etc.) One thing we would like to support is the ability to provide a mask for these column templates that would apply to the values coming from the backend. Below is a scenario that I'm having trouble with.
Problem: I can't seem to get a simple string format working. I'd like to format a STRING value of four digits (i.e. "1444") in a time format (i.e. "14:44"). I've tried:
String.Format("{0:00:00}", "1444")
Note the importance of the input being a STRING. If I supply an int value, the format will work. The reason I cannot use this is because all the data we receive from the backend is in string format, and we'd like for this to be generic (so casting isn't really an option).
By generic, I mean I'd like to specify a mask in our own XML templates, something like:
<MyColumnTemplate Id="MyColumn" Mask="00:00" />
and to use that mask in a string format call for string values? If the mask fails, we could just simply return the original value (as the String.Format() method already does by default).
Edit: To help clarify, here is a simplified version of what I'd like to be able to do in code:
string inputValue = "1444";
string maskValueFromXml = "00:00";
string mask = "{0:" + maskValueFromXml + "}";
string myDesiredEndResult = String.Format(mask, inputValue);
The thing is you are working string to string,since you ask for time and phone number they are all numbers then try this trick(if we can call it that :)):
string result = string.Format("{0:00:00}", int.Parse("1444"));
For phone number:
string result = string.Format("{0:000-000-0000}", int.Parse("1234560789"));
You can even place your desired masks in a dictionary for example and do this:
Dictionary<string, string> masks = new Dictionary<string, string>();
masks.Add("Phone", "{0:000-000-0000}");
masks.Add("Time", "{0:00:00}");
string test = "1234560789";
string result = string.Format(masks["Phone"], int.Parse(test));
Try with DateTime.TryParseExact, e.g:
DateTime dateEntered;
string input = "1444";
if (DateTime.TryParseExact(input, "HH:mm", System.Globalization.CultureInfo.CurrentCulture, System.Globalization.DateTimeStyles.None, out dateEntered))
{
MessageBox.Show(dateEntered.ToString());
}
else
{
MessageBox.Show("You need to enter valid 24hr time");
}
After that, you can use string.Format, predefined formats on MSDN.

parsing a string into int/long using custom format strings

In C#.Net, here's a simple example of how to format numbers into strings using custom format strings:
(example taken from: http://www.csharp-examples.net/string-format-int/)
String.Format("{0:+### ### ### ###}", 447900123456); // "+447 900 123 456"
String.Format("{0:##-####-####}", 8958712551); // "89-5871-2551"
Is there a way to convert this formatted string back into a long/integer ? Is there someway to do this :
long PhoneNumber = Int32.Parse("89-5871-2551", "{0:##-####-####}");
I saw that DateTime has a method ParseExact which can do this work well. But I did not see any such thing for int/long/decimal/double.
You can regex out all of the non numeric numbers, and what you're left with is a string of numbers that you can parse.
var myPhoneNumber = "89-5871-2551";
var strippedPhoneNumber = Regex.Replace(myPhoneNumber, #"[^\d]", "");
int intRepresentation;
if (Int32.TryParse(strippedPhoneNumber, out intRepresentation))
{
// It was assigned, intRepresentation = 8958712551
// now you can use intRepresentation.
} else {
// It was not assigned, intRepresentation is still null.
}
Well, you can always do
long PhoneNumber = Int32.Parse("89-5871-2551".
Replace(new char[]{'-','+',whatever..}).Trim());
By the way, considering that you're parsing a string received from some IO, I would suggest to use more secure (in terms of conversion) Int32.TryParse method.
The way like you described doesn't actually exist.
Just Regex out all of the non-numeric characters, then parse that string.

Categories