Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

added past/future times from a base date

  • Loading branch information...
commit c4af74b0519daaaa10fff5f27192406c606b2c16 1 parent fea116c
@ChrisMissal authored
View
16 src/TempusReader/BaseLexer.cs
@@ -0,0 +1,16 @@
+using System.Linq;
+using Parsley;
+
+namespace TempusReader
+{
+ internal class BaseLexer : Lexer
+ {
+ public static readonly TokenKind Separator = new Pattern("separator", @",|(and)", skippable: true);
+ public static readonly TokenKind Whitespace = new Pattern("whitespace", @"\s+", skippable: true);
+ public static readonly TokenKind Number = new Pattern("number", @"(?=0(?!\d)|[1-9])\d+((\.|\:)\d+)?");
+
+ public BaseLexer(params TokenKind[] kinds) : base(new [] { Separator, Whitespace, Number}.Concat(kinds).ToArray())
+ {
+ }
+ }
+}
View
75 src/TempusReader/Date.cs
@@ -0,0 +1,75 @@
+using System;
+using System.Linq;
+using Parsley;
+
+namespace TempusReader
+{
+ public class Date : IEquatable<Date>, IComparable<Date>
+ {
+ private static readonly Lexer Lexer = new TimeLexer();
+ private DateTime _dateTime;
+
+ public Date(DateTime dateTime)
+ {
+ _dateTime = dateTime;
+ }
+
+ public Date(DateTime dateTime, string input)
+ {
+ var tokens = Lexer.Tokenize(input).ToArray();
+
+ var difference = DateGrammar.Time.Parse(new TokenStream(tokens)).Value;
+ _dateTime = dateTime.Add(difference);
+ }
+
+ public static implicit operator DateTime?(Date date)
+ {
+ return date == null ? default(DateTime?) : date._dateTime;
+ }
+
+ public static implicit operator DateTime(Date date)
+ {
+ return date == null ? default(DateTime) : date._dateTime;
+ }
+
+ public bool Equals(Date other)
+ {
+ if (ReferenceEquals(null, other)) return false;
+ if (ReferenceEquals(this, other)) return true;
+ return other._dateTime.Equals(_dateTime);
+ }
+
+ public int CompareTo(Date other)
+ {
+ return _dateTime.CompareTo(other._dateTime);
+ }
+
+ public override string ToString()
+ {
+ return _dateTime.ToString();
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (ReferenceEquals(null, obj)) return false;
+ if (ReferenceEquals(this, obj)) return true;
+ if (obj.GetType() != typeof (Date)) return false;
+ return Equals((Date)obj);
+ }
+
+ public override int GetHashCode()
+ {
+ return _dateTime.GetHashCode();
+ }
+
+ public static bool operator ==(Date left, Date right)
+ {
+ return Equals(left, right);
+ }
+
+ public static bool operator !=(Date left, Date right)
+ {
+ return !Equals(left, right);
+ }
+ }
+}
View
26 src/TempusReader/DateGrammar.cs
@@ -0,0 +1,26 @@
+using Parsley;
+
+namespace TempusReader
+{
+ internal class DateGrammar : Grammar
+ {
+ private static readonly GrammarRule<Time> TimePrefix = new GrammarRule<Time>();
+ private static readonly GrammarRule<Time> TimeSuffix = new GrammarRule<Time>();
+ public static readonly GrammarRule<Time> Time = new GrammarRule<Time>();
+
+ static DateGrammar()
+ {
+ TimePrefix.Rule = from prefix in Choice(Token(TimeLexer.InTime))
+ from timeSpan in TimeGrammar.TimeSpan
+ select new Time(timeSpan);
+
+ TimeSuffix.Rule = from timeSpan in TimeGrammar.TimeSpan
+ from suffix in Choice(Token(TimeLexer.FromNowTime), Token(TimeLexer.AgoTime))
+ let adjusted = suffix.Kind.Name == "past" ? timeSpan.Negate() : timeSpan
+ select new Time(adjusted);
+
+ Time.Rule = from futures in Choice(TimePrefix, TimeSuffix)
+ select futures;
+ }
+ }
+}
View
17 src/TempusReader/DateLexer.cs
@@ -0,0 +1,17 @@
+using Parsley;
+
+namespace TempusReader
+{
+ /*internal class DateLexer : BaseLexer
+ {
+ public const string InTimePattern = @"in";
+ public const string FromNowTimePattern = @"from now";
+
+ public DateLexer() : base(InTime, FromNowTime)
+ {
+ }
+
+ public static Pattern InTime = new Pattern("future", InTimePattern);
+ public static Pattern FromNowTime = new Pattern("future", FromNowTimePattern);
+ }*/
+}
View
4 src/TempusReader/TempusReader.csproj
@@ -39,6 +39,10 @@
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
<ItemGroup>
+ <Compile Include="BaseLexer.cs" />
+ <Compile Include="Date.cs" />
+ <Compile Include="DateGrammar.cs" />
+ <Compile Include="DateLexer.cs" />
<Compile Include="Extensions.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Time.cs" />
View
2  src/TempusReader/Time.cs
@@ -38,7 +38,7 @@ public Time(string input)
public int CompareTo(Time other)
{
- return _timeSpan.CompareTo(other);
+ return _timeSpan.CompareTo(other._timeSpan);
}
public override string ToString()
View
4 src/TempusReader/TimeGrammar.cs
@@ -17,9 +17,9 @@ internal class TimeGrammar : Grammar
static TimeGrammar()
{
- Break.Rule = ZeroOrMore(Token(TimeLexer.Separator), Token(TimeLexer.Whitespace));
+ Break.Rule = ZeroOrMore(Token(BaseLexer.Separator), Token(BaseLexer.Whitespace));
- Amount.Rule = from number in Token(TimeLexer.Number)
+ Amount.Rule = from number in Token(BaseLexer.Number)
select ParseAmount(number);
TimeFrame.Rule = Choice(
View
15 src/TempusReader/TimeLexer.cs
@@ -2,27 +2,28 @@
namespace TempusReader
{
- internal class TimeLexer : Lexer
+ internal class TimeLexer : BaseLexer
{
public const string DaysPattern = @"(days|day|d)";
public const string HoursPattern = @"(hours|hour|hrs|hr)";
public const string MinutesPattern = @"(minutes|minute|mins|min|m)";
public const string SecondsPattern = @"(seconds|second|sec|s)";
public const string MillisecondsPattern = @"(milliseconds|ms)";
+ public const string InTimePattern = @"in";
+ public const string FromNowTimePattern = @"from(\s+)now";
+ public const string AgoTimePattern = @"ago";
- public TimeLexer() : base(Number, Milliseconds, Seconds, Minutes, Hours, Days, Separator, Whitespace)
+ public TimeLexer() : base(Milliseconds, Seconds, Minutes, Hours, Days, InTime, FromNowTime, AgoTime)
{
}
- public static readonly TokenKind Separator = new Pattern("separator", @",|(and)", skippable: true);
- public static readonly TokenKind Whitespace = new Pattern("whitespace", @"\s+", skippable: true);
-
- public static readonly TokenKind Number = new Pattern("number", @"(?=0(?!\d)|[1-9])\d+((\.|\:)\d+)?");
-
public static readonly Pattern Milliseconds = new Pattern("milliseconds", MillisecondsPattern);
public static readonly Pattern Seconds = new Pattern("seconds", SecondsPattern);
public static readonly Pattern Minutes = new Pattern("minutes", MinutesPattern);
public static readonly Pattern Hours = new Pattern("hours", HoursPattern);
public static readonly Pattern Days = new Pattern("days", DaysPattern);
+ public static readonly Pattern InTime = new Pattern("future", InTimePattern);
+ public static readonly Pattern FromNowTime = new Pattern("future", FromNowTimePattern);
+ public static readonly Pattern AgoTime = new Pattern("past", AgoTimePattern);
}
}
View
39 src/Tests/DateTests.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections;
+using NUnit.Framework;
+using TempusReader;
+using Shouldly;
+
+namespace Tests
+{
+ [TestFixture]
+ public class DateTests
+ {
+ private DateTime BaseDate { get; set; }
+
+ [TestFixtureSetUp]
+ public void TestFixtureSetUp()
+ {
+ BaseDate = new DateTime(1982, 10, 21, 23, 40, 0);
+ }
+
+ [TestCaseSource("RelativeTimeTestData")]
+ public Date Date_from_string(string input)
+ {
+ return new Date(BaseDate, input);
+ }
+
+ public IEnumerable RelativeTimeTestData
+ {
+ get
+ {
+ yield return new TestCaseData("in 10 minutes")
+ .Returns(new Date(new DateTime(1982, 10, 21, 23, 50, 0)));
+ yield return new TestCaseData("4 hrs from now")
+ .Returns(new Date(new DateTime(1982, 10, 22, 3, 40, 0)));
+ yield return new TestCaseData("45 seconds ago")
+ .Returns(new Date(new DateTime(1982, 10, 21, 23, 39, 15)));
+ }
+ }
+ }
+}
View
1  src/Tests/Tests.csproj
@@ -42,6 +42,7 @@
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
<ItemGroup>
+ <Compile Include="DateTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TimeTests.cs" />
</ItemGroup>
Please sign in to comment.
Something went wrong with that request. Please try again.