diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/CalcEngine/Expression.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/CalcEngine/Expression.cs index cea5599..485e1b0 100644 --- a/ClosedXML/ClosedXML/ClosedXML/Excel/CalcEngine/Expression.cs +++ b/ClosedXML/ClosedXML/ClosedXML/Excel/CalcEngine/Expression.cs @@ -9,498 +9,498 @@ namespace ClosedXML.Excel.CalcEngine { - /// + /// /// Base class that represents parsed expressions. /// - /// - /// For example: - /// - /// Expression expr = scriptEngine.Parse(strExpression); - /// object val = expr.Evaluate(); - /// - /// - internal class Expression : IComparable + /// + /// For example: + /// + /// Expression expr = scriptEngine.Parse(strExpression); + /// object val = expr.Evaluate(); + /// + /// + internal class Expression : IComparable { - //--------------------------------------------------------------------------- - #region ** fields + //--------------------------------------------------------------------------- + #region ** fields - internal Token _token; - static CultureInfo _ci = CultureInfo.InvariantCulture; + internal Token _token; + static CultureInfo _ci = CultureInfo.InvariantCulture; - #endregion + #endregion - //--------------------------------------------------------------------------- - #region ** ctors + //--------------------------------------------------------------------------- + #region ** ctors - internal Expression() + internal Expression() { - _token = new Token(null, TKID.ATOM, TKTYPE.IDENTIFIER); + _token = new Token(null, TKID.ATOM, TKTYPE.IDENTIFIER); } - internal Expression(object value) - { - _token = new Token(value, TKID.ATOM, TKTYPE.LITERAL); - } - internal Expression(Token tk) - { - _token = tk; - } + internal Expression(object value) + { + _token = new Token(value, TKID.ATOM, TKTYPE.LITERAL); + } + internal Expression(Token tk) + { + _token = tk; + } - #endregion + #endregion - //--------------------------------------------------------------------------- - #region ** object model + //--------------------------------------------------------------------------- + #region ** object model public virtual object Evaluate() { - if (_token.Type != TKTYPE.LITERAL) - { - throw new ArgumentException("Bad expression."); - } + if (_token.Type != TKTYPE.LITERAL) + { + throw new ArgumentException("Bad expression."); + } return _token.Value; } - public virtual Expression Optimize() - { - return this; - } + public virtual Expression Optimize() + { + return this; + } - #endregion + #endregion - //--------------------------------------------------------------------------- - #region ** implicit converters + //--------------------------------------------------------------------------- + #region ** implicit converters - public static implicit operator string(Expression x) - { - var v = x.Evaluate(); - return v == null ? string.Empty : v.ToString(); - } - public static implicit operator double(Expression x) - { - // evaluate - var v = x.Evaluate(); + public static implicit operator string(Expression x) + { + var v = x.Evaluate(); + return v == null ? string.Empty : v.ToString(); + } + public static implicit operator double(Expression x) + { + // evaluate + var v = x.Evaluate(); - // handle doubles - if (v is double) - { - return (double)v; - } + // handle doubles + if (v is double) + { + return (double)v; + } - // handle booleans - if (v is bool) - { - return (bool)v ? 1 : 0; - } + // handle booleans + if (v is bool) + { + return (bool)v ? 1 : 0; + } - // handle dates - if (v is DateTime) - { - return ((DateTime)v).ToOADate(); - } + // handle dates + if (v is DateTime) + { + return ((DateTime)v).ToOADate(); + } - // handle nulls - if (v == null) - { - return 0; - } + // handle nulls + if (v == null) + { + return 0; + } - // handle everything else - return (double)Convert.ChangeType(v, typeof(double), _ci); - } - public static implicit operator bool(Expression x) - { - // evaluate - var v = x.Evaluate(); + // handle everything else + return (double)Convert.ChangeType(v, typeof(double), _ci); + } + public static implicit operator bool(Expression x) + { + // evaluate + var v = x.Evaluate(); - // handle booleans - if (v is bool) - { - return (bool)v; - } + // handle booleans + if (v is bool) + { + return (bool)v; + } - // handle nulls - if (v == null) - { - return false; - } + // handle nulls + if (v == null) + { + return false; + } - // handle doubles - if (v is double) - { - return (double)v == 0 ? false : true; - } + // handle doubles + if (v is double) + { + return (double)v == 0 ? false : true; + } - // handle everything else - return (double)x == 0 ? false : true; - } - public static implicit operator DateTime(Expression x) - { - // evaluate - var v = x.Evaluate(); + // handle everything else + return (double)x == 0 ? false : true; + } + public static implicit operator DateTime(Expression x) + { + // evaluate + var v = x.Evaluate(); - // handle dates - if (v is DateTime) - { - return (DateTime)v; - } + // handle dates + if (v is DateTime) + { + return (DateTime)v; + } - // handle doubles - if (v is double) - { - return DateTime.FromOADate((double)x); - } + // handle doubles + if (v is double) + { + return DateTime.FromOADate((double)x); + } - // handle everything else - return (DateTime)Convert.ChangeType(v, typeof(DateTime), _ci); - } + // handle everything else + return (DateTime)Convert.ChangeType(v, typeof(DateTime), _ci); + } - #endregion + #endregion - //--------------------------------------------------------------------------- - #region ** IComparable + //--------------------------------------------------------------------------- + #region ** IComparable - public int CompareTo(Expression other) - { - // get both values - var c1 = this.Evaluate() as IComparable; - var c2 = other.Evaluate() as IComparable; + public int CompareTo(Expression other) + { + // get both values + var c1 = this.Evaluate() as IComparable; + var c2 = other.Evaluate() as IComparable; - // handle nulls - if (c1 == null && c2 == null) - { - return 0; - } - if (c2 == null) - { - return -1; - } - if (c1 == null) - { - return +1; - } + // handle nulls + if (c1 == null && c2 == null) + { + return 0; + } + if (c2 == null) + { + return -1; + } + if (c1 == null) + { + return +1; + } - // make sure types are the same - if (c1.GetType() != c2.GetType()) - { - c2 = Convert.ChangeType(c2, c1.GetType()) as IComparable; - } + // make sure types are the same + if (c1.GetType() != c2.GetType()) + { + c2 = Convert.ChangeType(c2, c1.GetType()) as IComparable; + } - // compare - return c1.CompareTo(c2); - } + // compare + return c1.CompareTo(c2); + } - #endregion - } - /// - /// Unary expression, e.g. +123 - /// + #endregion + } + /// + /// Unary expression, e.g. +123 + /// class UnaryExpression : Expression { - // ** fields + // ** fields Expression _expr; - // ** ctor + // ** ctor public UnaryExpression(Token tk, Expression expr) : base(tk) { _expr = expr; } - // ** object model + // ** object model override public object Evaluate() { - switch (_token.ID) + switch (_token.ID) { case TKID.ADD: - return +(double)_expr; + return +(double)_expr; case TKID.SUB: - return -(double)_expr; + return -(double)_expr; } throw new ArgumentException("Bad expression."); } - public override Expression Optimize() - { - _expr = _expr.Optimize(); - return _expr._token.Type == TKTYPE.LITERAL - ? new Expression(this.Evaluate()) - : this; - } + public override Expression Optimize() + { + _expr = _expr.Optimize(); + return _expr._token.Type == TKTYPE.LITERAL + ? new Expression(this.Evaluate()) + : this; + } } - /// - /// Binary expression, e.g. 1+2 - /// + /// + /// Binary expression, e.g. 1+2 + /// class BinaryExpression : Expression { - // ** fields + // ** fields Expression _lft; Expression _rgt; - // ** ctor + // ** ctor public BinaryExpression(Token tk, Expression exprLeft, Expression exprRight) : base(tk) { _lft = exprLeft; _rgt = exprRight; } - // ** object model + // ** object model override public object Evaluate() { // handle comparisons - if (_token.Type == TKTYPE.COMPARE) - { - var cmp = _lft.CompareTo(_rgt); - switch (_token.ID) - { - case TKID.GT: return cmp > 0; - case TKID.LT: return cmp < 0; - case TKID.GE: return cmp >= 0; - case TKID.LE: return cmp <= 0; - case TKID.EQ: return cmp == 0; - case TKID.NE: return cmp != 0; - } - } - - // handle everything else - switch (_token.ID) + if (_token.Type == TKTYPE.COMPARE) { - case TKID.CONCAT: - return (string)_lft + (string)_rgt; + var cmp = _lft.CompareTo(_rgt); + switch (_token.ID) + { + case TKID.GT: return cmp > 0; + case TKID.LT: return cmp < 0; + case TKID.GE: return cmp >= 0; + case TKID.LE: return cmp <= 0; + case TKID.EQ: return cmp == 0; + case TKID.NE: return cmp != 0; + } + } + + // handle everything else + switch (_token.ID) + { + case TKID.CONCAT: + return (string)_lft + (string)_rgt; case TKID.ADD: - return (double)_lft + (double)_rgt; + return (double)_lft + (double)_rgt; case TKID.SUB: - return (double)_lft - (double)_rgt; + return (double)_lft - (double)_rgt; case TKID.MUL: - return (double)_lft * (double)_rgt; + return (double)_lft * (double)_rgt; case TKID.DIV: - return (double)_lft / (double)_rgt; + return (double)_lft / (double)_rgt; case TKID.DIVINT: - return (double)(int)((double)_lft / (double)_rgt); + return (double)(int)((double)_lft / (double)_rgt); case TKID.MOD: - return (double)(int)((double)_lft % (double)_rgt); + return (double)(int)((double)_lft % (double)_rgt); case TKID.POWER: - var a = (double)_lft; - var b = (double)_rgt; - if (b == 0.0) return 1.0; - if (b == 0.5) return Math.Sqrt(a); - if (b == 1.0) return a; - if (b == 2.0) return a * a; - if (b == 3.0) return a * a * a; - if (b == 4.0) return a * a * a * a; - return Math.Pow((double)_lft, (double)_rgt); + var a = (double)_lft; + var b = (double)_rgt; + if (b == 0.0) return 1.0; + if (b == 0.5) return Math.Sqrt(a); + if (b == 1.0) return a; + if (b == 2.0) return a * a; + if (b == 3.0) return a * a * a; + if (b == 4.0) return a * a * a * a; + return Math.Pow((double)_lft, (double)_rgt); } throw new ArgumentException("Bad expression."); } - public override Expression Optimize() - { - _lft = _lft.Optimize(); - _rgt = _rgt.Optimize(); - return _lft._token.Type == TKTYPE.LITERAL && _rgt._token.Type == TKTYPE.LITERAL - ? new Expression(this.Evaluate()) - : this; - } - } - /// - /// Function call expression, e.g. sin(0.5) - /// - class FunctionExpression : Expression - { - // ** fields - FunctionDefinition _fn; - List _parms; + public override Expression Optimize() + { + _lft = _lft.Optimize(); + _rgt = _rgt.Optimize(); + return _lft._token.Type == TKTYPE.LITERAL && _rgt._token.Type == TKTYPE.LITERAL + ? new Expression(this.Evaluate()) + : this; + } + } + /// + /// Function call expression, e.g. sin(0.5) + /// + class FunctionExpression : Expression + { + // ** fields + FunctionDefinition _fn; + List _parms; - // ** ctor - internal FunctionExpression() - { - } - public FunctionExpression(FunctionDefinition function, List parms) - { - _fn = function; - _parms = parms; - } + // ** ctor + internal FunctionExpression() + { + } + public FunctionExpression(FunctionDefinition function, List parms) + { + _fn = function; + _parms = parms; + } - // ** object model - override public object Evaluate() - { - return _fn.Function(_parms); - } - public override Expression Optimize() - { - bool allLits = true; - if (_parms != null) - { - for (int i = 0; i < _parms.Count; i++) - { - var p = _parms[i].Optimize(); - _parms[i] = p; - if (p._token.Type != TKTYPE.LITERAL) - { - allLits = false; - } - } - } - return allLits - ? new Expression(this.Evaluate()) - : this; - } - } - /// - /// Simple variable reference. - /// - class VariableExpression : Expression - { - Dictionary _dct; - string _name; + // ** object model + override public object Evaluate() + { + return _fn.Function(_parms); + } + public override Expression Optimize() + { + bool allLits = true; + if (_parms != null) + { + for (int i = 0; i < _parms.Count; i++) + { + var p = _parms[i].Optimize(); + _parms[i] = p; + if (p._token.Type != TKTYPE.LITERAL) + { + allLits = false; + } + } + } + return allLits + ? new Expression(this.Evaluate()) + : this; + } + } + /// + /// Simple variable reference. + /// + class VariableExpression : Expression + { + Dictionary _dct; + string _name; - public VariableExpression(Dictionary dct, string name) - { - _dct = dct; - _name = name; - } - public override object Evaluate() - { - return _dct[_name]; - } - } - /// - /// Expression based on an object's properties. - /// - class BindingExpression : Expression - { - CalcEngine _ce; - CultureInfo _ci; - List _bindingPath; + public VariableExpression(Dictionary dct, string name) + { + _dct = dct; + _name = name; + } + public override object Evaluate() + { + return _dct[_name]; + } + } + /// + /// Expression based on an object's properties. + /// + class BindingExpression : Expression + { + CalcEngine _ce; + CultureInfo _ci; + List _bindingPath; - // ** ctor - internal BindingExpression(CalcEngine engine, List bindingPath, CultureInfo ci) - { - _ce = engine; - _bindingPath = bindingPath; - _ci = ci; - } + // ** ctor + internal BindingExpression(CalcEngine engine, List bindingPath, CultureInfo ci) + { + _ce = engine; + _bindingPath = bindingPath; + _ci = ci; + } - // ** object model - override public object Evaluate() - { - return GetValue(_ce.DataContext); - } + // ** object model + override public object Evaluate() + { + return GetValue(_ce.DataContext); + } - // ** implementation - object GetValue(object obj) - { - const BindingFlags bf = - BindingFlags.IgnoreCase | - BindingFlags.Instance | - BindingFlags.Public | - BindingFlags.Static; + // ** implementation + object GetValue(object obj) + { + const BindingFlags bf = + BindingFlags.IgnoreCase | + BindingFlags.Instance | + BindingFlags.Public | + BindingFlags.Static; - if (obj != null) - { - foreach (var bi in _bindingPath) - { - // get property - if (bi.PropertyInfo == null) - { - bi.PropertyInfo = obj.GetType().GetProperty(bi.Name, bf); - } + if (obj != null) + { + foreach (var bi in _bindingPath) + { + // get property + if (bi.PropertyInfo == null) + { + bi.PropertyInfo = obj.GetType().GetProperty(bi.Name, bf); + } - // get object - try - { - obj = bi.PropertyInfo.GetValue(obj, null); - } - catch - { - // REVIEW: is this needed? - System.Diagnostics.Debug.Assert(false, "shouldn't happen!"); - bi.PropertyInfo = obj.GetType().GetProperty(bi.Name, bf); - bi.PropertyInfoItem = null; - obj = bi.PropertyInfo.GetValue(obj, null); - } + // get object + try + { + obj = bi.PropertyInfo.GetValue(obj, null); + } + catch + { + // REVIEW: is this needed? + System.Diagnostics.Debug.Assert(false, "shouldn't happen!"); + bi.PropertyInfo = obj.GetType().GetProperty(bi.Name, bf); + bi.PropertyInfoItem = null; + obj = bi.PropertyInfo.GetValue(obj, null); + } - // handle indexers (lists and dictionaries) - if (bi.Parms != null && bi.Parms.Count > 0) - { - // get indexer property (always called "Item") - if (bi.PropertyInfoItem == null) - { - bi.PropertyInfoItem = obj.GetType().GetProperty("Item", bf); - } + // handle indexers (lists and dictionaries) + if (bi.Parms != null && bi.Parms.Count > 0) + { + // get indexer property (always called "Item") + if (bi.PropertyInfoItem == null) + { + bi.PropertyInfoItem = obj.GetType().GetProperty("Item", bf); + } - // get indexer parameters - var pip = bi.PropertyInfoItem.GetIndexParameters(); - var list = new List(); - for (int i = 0; i < pip.Length; i++) - { - var pv = bi.Parms[i].Evaluate(); - pv = Convert.ChangeType(pv, pip[i].ParameterType, _ci); - list.Add(pv); - } + // get indexer parameters + var pip = bi.PropertyInfoItem.GetIndexParameters(); + var list = new List(); + for (int i = 0; i < pip.Length; i++) + { + var pv = bi.Parms[i].Evaluate(); + pv = Convert.ChangeType(pv, pip[i].ParameterType, _ci); + list.Add(pv); + } - // get value - obj = bi.PropertyInfoItem.GetValue(obj, list.ToArray()); - } - } - } + // get value + obj = bi.PropertyInfoItem.GetValue(obj, list.ToArray()); + } + } + } - // all done - return obj; - } - } - /// - /// Helper used for building BindingExpression objects. - /// - class BindingInfo - { - public BindingInfo(string member, List parms) - { - Name = member; - Parms = parms; - } - public string Name { get; set; } - public PropertyInfo PropertyInfo { get; set; } - public PropertyInfo PropertyInfoItem { get; set; } - public List Parms { get; set; } - } - /// - /// Expression that represents an external object. - /// - class XObjectExpression : - Expression, - IEnumerable - { - object _value; + // all done + return obj; + } + } + /// + /// Helper used for building BindingExpression objects. + /// + class BindingInfo + { + public BindingInfo(string member, List parms) + { + Name = member; + Parms = parms; + } + public string Name { get; set; } + public PropertyInfo PropertyInfo { get; set; } + public PropertyInfo PropertyInfoItem { get; set; } + public List Parms { get; set; } + } + /// + /// Expression that represents an external object. + /// + class XObjectExpression : + Expression, + IEnumerable + { + object _value; - // ** ctor - internal XObjectExpression(object value) - { - _value = value; - } + // ** ctor + internal XObjectExpression(object value) + { + _value = value; + } - public object Value { get { return _value; } } + public object Value { get { return _value; } } - // ** object model - public override object Evaluate() - { - // use IValueObject if available - var iv = _value as IValueObject; - if (iv != null) - { - return iv.GetValue(); - } + // ** object model + public override object Evaluate() + { + // use IValueObject if available + var iv = _value as IValueObject; + if (iv != null) + { + return iv.GetValue(); + } - // return raw object - return _value; - } - public IEnumerator GetEnumerator() - { - var ie = _value as IEnumerable; - return ie != null ? ie.GetEnumerator() : null; - } - } - /// - /// Interface supported by external objects that have to return a value - /// other than themselves (e.g. a cell range object should return the - /// cell content instead of the range itself). - /// - public interface IValueObject - { - object GetValue(); - } + // return raw object + return _value; + } + public IEnumerator GetEnumerator() + { + var ie = _value as IEnumerable; + return ie != null ? ie.GetEnumerator() : null; + } + } + /// + /// Interface supported by external objects that have to return a value + /// other than themselves (e.g. a cell range object should return the + /// cell content instead of the range itself). + /// + public interface IValueObject + { + object GetValue(); + } } diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/CalcEngine/Functions/DateAndTime.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/CalcEngine/Functions/DateAndTime.cs index bf9009d..d454cfe 100644 --- a/ClosedXML/ClosedXML/ClosedXML/Excel/CalcEngine/Functions/DateAndTime.cs +++ b/ClosedXML/ClosedXML/ClosedXML/Excel/CalcEngine/Functions/DateAndTime.cs @@ -11,23 +11,23 @@ { ce.RegisterFunction("DATE", 3, Date); // Returns the serial number of a particular date ce.RegisterFunction("DATEVALUE", 1, Datevalue); // Converts a date in the form of text to a serial number - //ce.RegisterFunction("DAY", 1, Day); // Converts a serial number to a day of the month + ce.RegisterFunction("DAY", 1, Day); // Converts a serial number to a day of the month //ce.RegisterFunction("DAYS360", 1, Days360); // Calculates the number of days between two dates based on a 360-day year //ce.RegisterFunction("EDATE", 1, Edate); // Returns the serial number of the date that is the indicated number of months before or after the start date //ce.RegisterFunction("EOMONTH", 1, Eomonth); // Returns the serial number of the last day of the month before or after a specified number of months - //ce.RegisterFunction("HOUR", 1, Hour); // Converts a serial number to an hour - //ce.RegisterFunction("MINUTE", 1, Minute); // Converts a serial number to a minute - //ce.RegisterFunction("MONTH", 1, Month); // Converts a serial number to a month + ce.RegisterFunction("HOUR", 1, Hour); // Converts a serial number to an hour + ce.RegisterFunction("MINUTE", 1, Minute); // Converts a serial number to a minute + ce.RegisterFunction("MONTH", 1, Month); // Converts a serial number to a month //ce.RegisterFunction("NETWORKDAYS", 1, Networkdays); // Returns the number of whole workdays between two dates - //ce.RegisterFunction("NOW", 1, Now); // Returns the serial number of the current date and time - //ce.RegisterFunction("SECOND", 1, Second); // Converts a serial number to a second - //ce.RegisterFunction("TIME", 1, Time); // Returns the serial number of a particular time - //ce.RegisterFunction("TIMEVALUE", 1, Timevalue); // Converts a time in the form of text to a serial number - //ce.RegisterFunction("TODAY", 1, Today); // Returns the serial number of today's date + ce.RegisterFunction("NOW", 0, Now); // Returns the serial number of the current date and time + ce.RegisterFunction("SECOND", 1, Second); // Converts a serial number to a second + ce.RegisterFunction("TIME", 3, Time); // Returns the serial number of a particular time + ce.RegisterFunction("TIMEVALUE", 1, Timevalue); // Converts a time in the form of text to a serial number + ce.RegisterFunction("TODAY", 0, Today); // Returns the serial number of today's date //ce.RegisterFunction("WEEKDAY", 1, Weekday); // Converts a serial number to a day of the week //ce.RegisterFunction("WEEKNUM", 1, Weeknum); // Converts a serial number to a number representing where the week falls numerically with a year //ce.RegisterFunction("WORKDAY", 1, Workday); // Returns the serial number of the date before or after a specified number of workdays - //ce.RegisterFunction("YEAR", 1, Year); // Converts a serial number to a year + ce.RegisterFunction("YEAR", 1, Year); // Converts a serial number to a year //ce.RegisterFunction("YEARFRAC", 1, Yearfrac); // Returns the year fraction representing the number of whole days between start_date and end_date } @@ -47,5 +47,73 @@ return (int)Math.Floor(DateTime.Parse(date).ToOADate()); } + + static object Day(List p) + { + var date = (DateTime)p[0]; + + return date.Day; + } + + static object Month(List p) + { + var date = (DateTime)p[0]; + + return date.Month; + } + + static object Year(List p) + { + var date = (DateTime)p[0]; + + return date.Year; + } + + static object Minute(List p) + { + var date = (DateTime)p[0]; + + return date.Minute; + } + + static object Hour(List p) + { + var date = (DateTime)p[0]; + + return date.Hour; + } + + static object Second(List p) + { + var date = (DateTime)p[0]; + + return date.Second; + } + + static object Now(List p) + { + return DateTime.Now; + } + + static object Time(List p) + { + var hour = (int)p[0]; + var minute = (int)p[1]; + var second = (int)p[2]; + + return new TimeSpan(0, hour, minute, second); + } + + static object Timevalue(List p) + { + var date = (DateTime)p[0]; + + return (DateTime.MinValue + date.TimeOfDay).ToOADate(); + } + + static object Today(List p) + { + return DateTime.Now.Date; + } } } diff --git a/ClosedXML/ClosedXML/ClosedXML_Tests/Excel/CalcEngine/DateAndTimeTests.cs b/ClosedXML/ClosedXML/ClosedXML_Tests/Excel/CalcEngine/DateAndTimeTests.cs index b1b0c4e..a999c43 100644 --- a/ClosedXML/ClosedXML/ClosedXML_Tests/Excel/CalcEngine/DateAndTimeTests.cs +++ b/ClosedXML/ClosedXML/ClosedXML_Tests/Excel/CalcEngine/DateAndTimeTests.cs @@ -27,5 +27,75 @@ Object actual = XLWorkbook.EvaluateExpr("DateValue(\"8/22/2008\")"); Assert.AreEqual(39682, actual); } + + [TestMethod] + public void Day() + { + Object actual = XLWorkbook.EvaluateExpr("Day(\"8/22/2008\")"); + Assert.AreEqual(22, actual); + } + + [TestMethod] + public void Month() + { + Object actual = XLWorkbook.EvaluateExpr("Month(\"8/22/2008\")"); + Assert.AreEqual(8, actual); + } + + [TestMethod] + public void Year() + { + Object actual = XLWorkbook.EvaluateExpr("Year(\"8/22/2008\")"); + Assert.AreEqual(2008, actual); + } + + [TestMethod] + public void Second() + { + Object actual = XLWorkbook.EvaluateExpr("Second(\"8/22/2008 3:30:45 AM\")"); + Assert.AreEqual(45, actual); + } + + [TestMethod] + public void Minute() + { + Object actual = XLWorkbook.EvaluateExpr("Minute(\"8/22/2008 3:30:45 AM\")"); + Assert.AreEqual(30, actual); + } + + [TestMethod] + public void Hour() + { + Object actual = XLWorkbook.EvaluateExpr("Hour(\"8/22/2008 3:30:45 PM\")"); + Assert.AreEqual(15, actual); + } + + [TestMethod] + public void Time() + { + Object actual = XLWorkbook.EvaluateExpr("Time(1,2,3)"); + Assert.AreEqual(new TimeSpan(1, 2, 3), actual); + } + + [TestMethod] + public void TimeValue1() + { + Object actual = XLWorkbook.EvaluateExpr("TimeValue(\"2:24 AM\")"); + Assert.IsTrue(XLHelper.AreEqual(0.1, (double)actual)); + } + + [TestMethod] + public void TimeValue2() + { + Object actual = XLWorkbook.EvaluateExpr("TimeValue(\"22-Aug-2008 6:35 AM\")"); + Assert.IsTrue(XLHelper.AreEqual(0.27430555555555558, (double)actual)); + } + + [TestMethod] + public void Today() + { + Object actual = XLWorkbook.EvaluateExpr("Today()"); + Assert.AreEqual(DateTime.Now.Date, actual); + } } }