IOM
Copy
Always keep the following statements in mind when dealing with locale specific types using IOM:
- The format of property values that are local specific (‘date’, ‘float’, ‘decimal’) are always presented in AML in the neutral format.
- Property values of type ‘date’ are always presented in AML in the time zone of the current session
- Dates are always stored in the database in UTC (no time zone)
To support conversion to\from neutral format as well as get information about the current session locale\language\time zone\etc. IOM.Innovator class has a new method getI18NSessionContext() that returns an instance of a class that implements I18NSessionContext interface. The interface allows you to get information about the session locale\language\etc. (getLocale(), getLanguageCode(), etc.) as well as containing methods for converting to\from neutral format (ConvertToNeutral(..), ConvertFromNeutral(...)) and methods specific to converting to\from UTC date-time (ConvertUtcDateTimeToNeutral(..), ConvertNeutralToUtcDateTime(..)).
Here is the exact format of the conversion methods:
string ConvertToNeutral (string value, string type, string format )
where,
- ‘
value’ is a string that has to be converted (e.g. ‘12/25/2003’) - ‘
type’is name of an Aras Innovator type where representation is locale dependent; this parameter can be one of the following‘date’ | ‘float’ | ‘decimal’ - ‘
format’– format of the ‘value’. If the parameter is either a null or empty string then an attempt is made to parse the passed ‘value’assuming that the ‘value’has a format that is valid for the session locale; if parsing failed then an exception is thrown.
string ConvertFromNeutral( string value, string type, string format )
where,
- ‘
value’is a string in neutral format that has to be converted (in most cases the string would be a property value taken from AML) - ‘
type’is the name of an Aras Innovator type where representation is locale dependent; this parameter can be one of the following‘date’ | ‘float’ | ‘decimal’ - ‘
format’– the parameter is taken into account onlyif ‘type’=’date’in which case it’s one of the following:‘short_date’ | ‘long_date’ | ‘short_date_time’ | ‘long_date_time’ | ‘long_time’ | ‘short_time’.
value’returned by the method depends on the locale of the session (in other words: conversion to, let’s say, ‘short_date’of a particular ‘value’results in different short date format representations of the ‘value’depending on the session locale).
string ConvertUtcDateTimeToNeutral( string utcDateTime, string inFormat );
The method returns a string that represents ‘utcDateTime’ in the time zone of the session and in neutral format. Parameters are:
- ‘
utcDateTime’is a string that is interpreted either as UTC date-time if it doesn’t have an offset or has offset 0 or as the exact moment of time if it has an offset. - ‘
inFormat’defines the format of the ‘utcDateTime’string.
inFormat’is null then an attempt is made to parse passed ‘utcDateTime’assuming that it has a valid invariant culture format. If ‘inFormat’is not null then it has to represent a valid invariant culture date\time format.
string ConvertNeutralToUtcDateTime( string neutralDateTime, string outFormat ); the method returns a string that represents the corresponding UTC date-time in the specified format.
- ‘
neutralDateTime’is a string that represents a date-time value in the session time zone in neutral format - ‘
outFormat’is the format in which the resulting UTC date-time is returned.
Let’s consider several specific use-cases in order to understand i) what the above statements mean in each situation; ii) how I18NSessionContext methods can help.
Example 1
The User writes a client method that makes a request to the server and then converts the obtained value of the received property ‘modified_on’ of type ‘date’ into the ‘long_date’ format of the locale of the current session in order to display it in UI:
...
// Make request to the server and get the value of the “modified on” property
var request = this.newItem(“Issue”,"get”);
request.setProperty(“id”,"4A6478F0C0CB46F1B24D9526223FA14F”);
var response = request.apply();
var issue_date_str = response.getProperty(“modified_on”);
// At this point the value of “issue_date_str” is something like:
// 2007-12-25T15:23:30
// It has to be converted to the format that appropriate for the
// locale of the session:
var cntx = this.getInnovator().getI18NSessionContext();
var new_value =cntx.ConvertFromNeutral(issue_date_str,'date’,'short_date’);
// At this point the “new_value” would look as the following (let’s assume
// that the session locale is “en-US”; also remember that we used ‘short_date’
// format so time portion was cut):
// 12/25/2008
…
Example 2
The User writes a client method that reads a form field that contains a date; the user wants to build an AML putting the value read from the field into the AML property ‘effective_date’:
...
// Read the value from the field
var duedate = document.forms[0].new_due_date.value;
// The “duedate” looks as the following (let’s assume that session locale is
// “fr-FR” (French(France)): 25/12/2007
// Convert to neutral format because according to the statement a.
// all dates in AML must be in neutral format:
var cntx = this.getInnovator().getI18NSessionContext();
var dd_neutral = cntx.ConvertToNeutral( duedate, ‘date’, ‘’);
// The value of “dd_neutral” would look like: 2007-12-25
// Now create item and set its property ‘effective_date’
var newPart = this.newItem(“Part”,"add”);
newPart.setProperty(“item_number”,"xxx”);
newPart.setProperty(“effective_date”,dd_neutral);
...
Example 3
The user writes a stand-alone application using IOM to access Aras Innovator and needs to form a correct AML for properties of type ‘date’:
...
// Instance of IOM.Innovator is available as ‘inn’
I18NSessionContext cntx = inn.getI18NSessionContext();
Item my_part = inn.newItem( ‘Person’, ‘add’ );
// Let’s assume that user of the application entered the date-time value
// in a text field; this value is a) in the time zone of the machine which is also
// the time zone of the current Aras Innovator session; b) in the ‘long_date_time’
// format of the session locale (let’s assume it’s “en-US”). Before the conversion
// the date looks like “Friday, October 10, 2008 01:00:00 PM”; after the convertion –
// “2008/10/10T13:00:00”
string dob_val = , cntx.ConvertToNeutral(inputText.Text, ‘date’, ‘’);
// Finally set the property
my_part.setProperty( ‘date_of_birth’, dob_val );
…
Example 4
The user writes a stand-alone application using IOM to access Aras Innovator and needs to show dates obtained in AML in the short-date-time format of the machine locale (which is also the locale of the current session):
...
// Instance of IOM.Innovator is available as ‘inn’
I18NSessionContext cntx = inn.getI18NSessionContext();
// Make the request to get data
Item request = this.newItem( ‘Part’, ‘get’ );
request.setProperty( ‘item_number’, ‘xxx’ );
Item response = request.apply();
string part_date_str = response.getProperty( ‘modified_on’ );
// ‘modified_on’ date is in the time zone of the current session (according
// to the statement b) and in neutral format (according to the statement a).
// So before the conversion the date would like: “2005/09/17T11:22:35”,
// after the conversion (let’s assume that the locale is “fr-FR”):
// “17/09/2005 11:22:35”
inputText.Text = cntx.ConvertFromNeutral( part_date_str, ‘date’, ‘short_date’ );
Example 5
The user writes a server ‘onBefore’ method in which the user needs to compare the created_on property in the AML with some other date that needs to be obtained from the database:
…
// The value is the date in the session time zone (according to the statement b)
// which is presented in neutral format (per statement a).
string created_on_str = this.getProperty( ‘created_on’);
// Convert this to a date-time object
DateTime created_on_dt = DateTime.Parse(created_on_str);
// Build request to the database and get another date with which we need to compare
// Note that interested us property value of type ‘date’ is also in the neutral
// format (according to statement a) and in the time zone of the session (statement b)
Item request = this.newItem( ‘Part’, ‘get’ );
request.setProperty( ‘item_number’, ‘xxx’ );
Item response = request.apply();
string part_date_str = response.getProperty( ‘modified_on’ );
DateTime part_dt = DateTime.Parse( part_date_str);
// Because both created_on_dt and part_dt are DateTime objects
// in the same time zone they could be compared
if( DateTime.Compare( created_on_dt, part_dt ) != 0 )
…
Example 6
Let’s say the user writes a server method that must set property closed_on of type ‘date’. The format of the property value must be in neutral format and the value must be in the time zone of the session in which the method is called. Here is a problem though: an attempt to create an instance of DateTime on the server would return a date\time object in the time zone of the server which might be different from the time zone of the current session; from the other side methods for getting DateTime in a particular time zone and\or converting from a time zone to another time zone are available only in .NET 3.5. In this case the best option is to use method ConvertUtcDateTimeToNeutral(...) available in I18NSessionContext class:
…
// First, get session context
I18NSessionContext cntx = this.getInnovator().getI18NSessionContext();
// Get ‘now’ moment as date-time in UTC in SortableDateTimePattern
// which is: “yyyy'-'MM'-'dd’T’HH':'mm':'ss”
String utc_now = DateTime.UtcNow.ToString( “s”);
// Get the same moment of time in the time zone of the session
// and in neutral format.
String pval = cntx.ConvertUtcDateTimeToNeutral( utc_now, null );
// Finally set the property value
this.setProperty( ‘closed_on’, pval );
…
now’ moment of time as the value of a property. In this cases an alternative simpler approach would be to put
__now()into the property
closed_on. Note that can be done only in request AML as the __now()is interpreted by the Aras Innovator server and replaced on the equivalent date-time representation of ‘this moment of time’. So that can be done in let’s say a method that is called onBeforeUpdateas the resulting AML is processed by the update action of server and the
__now()is interpreted correctly. At the same time if the method is invoked on, let’s say, onAfterUpdate putting __now()would be a wrong thing to do because this syntax is allowed only in AML requests (not responses (!) and
onAfterUpdateevent works on a response AML that is about to be sent back to the client) of add/update type (i.e. action=”add” | “edit” | “merge” | “update”| etc.) – refer to section DateTime Properties for more details.
Example 7
Let’s say a user triggers a Server Event from a Client machine in the United States locale (en-US) but the server is located on a German locale with a German operating system (de-DE). This German server by default handles decimals in the format 123.456,78 whereas the US client handles decimals 123,456.78. Because of this mismatch in decimal handling on the client and server the server method must be able to handle an invariant culture for decimals. Here is some sample code written in C# to parse a string (returning a decimal property) and convert that string to Decimal:
string dval_str_enUS = “123,456.78”; // US Decimal String
string dval_str_deDE = “123.456,78”; // German Decimal String
//Convert US Decimal string to Decimal value
decimal dval_enUS = Decimal.Parse( dval_str_enUS, CultureInfo.InvariantCulture );
//Convert German Decimal string to Decimal Value
decimal dval_deDE = Decimal.Parse( dval_str_deDE, CultureInfo.InvariantCulture );
…//Perform some computations on decimal values…
this.setProperty(“my_prop”,cntx.ConvertToNeutral(dval_enUS.ToString(),”decimal”,””);
…