Equivalent to strtotime in .NET.

Is there an equivalent to the PHP strtotime() function working in the .NET Framework. I am talking about this ability to process strings:

  • StrToTime (" Now ")
  • strtotime ("September 10, 2000")
  • strtotime (" +1 day ")
  • strtotime (" +1 week ")
  • strtotime (" +1 week 2 days 4 hours 2 seconds ")
  • strtotime (" next thursday ")
  • strtotime (" last monday ")

Obviously, DateTime.Parse() and Convert.ToDateTime() do not.

The closest I found a small class that processes only a few of them: http://refactormycode.com/codes/488-parse-relative-date

EDIT: I'm not interested in C # compilation functions. The problem is converting human relative date / time strings to DateTime at runtime (i.e., "Now" -> DateTime.Now, etc.).

+4
source share
6 answers

As there is no answer yet, I did this based on the above example. It supports most cases, with the exception of the "last day" (or other days of the week).

 /// <summary> /// Parse a date/time string. /// /// Can handle relative English-written date times like: /// - "-1 day": Yesterday /// - "+12 weeks": Today twelve weeks later /// - "1 seconds": One second later from now. /// - "5 days 1 hour ago" /// - "1 year 2 months 3 weeks 4 days 5 hours 6 minutes 7 seconds" /// - "today": This day at midnight. /// - "now": Right now (date and time). /// - "next week" /// - "last month" /// - "2010-12-31" /// - "01/01/2010 1:59 PM" /// - "23:59:58": Today at the given time. /// /// If the relative time includes hours, minutes or seconds, it relative to now, /// else it relative to today. /// </summary> internal class RelativeDateParser { private const string ValidUnits = "year|month|week|day|hour|minute|second"; /// <summary> /// Ex: "last year" /// </summary> private readonly Regex _basicRelativeRegex = new Regex(@"^(last|next) +(" + ValidUnits + ")$"); /// <summary> /// Ex: "+1 week" /// Ex: " 1week" /// </summary> private readonly Regex _simpleRelativeRegex = new Regex(@"^([+-]?\d+) *(" + ValidUnits + ")s?$"); /// <summary> /// Ex: "2 minutes" /// Ex: "3 months 5 days 1 hour ago" /// </summary> private readonly Regex _completeRelativeRegex = new Regex(@"^(?: *(\d) *(" + ValidUnits + ")s?)+( +ago)?$"); public DateTime Parse(string input) { // Remove the case and trim spaces. input = input.Trim().ToLower(); // Try common simple words like "yesterday". var result = TryParseCommonDateTime(input); if (result.HasValue) return result.Value; // Try common simple words like "last week". result = TryParseLastOrNextCommonDateTime(input); if (result.HasValue) return result.Value; // Try simple format like "+1 week". result = TryParseSimpleRelativeDateTime(input); if (result.HasValue) return result.Value; // Try first the full format like "1 day 2 hours 10 minutes ago". result = TryParseCompleteRelativeDateTime(input); if (result.HasValue) return result.Value; // Try parse fixed dates like "01/01/2000". return DateTime.Parse(input); } private static DateTime? TryParseCommonDateTime(string input) { switch (input) { case "now": return DateTime.Now; case "today": return DateTime.Today; case "tomorrow": return DateTime.Today.AddDays(1); case "yesterday": return DateTime.Today.AddDays(-1); default: return null; } } private DateTime? TryParseLastOrNextCommonDateTime(string input) { var match = _basicRelativeRegex.Match(input); if (!match.Success) return null; var unit = match.Groups[2].Value; var sign = string.Compare(match.Groups[1].Value, "next", true) == 0 ? 1 : -1; return AddOffset(unit, sign); } private DateTime? TryParseSimpleRelativeDateTime(string input) { var match = _simpleRelativeRegex.Match(input); if (!match.Success) return null; var delta = Convert.ToInt32(match.Groups[1].Value); var unit = match.Groups[2].Value; return AddOffset(unit, delta); } private DateTime? TryParseCompleteRelativeDateTime(string input) { var match = _completeRelativeRegex.Match(input); if (!match.Success) return null; var values = match.Groups[1].Captures; var units = match.Groups[2].Captures; var sign = match.Groups[3].Success ? -1 : 1; Debug.Assert(values.Count == units.Count); var dateTime = UnitIncludeTime(units) ? DateTime.Now : DateTime.Today; for (int i = 0; i < values.Count; ++i) { var value = sign*Convert.ToInt32(values[i].Value); var unit = units[i].Value; dateTime = AddOffset(unit, value, dateTime); } return dateTime; } /// <summary> /// Add/Remove years/days/hours... to a datetime. /// </summary> /// <param name="unit">Must be one of ValidUnits</param> /// <param name="value">Value in given unit to add to the datetime</param> /// <param name="dateTime">Relative datetime</param> /// <returns>Relative datetime</returns> private static DateTime AddOffset(string unit, int value, DateTime dateTime) { switch (unit) { case "year": return dateTime.AddYears(value); case "month": return dateTime.AddMonths(value); case "week": return dateTime.AddDays(value * 7); case "day": return dateTime.AddDays(value); case "hour": return dateTime.AddHours(value); case "minute": return dateTime.AddMinutes(value); case "second": return dateTime.AddSeconds(value); default: throw new Exception("Internal error: Unhandled relative date/time case."); } } /// <summary> /// Add/Remove years/days/hours... relative to today or now. /// </summary> /// <param name="unit">Must be one of ValidUnits</param> /// <param name="value">Value in given unit to add to the datetime</param> /// <returns>Relative datetime</returns> private static DateTime AddOffset(string unit, int value) { var now = UnitIncludesTime(unit) ? DateTime.Now : DateTime.Today; return AddOffset(unit, value, now); } private static bool UnitIncludeTime(CaptureCollection units) { foreach (Capture unit in units) if (UnitIncludesTime(unit.Value)) return true; return false; } private static bool UnitIncludesTime(string unit) { switch (unit) { case "hour": case "minute": case "second": return true; default: return false; } } } 

I'm sure improvements are possible, but it should handle most cases in English. Please comment if you see improvements (for example, locale errors or such).

EDIT: Corrected relatively relatively now if relative time includes time.

+7
source

The DateTime structure has several methods and properties to get what you need:

 DateTime.Now; DateTime.Parse("10 September 2000"); DateTime.Now.AddDays(1); DateTime.Now.AddDays(7); DateTime.Now.AddDays(9).AddHours(4).AddSeconds(2); // And so on 

If the functionality provided by the DateTime structure is not enough, I suggest checking out the time-node project (by Jon Skeet).

+2
source

I think you have to write your own method.

"now" is just DateTime.Now .

"+ 1 day" will be DateTime.Now.AddDays(1) , for example.

So, you need to parse the string that searches for this type of input, and then call the appropriate DateTime method. A passing case would be to pass the string through DateTime.Parse(String, IFormatProvider, DateTimeStyles) with different DateTimeStyles.

0
source
 DateTime date = new DateTime(10,10,2010) Response.Write(date.ToShortDateTimeString()); Response.Write(date.Year); date = DateTime.Now; 

etc.

0
source

I think this is the best way to write extension methods for DateTime to suit your needs.

It might be OSS, so the community can help you implement it.

0
source

I think the correct answer here is to use something like https://github.com/robertwilczynski/nChronic . It is a Ruby equivalent port and can parse a wide range of date formats, as indicated here: http://chronic.rubyforge.org/ in the Examples section (scroll down).

0
source

Source: https://habr.com/ru/post/1345100/


All Articles