I am having relative datetime
string like:
- "5 minutes ago"
- "10 hours ago"
- "3 days ago" etc.
How can I convert this to exact datetime
, as exactly opposite of this question
I am having relative datetime
string like:
How can I convert this to exact datetime
, as exactly opposite of this question
You will need to write your own routines to do so, just like the people doing the opposite had to do.
Essentially, you will need to parse the text to find the interval (i.e. minutes, hours, days etc...), the amount and whether it is in the past or future (using ago
or from
).
At this point you will have enough data to construct an appropriate TimeSpan
instance and use it with DateTime.Now
to get that time.
In order fro the above to work, you will need to ensure that the string values to parse are standardized.
This code should work:
string input = "10 days ago";
DateTime result = DateTime.MinValue;
int minutesMultiplier = 0;
if (input.Contains("minute"))
minutesMultiplier = 1;
else
if (input.Contains("hour"))
minutesMultiplier = 60;
else
if (input.Contains("day"))
minutesMultiplier = 1440;
else
throw new Exception("Couldn't parse time format");
string numberStr = input.Split(' ')[0];
int number;
if (int.TryParse(numberStr, out number))
result = DateTime.Now.AddMinutes(-number * minutesMultiplier);
It does the parsing of an interval name (such as minute, hour, day) and multiplies them to get the number of minutes because later on it uses DateTime.Now.AddMinutes
method, same thing could be done using TimeSpan
and calling DateTime.Now.Add
.
Here is one more example that handles case of a string that contains more than one interval name, such as "10 hours and 15 minutes ago":
// If there are mixed interval types in an input string
string input = "10 days and 10 hours ago";
// Parse out the intervals and numbers
var matches = Regex.Matches(input,
@"(?<number>\d+)\s(?<interval>(day)|(minute)|(hour))");
// Convert them to dictionary
var dic = matches
.Cast<Match>()
.ToDictionary(
key => key.Groups["interval"].Value,
o => int.Parse(o.Groups["number"].Value));
// Calculate the total number of minutes for each interval
DateTime result = DateTime.MinValue;
int totalMinutes = 0;
foreach (var keyValue in dic)
{
if (keyValue.Key.Contains("minute"))
totalMinutes += keyValue.Value;
else
if (keyValue.Key.Contains("hour"))
totalMinutes += keyValue.Value * 60;
else
if (keyValue.Key.Contains("day"))
totalMinutes += keyValue.Value * 1440;
else
throw new Exception("Unparsable time format");
}
result = DateTime.Now.AddMinutes(-totalMinutes);
The proper way would be storing your relative value as a TimeSpan
value and subtracting that from DateTime.Now
(or from whatever DateTime
you want to use as a base).
You can use methods such as int.Parse
in order to convert the numbers (the number of minutes, hours etc. ago) into integer values and copy those into your TimeSpan
value. The exact parsing algorithm depends on the actual format of your strings, i.e. what words are allowed in there, and in what order the numbers may appear.
If the strings are already isolated as shown in your question, you can try and disassemble them using a regular expression (with the Regex
class):
^(\d+)\s+([a-z]+)\s+ago$