的strtotime相当于.NET [英] strtotime equivalent in .NET
问题描述
有PHP的的strtotime()
函数工作的.NET Framework等效。我说的是它的能力,处理字符串喜欢的:
Is there an equivalent of PHP's strtotime()
function working on .NET Framework. I'm talking about it's capacity to handle strings likes:
- 的strtotime(现在)
- 的strtotime(2000年9月10)
- 的strtotime(1天)
- 的strtotime(1周)
- 的strtotime(1周2天4小时2秒)
- 的strtotime(下周四)
- 的strtotime(上周一)
- strtotime("now")
- strtotime("10 September 2000")
- strtotime("+1 day")
- strtotime("+1 week")
- strtotime("+1 week 2 days 4 hours 2 seconds")
- strtotime("next Thursday")
- strtotime("last Monday")
显然 DateTime.Parse()
和 Convert.ToDateTime()
不这样做。
我发现的最接近的是一个小的类,它只处理那几个:的 HTTP://refactormy$c$c.com/$c$cs/488-parse-relative-date
The closest I've found is a small class which only handles a few of those: http://refactormycode.com/codes/488-parse-relative-date
编辑:我的没有的兴趣在C#编译时的功能。现在的问题是将人类相对日期/时间字符串到日期时间的在运行时(也就是现在 - > DateTime.Now等等)。
I'm not interested in C# compile-time features. The problem is converting human relative date/time strings to DateTime at runtime (i.e., "now" --> DateTime.Now and such).
推荐答案
由于至今没有答案,我把它根据给出的例子。它支持大多数情况下,除了那些像最后的Thurday(或一周中的其他天)。
As so far there is no answer, I made it based on the example given. It supports most cases except those like "last Thurday" (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's relative to now,
/// else it's 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 there are improvements possible but it should handle most cases in English. Please comment if you see improvements (like locale errors or such).
编辑:固定为相对于现在如果相对时间包括
Fixed to be relative to now if the relative time includes time.
这篇关于的strtotime相当于.NET的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!