TEIs class
The Is TE provides funcationality to test for equality of the various DateTime components such as Year, Month, etc. as a Temporal Expression at the resolution that makes sense for a particular data type. This is instantiated via individual data type constructors that are based on the requsted resolution.
class TEIs extends TExpression { DateTime _first; // The first DateTime that matches this TE DateTime _last; // The last DateTime that matches this TE int _teType; // Keeps track of the "type" of TE that we are tracking var _value; // Holds the value provided ot the constructor /// Returns the first DateTime that can be matched by a particular TE, or null if none exists. /// The first() method should used a cached value that is calculated at construction where possible in order to reduce the calculation overhead for other methods depending on it. /// TEIs year2013 = new TEIs.Year(2010); /// /// year2013.first(); // returns a Date Time for 01-Jan-2013 00:00:00 DateTime first() { return _first; } /// Returns the last DateTime that can be matched by a particular TE, or null if none exists. /// The last() method should used a cached value that is calculated at construction where possible in order to reduce the calculation overhead for other methods that depend on it. /// TEIs year2013 = new TEIs.Year(2010); /// /// year2013.last(); // returns a Date Time for 31-Dec-2013 23:59:999 DateTime last() { return _last; } /// Allow this class to be "stringified", this does not return the JSON string but does return a Map that can be stringified. /// This is so that the TE can be passed to the "Stringify" function in Dart core. /// TEIs year2013 = new TEIs.Yaer(2013); /// /// year2013.toJson(); // Returns a string that can be parsed by Dart core stringify() /// stringify(year2013); // Remember that stringify() will call toJson if required Map toJson() { if(_value is int) { return ({"TEMasterType": "TEIs", "TEType": _teType, "Value": _value}); } else if(_value is DateTime) { return({"TEMasterType": "TEIs", "TEType": _teType, "Value": {"TEMasterType":"DateTime", "Value": _value.millisecondsSinceEpoch}}); } } /// Create a TEIs object from a Map object that was created from the toJson method or manually (why?) /// Is a class factory calling other constructors to do the work. /// Throws an [InvalidJSONException] if the input format is not recognized. /// TEIs year2013 = new TEIs.Yaer(2013); /// /// year2013.toJson(); // Returns a string that can be parsed by Dart core stringify() /// TEIs fromJson2013 = new TEIs.fromJson(parse(stringify(year2013)); // Returns a duplicate TE to year2013 factory TEIs.fromJson(Map source) { var value = source["Value"]; TEIs result; if(value is Map) { value = new DateTime.fromMillisecondsSinceEpoch(value["Value"], isUtc: true); } switch(source["TEType"]) { case TExpression.YEAR: result = new TEIs.Year(value); break; case TExpression.MONTH: result = new TEIs.Month(value); break; case TExpression.DATETIME: result = new TEIs.DateTime(value); break; case TExpression.DAYOFWEEK: result = new TEIs.DayOfWeek(value); break; case TExpression.DAYOFMONTH: result = new TEIs.DayOfMonth(value); break; case TExpression.WEEKOFYEAR: result = new TEIs.WeekOfYear(value); break; case TExpression.DAYOFYEAR: result = new TEIs.DayOfYear(value); break; case TExpression.HOUR: result = new TEIs.Hour(value); break; case TExpression.MINUTE: result = new TEIs.Minute(value); break; case TExpression.SECOND: result = new TEIs.Second(value); break; case TExpression.MILLISECOND: result = new TEIs.Millisecond(value); break; case TExpression.DATE: result = new TEIs.Date(value); break; case TExpression.WEEKOFMONTH: result = new TEIs.WeekOfMonth(value); break; default: throw new InvalidJSONException("Invalid JSON Format: Not TEIs"); } return result; } /// Constructor to match all DateTimes in a specifically supplied year. /// Because we have a specific year, first() and last() will be able to return DateTimes, /// and not the null standard to many other methods. TEIs.Year(int year) { _first = new DateTime.utc(year,1,1,0,0,0,0); _last = new DateTime.utc(year + 1,1,1,0,0,0,-1); _teType = TExpression.YEAR; _value = year; } /// Constructor to match all DateTimes that occur in a given month, regardless of year. /// Because of the lack of year for this, first() and last() both return null TEIs.Month(int month) { _first = null; // first and last are null because year is undefined _last = null; _teType = TExpression.MONTH; _value = month; } /// Constructor to match all DateTimes that occur on a specific day of the week (Monday for example) regardless of Year, week, month, etc. /// Uses the DateTime constants (DateTime.MONDAY) to select /// The parameter is compatible with the DateTime constants (DateTime.MONDAY - DateTime.SUNDAY). TEIs.DayOfWeek(int day) { _first = null; // first and last are null because year, month, and week are undefined _last = null; _teType = TExpression.DAYOFWEEK; _value = day; } /// Constructor to match all DateTimes that occur on a specific day of every month (3rd of every month for example) regardless of year TEIs.DayOfMonth(int day) { _first = null; // first and last are null because year and month are undefined _last = null; _teType = TExpression.DAYOFMONTH; _value = day; } /// Constructor to match all DateTimes that occur on a specific day of every year (day 212 of every year) TEIs.DayOfYear(int day) { _first = null; // first and last are null because year is undefined _last = null; _teType = TExpression.DAYOFYEAR; _value = day; } /// Constructor to match all DateTimes that occur during a specific hour of every day. TEIs.Hour(int hour) { _first = null; // first and last are null because year is undefined _last = null; _teType = TExpression.HOUR; _value = hour; } /// Constructor to match all DateTimes that occur during a specific minute of every hour; TEIs.Minute(int minute) { _first = null; // first and last are null because year is undefined _last = null; _teType = TExpression.MINUTE; _value = minute; } /// Constructor to match all DateTimes that occur during a specific second of every minute; TEIs.Second(int second) { _first = null; // first and last are null because year is undefined _last = null; _teType = TExpression.SECOND; _value = second; } /// Constructor to match all DateTimes that occur during a specific millisecond of every second; TEIs.Millisecond(int millisecond) { _first = null; // first and last are null because year is undefined _last = null; _teType = TExpression.MILLISECOND; _value = millisecond; } /// Constructor to match all dateTimes that occur during a specific week of the year. TEIs.WeekOfYear(int week) { _first = null; // first and last are null because year is undefined _last = null; _teType = TExpression.WEEKOFYEAR; _value = week; } /// Constructor to match all DateTimes that occur exactly at given DateTime TEIs.DateTime(DateTime date) { _first = date; _last = date; _teType = TExpression.DATETIME; _value = date; } /// Constructor to match all DateTimes that occur on a specific day (ignoring supplied time parameters provided (if any) supplied in the DateTime TEIs.Date(DateTime date) { _first = new DateTime.utc(date.year, date.month, date.day, 0, 0, 0, 0); _last = new DateTime.utc(date.year, date.month, date.day + 1, 0, 0, 0, -1); _teType = TExpression.DATE; _value = date; } /// Constructor to match the week of a month. /// Positive values indicate a count starting from the beginning of the month /// Negative values indicate a count starting from the end of the month. /// A value of 0 will return false TEIs.WeekOfMonth(int week) { _first = null; _last = null; _teType = TExpression.WEEKOFMONTH; _value = week; } /// Test to see if an arbitrary testDate is a match for this TE bool includes(DateTime testDate) { bool result = false; switch(_teType) { case TExpression.YEAR: result = testDate.year == _value; break; case TExpression.MONTH: result = testDate.month == _value; break; case TExpression.DATETIME: result = testDate.isAtSameMomentAs(_value); break; case TExpression.DAYOFWEEK: result = testDate.weekday == _value; break; case TExpression.DAYOFMONTH: result = testDate.day == _value; break; case TExpression.WEEKOFYEAR: result = weekOfYear(testDate) == _value; break; case TExpression.DAYOFYEAR: result = dayOfYear(testDate) == _value; break; case TExpression.HOUR: result = testDate.hour == _value; break; case TExpression.MINUTE: result = testDate.minute == _value; break; case TExpression.SECOND: result = testDate.second == _value; break; case TExpression.MILLISECOND: result = testDate.millisecond == _value; break; case TExpression.DATE: result = (testDate.millisecondsSinceEpoch >= _first.millisecondsSinceEpoch) && (testDate.millisecondsSinceEpoch <= _last.millisecondsSinceEpoch); break; case TExpression.WEEKOFMONTH: result = false; int testWOM = weekOfMonth(testDate); if(_value >= 0) { result = _value == testWOM; } else { int maxWOM = maxWeekOfMonth(testDate); result = ((maxWOM + _value) + 1) == testWOM; } break; } return result; } }
Extends
TExpression > TEIs
Constructors
new TEIs.Date(DateTime date) #
Constructor to match all DateTimes that occur on a specific day (ignoring supplied time parameters provided (if any) supplied in the DateTime
TEIs.Date(DateTime date) { _first = new DateTime.utc(date.year, date.month, date.day, 0, 0, 0, 0); _last = new DateTime.utc(date.year, date.month, date.day + 1, 0, 0, 0, -1); _teType = TExpression.DATE; _value = date; }
new TEIs.DateTime(DateTime date) #
Constructor to match all DateTimes that occur exactly at given DateTime
TEIs.DateTime(DateTime date) { _first = date; _last = date; _teType = TExpression.DATETIME; _value = date; }
new TEIs.DayOfMonth(int day) #
Constructor to match all DateTimes that occur on a specific day of every month (3rd of every month for example) regardless of year
TEIs.DayOfMonth(int day) { _first = null; // first and last are null because year and month are undefined _last = null; _teType = TExpression.DAYOFMONTH; _value = day; }
new TEIs.DayOfWeek(int day) #
Constructor to match all DateTimes that occur on a specific day of the week (Monday for example) regardless of Year, week, month, etc. Uses the DateTime constants (DateTime.MONDAY) to select The parameter is compatible with the DateTime constants (DateTime.MONDAY - DateTime.SUNDAY).
TEIs.DayOfWeek(int day) { _first = null; // first and last are null because year, month, and week are undefined _last = null; _teType = TExpression.DAYOFWEEK; _value = day; }
new TEIs.DayOfYear(int day) #
Constructor to match all DateTimes that occur on a specific day of every year (day 212 of every year)
TEIs.DayOfYear(int day) { _first = null; // first and last are null because year is undefined _last = null; _teType = TExpression.DAYOFYEAR; _value = day; }
factory TEIs.fromJson(Map source) #
Create a TEIs object from a Map object that was created from the toJson method or manually (why?) Is a class factory calling other constructors to do the work. Throws an InvalidJSONException if the input format is not recognized.
TEIs year2013 = new TEIs.Yaer(2013);
year2013.toJson(); // Returns a string that can be parsed by Dart core stringify()
TEIs fromJson2013 = new TEIs.fromJson(parse(stringify(year2013)); // Returns a duplicate TE to year2013
factory TEIs.fromJson(Map source) { var value = source["Value"]; TEIs result; if(value is Map) { value = new DateTime.fromMillisecondsSinceEpoch(value["Value"], isUtc: true); } switch(source["TEType"]) { case TExpression.YEAR: result = new TEIs.Year(value); break; case TExpression.MONTH: result = new TEIs.Month(value); break; case TExpression.DATETIME: result = new TEIs.DateTime(value); break; case TExpression.DAYOFWEEK: result = new TEIs.DayOfWeek(value); break; case TExpression.DAYOFMONTH: result = new TEIs.DayOfMonth(value); break; case TExpression.WEEKOFYEAR: result = new TEIs.WeekOfYear(value); break; case TExpression.DAYOFYEAR: result = new TEIs.DayOfYear(value); break; case TExpression.HOUR: result = new TEIs.Hour(value); break; case TExpression.MINUTE: result = new TEIs.Minute(value); break; case TExpression.SECOND: result = new TEIs.Second(value); break; case TExpression.MILLISECOND: result = new TEIs.Millisecond(value); break; case TExpression.DATE: result = new TEIs.Date(value); break; case TExpression.WEEKOFMONTH: result = new TEIs.WeekOfMonth(value); break; default: throw new InvalidJSONException("Invalid JSON Format: Not TEIs"); } return result; }
new TEIs.Hour(int hour) #
Constructor to match all DateTimes that occur during a specific hour of every day.
TEIs.Hour(int hour) { _first = null; // first and last are null because year is undefined _last = null; _teType = TExpression.HOUR; _value = hour; }
new TEIs.Millisecond(int millisecond) #
Constructor to match all DateTimes that occur during a specific millisecond of every second;
TEIs.Millisecond(int millisecond) { _first = null; // first and last are null because year is undefined _last = null; _teType = TExpression.MILLISECOND; _value = millisecond; }
new TEIs.Minute(int minute) #
Constructor to match all DateTimes that occur during a specific minute of every hour;
TEIs.Minute(int minute) { _first = null; // first and last are null because year is undefined _last = null; _teType = TExpression.MINUTE; _value = minute; }
new TEIs.Month(int month) #
Constructor to match all DateTimes that occur in a given month, regardless of year. Because of the lack of year for this, first() and last() both return null
TEIs.Month(int month) { _first = null; // first and last are null because year is undefined _last = null; _teType = TExpression.MONTH; _value = month; }
new TEIs.Second(int second) #
Constructor to match all DateTimes that occur during a specific second of every minute;
TEIs.Second(int second) { _first = null; // first and last are null because year is undefined _last = null; _teType = TExpression.SECOND; _value = second; }
new TEIs.WeekOfMonth(int week) #
Constructor to match the week of a month. Positive values indicate a count starting from the beginning of the month Negative values indicate a count starting from the end of the month. A value of 0 will return false
TEIs.WeekOfMonth(int week) { _first = null; _last = null; _teType = TExpression.WEEKOFMONTH; _value = week; }
new TEIs.WeekOfYear(int week) #
Constructor to match all dateTimes that occur during a specific week of the year.
TEIs.WeekOfYear(int week) { _first = null; // first and last are null because year is undefined _last = null; _teType = TExpression.WEEKOFYEAR; _value = week; }
new TEIs.Year(int year) #
Constructor to match all DateTimes in a specifically supplied year. Because we have a specific year, first() and last() will be able to return DateTimes, and not the null standard to many other methods.
TEIs.Year(int year) { _first = new DateTime.utc(year,1,1,0,0,0,0); _last = new DateTime.utc(year + 1,1,1,0,0,0,-1); _teType = TExpression.YEAR; _value = year; }
Methods
Future<List<DateTime>> dates(DateTime baseDate, Duration interval, [int maxCount = 10, int maxIterations = 10000]) #
Returns the matching dates between the two dates defining the ranges
- Implemented as a Future which ultimately returns a List<DateTime> containing an ordered List of DateTime objects that meet the requirements
- The baseDate DateTime object is the point from which all future matches will be measured.
- The interval Duration is used to tell the method how much to increment each test by
- The optional maxCount parameter tells the method the maximum number of records to return (the method may return fewer, default 10)
- The maxIterations paramter sets the maximum number of attempts that the method will make to find the maxCount records requested. (default, 10000) if no matches are found before the maxIterations attempts expire.
Future<List<DateTime>> dates(DateTime baseDate, Duration interval, [int maxCount = 10, int maxIterations = 10000]) { Future<List<DateTime>> future = new Future(() { List<DateTime>response = new List<DateTime>(); bool complete = false; DateTime checkDate = baseDate; int results = maxCount; int iterations = maxIterations; while(complete == false) { // check to see if the check date is within scope if(_first != null) { if(checkDate.millisecondsSinceEpoch >= _first.millisecondsSinceEpoch) { // So now check to see if the date is included, if so, push to the results if(includes(checkDate)) { response.add(checkDate); results -= 1; } } } else { if(includes(checkDate)) { response.add(checkDate); results -= 1; } } checkDate = checkDate.add(interval); iterations -= 1; if(results <= 0 || iterations <= 0) { complete = true; } } return response; }); return future; }
int dayOfYear(DateTime date) #
Calculate what day of the year the provided DateTime sits on. This method handles leap year appropriately.
int dayOfYear(DateTime date) { int result = 0; int month = date.month; List<int> dayCounts = [0, 0,31,59,90,120,151,181,212,243,273,304,334]; result = dayCounts[month] + date.day; // This is to check to see if we need to add an extra day for leap year if(month > 2) { if(new DateTime(date.year, 3, 1, 0, 0, 0, -1).day == 29) { result += 1; } } return result; }
DateTime first() #
Returns the first DateTime that can be matched by a particular TE, or null if none exists. The first() method should used a cached value that is calculated at construction where possible in order to reduce the calculation overhead for other methods depending on it.
TEIs year2013 = new TEIs.Year(2010);
year2013.first(); // returns a Date Time for 01-Jan-2013 00:00:00
DateTime first() { return _first; }
bool includes(DateTime testDate) #
Test to see if an arbitrary testDate is a match for this TE
bool includes(DateTime testDate) { bool result = false; switch(_teType) { case TExpression.YEAR: result = testDate.year == _value; break; case TExpression.MONTH: result = testDate.month == _value; break; case TExpression.DATETIME: result = testDate.isAtSameMomentAs(_value); break; case TExpression.DAYOFWEEK: result = testDate.weekday == _value; break; case TExpression.DAYOFMONTH: result = testDate.day == _value; break; case TExpression.WEEKOFYEAR: result = weekOfYear(testDate) == _value; break; case TExpression.DAYOFYEAR: result = dayOfYear(testDate) == _value; break; case TExpression.HOUR: result = testDate.hour == _value; break; case TExpression.MINUTE: result = testDate.minute == _value; break; case TExpression.SECOND: result = testDate.second == _value; break; case TExpression.MILLISECOND: result = testDate.millisecond == _value; break; case TExpression.DATE: result = (testDate.millisecondsSinceEpoch >= _first.millisecondsSinceEpoch) && (testDate.millisecondsSinceEpoch <= _last.millisecondsSinceEpoch); break; case TExpression.WEEKOFMONTH: result = false; int testWOM = weekOfMonth(testDate); if(_value >= 0) { result = _value == testWOM; } else { int maxWOM = maxWeekOfMonth(testDate); result = ((maxWOM + _value) + 1) == testWOM; } break; } return result; }
DateTime last() #
Returns the last DateTime that can be matched by a particular TE, or null if none exists. The last() method should used a cached value that is calculated at construction where possible in order to reduce the calculation overhead for other methods that depend on it.
TEIs year2013 = new TEIs.Year(2010);
year2013.last(); // returns a Date Time for 31-Dec-2013 23:59:999
DateTime last() { return _last; }
int maxWeekOfMonth(DateTime date) #
Calculate the maximum week of the month that a date falls on Similar to weekOfMonth, this is a guess, there may be a more standard way to do thi It will always be between 1 and 6.
int maxWeekOfMonth(DateTime date) { DateTime monthStart = new DateTime(date.year, date.month, 1, 0, 0, 0, 0); DateTime lastDay = new DateTime(date.year, date.month + 1, 1, 0,0,0,-1); int lastWeek = weekOfYear(lastDay); int firstWeek = weekOfYear(monthStart); return (lastWeek - firstWeek + 1); }
Future<List<TEInRange>> openings(DateTime baseDate, Duration duration, Duration testResolution, Duration failResolution, Duration successResolution, [int maxCount = 10, int maxIterations = 10000]) #
This method is used to find available openings for scheduling events. A use case would be to find an opening for a two hour meeting on a calendar. This method takes several parameters that allow the programmer to control how the responses are calculated
- Implemented as a Future which ultimately returns a List of List<DateTime> containing an ordered List of start/end DateTime objects that meet the requirements
- The baseDate DateTime object is the point from which all future matches will be measured.
- The duration Duration is how long the gap we are looking for is.
- The testResolution is how frequently to test for collisions. This should be the smallest interval that can be scheduled.
- The failResolution is how for to space the next test if the current one fails.
- The successResolution is how far to space the next test once a hit is found. These allow us to ensure that we do not return 1000 ranges all starting 1ms apart.
- The optional maxCount parameter tells the method the maximum number of records to return (the method may return fewer, default 10)
- The maxIterations paramter sets the maximum number of attempts that the method will make to find the maxCount records requested. (default, 10000) if no matches are found before the maxIterations attempts expire.
Future<List<TEInRange>> openings(DateTime baseDate, Duration duration, Duration testResolution, Duration failResolution, Duration successResolution, [int maxCount = 10, int maxIterations = 10000]) { Future<List<TEInRange>> future = new Future(() { List<TEInRange> response = new List<TEInRange>(); bool complete = false; bool rangePass = true; DateTime startDate = baseDate; DateTime endDate = baseDate.add(duration); DateTime checkDate = baseDate; int results = maxCount; int iterations = maxIterations; // Keep going until the test is complete, it will end if: // * maxIterations limit is hit // * maxCount results are found // * The test start range is outside of the .first() .last() range. while(!complete) { iterations -= 1; checkDate = startDate; endDate = startDate.add(duration); rangePass = true; // See if the current range is passable while(rangePass && checkDate.isBefore(endDate)) { rangePass = includes(checkDate) ? true : false; checkDate = checkDate.add(testResolution); } if(rangePass) { response.add(new TEInRange.DateTime(startDate, startDate.add(duration))); startDate = startDate.add(successResolution); results -= 1; } else { startDate = startDate.add(failResolution); } // Here are the tests for completion if(results <= 0 || iterations <= 0 || startDate.millisecondsSinceEpoch > last().millisecondsSinceEpoch) { complete = true; } } return response; }); return future; }
Map toJson() #
Allow this class to be "stringified", this does not return the JSON string but does return a Map that can be stringified. This is so that the TE can be passed to the "Stringify" function in Dart core.
TEIs year2013 = new TEIs.Yaer(2013);
year2013.toJson(); // Returns a string that can be parsed by Dart core stringify()
stringify(year2013); // Remember that stringify() will call toJson if required
Map toJson() { if(_value is int) { return ({"TEMasterType": "TEIs", "TEType": _teType, "Value": _value}); } else if(_value is DateTime) { return({"TEMasterType": "TEIs", "TEType": _teType, "Value": {"TEMasterType":"DateTime", "Value": _value.millisecondsSinceEpoch}}); } }
int type() #
Return the type code for this TE, will be one of the above defined constants or -1 (TExpression.UNDEFINED) if not properly set.
int type() { return _teType; }
int weekOfMonth(DateTime date) #
Calculate the week of the month that a date falls on This is a wild guess as to the best way to calculate this It will always start at 1 and go as high as 6
int weekOfMonth(DateTime date) { DateTime monthStart = new DateTime(date.year, date.month, 1, 0, 0, 0, 0); int startWeek = weekOfYear(monthStart); int endWeek = weekOfYear(date); return (endWeek - startWeek + 1); }
int weekOfYear(DateTime date) #
Calculate what week of the year the provided DateTime is in, as defined in ISO8601. The Dart DateTime library is also based on ISO8601, as a result the following conventions apply: Weeks begin on MONDAY, not SUNDAY as in some calendar implementations The first week of the year is defined as that which includes January 4th. As a result, the first one to three days may be included in the last week of the previous year. If that is the case, this function returns that week as 0.
int weekOfYear(DateTime date) { int dowJan4 = new DateTime(date.year,1,4,0,0,0,0).weekday; return ((dowJan4 + dayOfYear(date) + 2) ~/ 7); }