Time zone differences





This article describes the standards that apply to applied solution that can run in different time zones. All of the listed recommendations are mandatory unless noted otherwise.

1. Configurations must support scenarios where the server time zone is different from the user time zone. For example, users in a Denver company access a server located in Boston and all system operations must be recorded in the local (Denver) time.

This scenario is often required in client/server infobases and in SaaS applied solutions.

2.1. Do not use the CurrentDate function, which returns the server date and time, in server procedures and functions. Use the CurrentSessionDate function instead, which converts the server time to the user session time.

2.2. When you need a universal time value that does not depend on the user time zone, use the ToUniversalTime function. For example, you might need this for defining the cache overflow time or getting the time when a scheduled job was last executed.  

2.3. When using platform methods that return the local server date, convert it either to the universal time or the the user session time, as in the following example:

UpdateDateUniversal = ToUniversalTime(FullTextSearch.UpdateDate());
UpdateDate = ToLocalTime(UpdateDateUniversal, SessionTimeZone());

3.1. Do not use the CurrentDate function in the client code. This is required because the current time calculated in the client code must be identical to the current time calculated in the server code.

For example, a server is located in New York and users access it from Chicago. The CurrentDate function returns 10:00 on the client and 11:00 on the server. At the same time the CurrentSessionDate function returns 10:00 on the server, provided that the Chicago time is set in the infobase (using the SetInfoBaseTimeZone method).

Normally, instead of calling the CurrentDate function on the client you have to: 

  • pass the date and time converted to the user session time zone from the server to the client; 
  • for document operations on the client, use the document date.

The following examples illustrate some typical scenarios.

3.2. In a month closing algorithm a date is passed from the client to the server. This date defines which month is closed.

Incorrect:

&AtClient
Procedure CommandOpenMonthClosing(Command)
 CurrentData = Items.List.CurrentData;
 If CurrentData = Undefined Then
  CurDate  = CurrentDate();  // calling CurrentDate() on the client
 Else
  CurDate  = CurrentData.Date;
 EndIf;
 FormParameters = New Structure;
 FormParameters.Insert("RegistrationPeriod", CurDate);
OpenForm("DataProcessor.MonthClosing.Form.Form", FormParameters, ThisObject);

and then in the data processor form:

&AtServer
Procedure OnCreateAtServer(Cancel, StandardProcessing)
 FillPropertyValues(Object, Parameters);
 If Not ValueIsFilled(Object.RegistrationPeriod) Then
  Object.RegistrationPeriod = BegOfMonth(CurrentDate());
 EndIf;

Correct (the current date is retrieved on the server):

&AtClient
Procedure CommandOpenMonthClosing(Command)
 CurrentData = Items.List.CurrentData;
  If CurrentData = Undefined Then
  CurDate  = Undefined; // CurrentDate() is not called on the client
 Else
  CurDate = CurrentData.Date;
 EndIf;
 FormParameters = New Structure;
 FormParameters.Insert("RegistrationPeriod", CurDate);
OpenForm("DataProcessor.MonthClosing.Form.Form", FormParameters, ThisObject);

and use the CurrentSessionDate function in the data processor form:

&AtServer
Procedure OnCreateAtServer(Cancel, StandardProcessing)
 FillPropertyValues(Object, Parameters);
 If Not ValueIsFilled(Object.RegistrationPeriod) Then
  Object.RegistrationPeriod = BegOfMonth(CurrentSessionDate());
 EndIf;

3.3. During document operations, consider using the document date instead of the current date.

In the following example the calculation date, which is used for displaying prices and balances as of this date, is passed to the tabular section of the product list filling form.

Incorrect:

&AtClient
Procedure FillProducts(Command)
 FillParameters = New Structure;
 CalculationDate = ?(BegOfDay(Object.Date) = BegOfDay(CurrentDate()),
  Undefined, Object.Date); // CurrentDate() is called on the client
 FillParameters.Insert("CalculationDate", CalculationDate);
 ...
 OpenForm("DataProcessor.ProductFilling.Form.Form", FillParameters,
  ThisObject, UUID);

The correct method is passing the document date to the server and calculate the calculation date on the server:

&AtClient
Procedure FillProducts(Command)
 FillParameters = New Structure;
 FillParameters.Insert("CalculationDate", Object.Date);
 ...
 OpenForm("DataProcessor.ProductFilling.Form.Form", FillParameters,
  ThisObject, UUID);

Another example. When the list of sales orders that can be closed by a sales invoice is filled, the "document date is less or equal to the date passed to the form" filter is set in the form where the list is filled.

Incorrect:

&AtClient
Procedure OrderClosingStartOrderDocumentSelection(Item, ChoiceData, StandardProcessing)
 StandardProcessing = False;
 FormParameters = New Structure;
  FormParameters.Insert("EndOfPeriod",                                   
?(ValueIsFilled(Parameters.Key), Object.Date - 1, EndOfDay(CurrentDate()))); // CurrentDate() is called on the client
 ...
  OpenForm("Document.SalesOrder.ChoiceForm",        
FormParameters, Item);
...

The correct method is calculating the EndOfPeriod parameter by document date:

&AtClient
Procedure OrderClosingStartOrderDocumentSelection(Item, ChoiceData, StandardProcessing)
 StandardProcessing = False;
  FormParameters = New Structure;
  FormParameters.Insert("EndOfPeriod", ?(ValueIsFilled(Parameters.Key),
  Object.Date - 1, EndOfDay(Object.Date)));
 ...
  OpenForm("Document.SalesOrder.ChoiceForm", FormParameters, Item);

4. Exceptions from rules described in paragraphs 2 and 3 are allowed in rare specific cases when you actually need to use the current server time. Explain each exception in the comments to the function call.

5. Avoid multiple calls of CurrentSessionDate or CurrentDate in a single procedure or function because they will return different values.

Incorrect:

LastNotificationDate = CurrentSessionDate();
NextNotificationDate = CalculateDate() + CurrentSessionDate();

The correct method is using the previously calculated date and time:

LastNotificationDate = CurrentSessionDate();
NextNotificationDate = CalculateDate() + LastNotificationDate;


Comments
0
Add comment