Simphony JavaScript Extensibility tries its best to convert between C# and Javascript native types (ints, doubles, dates).
One slightly complicated area is the C# DateTime/Javascript Date conversion. If a script reads the check CheckOpenTime property, the C# DateTime struct is automatically converted to a Javascript Date object. In fact, since the conversion happens automatically, it is not possible to access the C# DateTime struct directly.
The conversion from C# DateTime to JavaScript Date has issues, especially when the DateTime.Kind property in C# is “Unknown”. Both objects offer their own functionality, but they are not equivalent.
There are times where direct access to the C# DateTime struct is
necessary. For example, a script would prefer the C# DateTime parsing
and formatting functions. In order to help JavaScript applications
access the C# DateTime struct directly, the
SimphonyExtensibilityAPI.DateTimeAccess
API object was
introduced.
DateTimeAccess API functionality:
DateTimeScriptable
. This class
provides identical DateTime functionality, but it hides the underlying
DateTime to prevent Javascript native Date conversion.DateTimeScriptable
in the DateTimeAccess API.DateTimeScriptable
object.DateTimeScriptable
.There are 2 ways to construct a DateTimeScriptable
object
(See API documentation below for all methods on DateTimeAccess.)
Using DateTimeAccess to construct a DateTimeScriptable
is straightforward; the DateTime constructor methods are duplicated in
DateTimeAccess.
var _api = SimphonyExtensibilityAPI;
let dts = null;
// allocate with date
= _api.DateTimeAccess.AllocateScriptable(1980, 1, 10);
dts
// allocate with date, time, and ms
= _api.DateTimeAccess.AllocateScriptable(1980, 1, 10, 12, 30, 45, 500); dts
Constructing a DateTimeScriptable
from an existing
DateTime is subtle. While a constructor exists with a DateTime, the
Javascript engine will automatically convert the argument to a
Javascript Date, and then convert back to DateTime, which may lose
important information such as the Kind property. In general, this
conversion is fine.
// allocate directly, DateTime converted to Date, and then back to DateTime
let dts = _api.DateTimeAccess.AllocateScriptable(args.Check.Header.CheckOpenTime);
To prevent C# DateTime from being converted to Date, DateTimeAccess provides a method which uses reflection to access the DateTime without the Javascript engine converting it to a Date.
// method will use reflection to access the DateTime property,
// Javascript engine will not be involved
let dts = _api.DateTimeAccess.AllocateScriptableFromProperty(args.Check.Header, 'CheckOpenTime');
What does this accomplish? The moment the Javascript engine accesses
the C# CheckOpenTime property, it is converted to a Javascript Date. By
using reflection, the DateTimeScriptable
is allocated
without the Javascript engine ever touching the property.
Why would a script writer the original DateTime? C# DateTime has properties not available in Javascript Date. The “Kind” property (Local, UTC, Unknown) can affect how a Javascript Date is created. If Kind==Unknown, many problems can arise.
A DateTimeScriptable
object wraps a C# DateTime struct.
Most methods in DateTime are provided in
DateTimeScriptable
. (See API reference below)
Once a script has access to DateTimeScriptable
, it can
treat it in the same way as it would a native DateTime.
The only unimplemented methods are operator overloads.
// use DateTime.Parse() to create a js Date
let jsDate = _net.System.DateTime.Parse("April 15, 2025 12:30:35pm");
// convert to DateTime wrapper object
let netDate = _api.DateTimeAccess.AllocateScriptable(jsDate);
// format
let fmtText = null;
= netDate.ToString("yyyy-MM-dd HH:mm:ss.fff");
fmtText = netDate.ToLongDateString() + ' ' + netDate.ToLongTimeString();
fmtText
// get day of week
let dayOfWeek = netDate.DayOfWeek.ToString();
// date arithmetic, Add/Subtract return a DateTimeScriptable
= netDate.AddMonths(5);
netDate = netDate.AddMinutes(30); netDate
public class DateTimeScriptable
{
public DateTimeScriptable Add( TimeSpan value );
public DateTimeScriptable AddDays( double value );
public DateTimeScriptable AddHours( double value );
public DateTimeScriptable AddMilliseconds( double value );
public DateTimeScriptable AddMinutes( double value );
public DateTimeScriptable AddMonths( int value );
public DateTimeScriptable AddSeconds( double value );
public DateTimeScriptable AddTicks( long value );
public DateTimeScriptable AddYears( int value );
public DateTimeScriptable Subtract( TimeSpan value );
public bool IsDaylightSavingTime();
public DateTimeScriptable ToLocalTime();
public DateTimeScriptable ToUniversalTime();
public double ToOADate();
public int CompareTo( DateTimeScriptable value );
public long ToBinary();
public long ToFileTime();
public long ToFileTimeUtc();
public string ToLongDateString();
public string ToLongTimeString();
public string ToShortDateString();
public string ToShortTimeString();
public String[] GetDateTimeFormats( char format );
public String[] GetDateTimeFormats( char format, IFormatProvider provider );
public String[] GetDateTimeFormats( IFormatProvider provider );
public String[] GetDateTimeFormats();
public TimeSpan Subtract( DateTimeScriptable value );
public TypeCode GetTypeCode();
public DateTime Actual { get; }
public DateTime Date { get; }
public DateTimeKind Kind { get; }
public DayOfWeek DayOfWeek { get; }
public int Day { get; }
public int DayOfYear { get; }
public int Hour { get; }
public int Millisecond { get; }
public int Minute { get; }
public int Month { get; }
public int Second { get; }
public int Year { get; }
public long Ticks { get; }
public TimeSpan TimeOfDay { get; }
}