Appearance
Time processing
Basic Concepts
AppCube
Time processing in the system is complex, especially when multiple time zones are involved. Its complexity lies not in the complexity of the interface, but in the variety of scenarios in which scripts are used.AppCube
There are three trigger modes:
- After the user logs in,
http
The request directly or indirectly triggers the script. (Indirect triggering modes include flow invoking and triggering.) - Script triggered by the scheduled task directly or indirectly.
- Scripts triggered by events directly or indirectly.
The time zone used in the execution context is different in the three cases:
Time zone of the login user in the first case, organization time zone of the tenant in the second case, and UTC time zone in the third case.
AppCube
There are four time zones in the system:
- User Time Zone
The user's default time zone isLocal
It is easy to mislead people into thinking that this is the time zone of the operating system where the browser is located, but it isAppCube
Time zone of the operating system on the server. You are advised to change the time zone to the following:
The time zone in the script execution triggered by a normal request is the user time zone.
- Tenant organization time zone
Tenant organization time zone, which is used by the script execution context triggered by the scheduled task.
- Server OS Time Zone
AppCube
By default, the backend script engine of the uses this time zone.
- Client OS Time Zone (Browser)
AppCube
The backend scripting engine does not use this time zone. OnlyAppCube
The frontend script uses this time zone.
After we know the information about the time zone, let's look at it again.AppCube
Time type involved in.
javascript
Time type ofDate
We first have to be clearjavascript
MediumDate
Definition of the type:
Date
Creates a JavaScript Date instance that renders a moment in time. The Date object is based on the Unix Time Stamp, which is the number of milliseconds since January 1, 1970 (UTC).
From the definition we can see,Date
The object itself indicates yes: the number of milliseconds elapsed since January 1, 1970 (UTC). There is no concept of time zone.
The concept of when and sometimes zone. Simply put:
Is to turn a string into aDate
Instance, or from aDate
The concept of a time zone becomes apparent as the instance gets a time string.
const date1 = new Date('December 17, 1995 03:24:00');
console.log(date1.toString());
const date2 = new Date('1995-12-17T03:24:00');
console.log(date2.toLocaleString('zh-CN', { timeZone: 'UTC' }));
AppCube
By default, the backend script engine of the uses the UTC time zone, as shown in.new Date(...)
,JSON.parse, JSON.stringify
Function,
AppCube
in the back-end script engineconsole.log
PrintDate
When a variable is instanced, the script execution context time zone is used.
console.log
The output time string uses the script execution context timezone because it is notjavascript
For the standard library, it'sAppCube
Extended implementation of,AppCube
The script engine uses the time zone information of the execution context when printing logs.
AppCube time type.Date
To be associated with theDatetime
AppCube
Object field type support inDate
To be associated with theDatetime
Type, both of which are mapped in the back-end scripting engine tojavascript
of theDate
Type. However, the processing of the two types in the time zone is different:
- object's
Date
Indicates the year, month, and day information. There is no time zone. The date character string transferred by the client is invoked.yyyy-MM-dd
All are processed as character strings of the UTC time zone. - object's
Datetime
Indicates the year, month, day, hour, minute, and second information. The time zone is a date character string transferred by the client.yyyy-MM-dd HH:mm:ss
Strings that are treated as different time zones in different script triggering processes.
Writing an Example Script
Let's use an example script as an example:
ts
export class Input {
@action.param({ type: "Date" })
inDate: Date;
@action.param({ type: "Datetime" })
inDatetime: Date;
}
export class Output {
@action.param({ type: "Date" })
outDate: Date;
@action.param({ type: "Datetime" })
outDatetime: Date;
}
export class DateDemo {
@action.method({ input: "Input", output: "Output", description: "do a operation" })
run(input: Input): Output {
let output = new Output();
console.log("input date = ", input.inDate);
console.log("input datetime = ", input.inDatetime);
output.outDate = new Date("2021-07-01 06:30:30");
output.outDatetime = new Date("2021-07-01 06:30:30");
console.log("output date = ", output.outDate);
console.log("output datetime = ", output.outDatetime);
return output;
}
}
Execute the script.
- Request parameter
ts
{
"inDate": "2021-07-01 06:30:30",
"inDatetime": "2021-07-01 06:30:30"
}
Date
You can also enter a character string containing the hour, hour, and second. When the backend script is executed, the parameter is directly deleted.
- Script running output log
ts
0728 11:10:25.314|debug|vm[18]>>> Build #AppCube Core 1.3.7 on amd64
Built on 2021-07-27 20:14:22
Commit #4c0246172d
0728 11:10:25.314|debug|vm[18]>>> node: 2
0728 11:10:25.314|debug|vm[18]>>> script: my__datedemo 1.0.1 DateDemo.run
0728 11:10:25.314|debug|vm[18]>>> locale: zh_CN
0728 11:10:25.314|debug|vm[18]>>> timezone: (GMT+08:00) China Standard Time (Asia/Shanghai)
0728 11:10:25.314|debug|vm[18]>>> input date = 2021-07-01T08:00:00+08:00 (my__datedemo.ts:22)
0728 11:10:25.314|debug|vm[18]>>> input datetime = 2021-07-01T06:30:30+08:00 (my__datedemo.ts:23)
0728 11:10:25.314|debug|vm[18]>>> output date = 2021-07-01T14:30:30+08:00 (my__datedemo.ts:28)
0728 11:10:25.314|debug|vm[18]>>> output datetime = 2021-07-01T14:30:30+08:00 (my__datedemo.ts:29)
- From the
input date = 2021-07-01T08:00:00+08:00
Informationally, the input parameterinDate
The hour, minute and second of is truncated into2021-07-01
, and is treated as a UTC date string. - From the
input datetime = 2021-07-01T06:30:30+08:00
Informationally, the input parameterinDatetime
Used as a user time zone string: GMT+8 character string - From the
output date = 2021-07-01T14:30:30+08:00
Informationally,new Date("2021-07-01 06:30:30")
The input parameter is used asUTC
Time string,console.log
The print result is converted into a character string of GMT+8 hours. - According to the logs,
AppCube
in the back-end script engineconsole.log
PrintDate
When a variable is instanced, the script execution context time zone, that is, the user time zone, is used.
- Returned information
ts
{
"outDate": "2021-07-01 08:00:00",
"outDatetime": "2021-07-01 14:30:30"
}
From theoutDate
According to the returned result, the hour, hour, and second are truncated. and the character string converted to the user time zone is returned. Technically, it should be returned.2021-07-01
That's right. but because the underlying libraryjson
Serialization does not distinguish the object engineDate
To be associated with theDatetime
Type, so the format string with hour, hour, and second is returned.
From theoutDatetime
According to the returned result of,new Date("2021-07-01 06:30:30")
The input parameter is used as theUTC
In addition to the time string, the returned time zone is converted to GMT+8, which adds eight hours.
The preceding figure shows the time zone processing for the script after the user logs in to the system. When an event is triggered or a scheduled task is triggered, the preceding results are different: The time zone in the script execution context affects the processing of time strings.
Date module
In order to handle the time zone processing of the above complicated date and time,AppCube
Offered date module, The module deals specifically with these issues.
- format
ts
function format(date: Date, layout: string, timezone?: TimeZones): string
Formats the Date type as a string. If the time zone is not specifiedtimezone
, obtain the time zone information based on the following rules:
- The user time zone is used in the script triggered by the user HTTP request.
- Use the tenant organization time zone in the script triggered by the scheduled task.
- Use the UTC time zone in the script triggered by an event.
ts
import { getTimeZone } from 'context';
import { format } from 'date';
let result = format(new Date(), 'yyyy-MM-dd HH:mm:ss', getTimeZone());
in that above example,timezone
Use the time zone of the script execution context:getTimeZone()
, which is the same as the default value.
- parse
ts
function parse(dateStr: string): Date
Parses a date string into a variable of the Date type based on the specified format string. Obtain the time zone information as follows:
- User
http
In the script triggered by the request, the user time zone is used. - The tenant time zone is used in the script triggered by the scheduled task.
- In the event-triggered script, use the
UTC
Time zone - toDate
ts
function toDate(date: string, layout: string, timezone?: TimeZones): Date
Parses a date string into a variable of the Date type based on the specified format string. If the time zone is not specifiedtimezone
, obtain the time zone information based on the following rules:
- User
http
In the script triggered by the request, the user time zone is used. - The tenant time zone is used in the script triggered by the scheduled task.
- In the event-triggered script, use the
UTC
Time zone
ts
import { getOrganizationTimeZone } from 'context';
import { toDate } from 'date';
let date = toDate('2018-08-08 20:08:08', 'yyyy-MM-dd HH:mm:ss', getOrganizationTimeZone());
In the preceding example, the tenant organization time zone is used, and a time string is used.2018-08-08 20:08:08
Converted into ajavascript
of theDate
Type instance.
Recommended solution for unified handling of time zones
With the above knowledge in mind, we can begin to discuss how a script that processes time can be executed consistently and successfully in different execution contexts. In general, there are three strategies:
Time string with time zone information
In the event triggering and scriptinghttp
The time character strings of input and output parameters such as requests contain the time zone information. For example:
ts
{
"inDate": "2021-07-01T06:30:30+08:00",
"inDatetime": "2021-07-01T06:30:30+08:00"
}
AppCube
The time zone information in the time string is used preferentially. However, this can only solve the problem of input and output parameters, not the problem.new Date
The time zone of the script standard library is incorrect. In addition, many interconnected third-party systems may not support the character string format with the time zone.
Determine different execution contexts and perform special processing.
context
The module provides the following interfaces:
ts
/**
*Script Execution Triggering Request Type
*/
export enum RequestType {
/**
*RESTful request of the login user
*/
User = 0,
/**
*Event-triggered request
*/
Event = 1,
/**
*Request triggered by a scheduled task
*/
Task = 2
}
function getRequestType(): RequestType
Based on the execution context type of the script, the code performs different special processing on the time character string. The example is provided in the third case.
Use the tenant organization time zone in a unified manner.
Now we use thedate
The module rewrites the previous example script:
ts
import * as date from 'date';
import * as context from 'context';
export class Input {
@action.param({ type: "Date" })
inDate: Date;
@action.param({ type: "Datetime" })
inDatetime: Date;
}
export class Output {
@action.param({ type: "Date" })
outDate: Date;
@action.param({ type: "Datetime" })
outDatetime: Date;
}
const dateLayout = 'yyyy-MM-dd HH:mm:ss';
export class DateDemo {
@action.method({ input: "Input", output: "Output", description: "do a operation" })
run(input: Input): Output {
let output = new Output();
console.log("input date = ", input.inDate);
let inDatetime = context2OrganizationTime(input.inDatetime);
console.log("input datetime = ", inDatetime);
output.outDate = newOrganizationTime("2021-07-01 06:30:30");
output.outDatetime = newOrganizationTime("2021-07-01 06:30:30");
console.log("output date = ", output.outDate);
console.log("output datetime = ", output.outDatetime);
return output;
}
}
function newOrganizationTime(dateStr: string): Date {
return date.toDate(dateStr, dateLayout, context.getOrganizationTimeZone())
}
function context2OrganizationTime(d: Date): Date {
//Correction time input parameter, which may be incorrect in event-triggered execution scenarios.
//This judgment processing is not required actually. However, adding this function can improve performance and reduce the number of time objects to be created.
if (context.getRequestType() != context.RequestType.Event) {
return d;
}
let dateStr = date.format(d, dateLayout, context.getTimeZone());
return date.toDate(dateStr, dateLayout, context.getOrganizationTimeZone());
}
Compared with the previous version, the code in this version has the following changes:
- For input parameters, call
context2OrganizationTime
Function to convert from the script execution context time zone to the tenant organization time zone - Use the
date.toDate
In place of thenew Date
The execution information of the script code of this version is as follows:
- Request parameter
ts
{
"inDate": "2021-07-01 06:30:30",
"inDatetime": "2021-07-01 06:30:30"
}
- Script running output log
bash
0728 14:39:33.924|debug|vm[22]>>> Build #AppCube Core 1.3.7 on amd64
Built on 2021-07-27 20:14:22
Commit #4c0246172d
0728 14:39:33.924|debug|vm[22]>>> node: 2
0728 14:39:33.924|debug|vm[22]>>> script: my__orgdatedemo 1.0.1 DateDemo.run
0728 14:39:33.924|debug|vm[22]>>> locale: zh_CN
0728 14:39:33.924|debug|vm[22]>>> timezone: (GMT+08:00) China Standard Time (Asia/Shanghai)
0728 14:39:33.925|debug|vm[22]>>> input date = 2021-07-01T08:00:00+08:00 (my__orgdatedemo.ts:28)
0728 14:39:33.925|debug|vm[22]>>> input datetime = 2021-07-01T06:30:30+08:00 (my__orgdatedemo.ts:31)
0728 14:39:33.925|debug|vm[22]>>> output date = 2021-07-01T06:30:30+08:00 (my__orgdatedemo.ts:36)
0728 14:39:33.925|debug|vm[22]>>> output datetime = 2021-07-01T06:30:30+08:00 (my__orgdatedemo.ts:37)
- Returned information
ts
{
"outDate": "2021-07-01 08:00:00",
"outDatetime": "2021-07-01 06:30:30"
}
The following information is displayed in the log:output datetime = 2021-07-01T06:30:30+08:00
and return value"outDatetime": "2021-07-01 06:30:30"
Informationally, the originalnew Date
The problem of adding eight hours is gone.
Secondary Log Informationinput datetime = 2021-07-01T06:30:30+08:00
Come and see, putinDatetime
After the tenant organization time zone is changed, the result is still correct. The output is the same regardless of the scenario in which the script is executed.
The prerequisite for this solution is that the user time zone is the same as the tenant organization time zone.