diff --git a/docs/docs/03-language-reference.md b/docs/docs/03-language-reference.md index b8a3c5bc25b..082fe73ab99 100644 --- a/docs/docs/03-language-reference.md +++ b/docs/docs/03-language-reference.md @@ -413,11 +413,62 @@ assert(threeHours.minutes == 180); Duration objects are immutable and can be referenced across inflight context. -#### 1.1.5.1 Roadmap +#### 1.1.6 `Datetime` -An additional built-in `datetime` type is planned and not yet implemented. `datetime` represents a single moment in time in a platform-independent +The `Datetime` (alias `datetime`) type represents a single moment in time in a platform-independent format. -See https://github.com/winglang/wing/issues/2102 to track. +Datetime objects are immutable and can be referenced across inflight context. +Here is the initial API for the Datetime type: + +```TS +struct DatetimeComponents { + year: num; + month: num; + day: num; + hour: num; + min: num; + sec: num; + ms: num; + tz: num; // timezone offset in minutes from UTC +} + +class Datetime { + static utcNow(): Datetime; // returns the current time in UTC timezone + static systemNow(): Datetime; // returns the current time in system timezone + static fromIso(iso: str): Datetime; // creates an instance from an ISO-8601 string, represented in UTC timezone + static fromComponents(c: DatetimeComponents): Datetime; + + timestamp: num; // Date.valueOf()/1000 (non-leap seconds since epoch) + timestampMs: num; // Date.valueOf() (non-leap milliseconds since epoch) + + hours: num; // Date.getHours() + min: num; // Date.getMinutes() + sec: num; // Date.getSeconds() + ms: num; // Date.getMilliseconds() + dayOfMonth: num; // Date.getDate() + dayOfWeek: num; // Date.getDay() + month: num; // Date.getMonth() + year: num; // Date.getFullYear() + + timezone: num; // (offset in minutes from UTC) + utc: Datetime; // returns the same time in UTC timezone + + toIso(): str; // returns ISO-8601 string +} +``` + +A few examples: + +```TS +let now = Datetime.utcNow(); +log("It is now ${now.month}/${now.dayOfMonth}/${now.year} at ${now.hours}:${now.min}:${now.sec})"); +assert(now.timezone == 0); // UTC + +let t1 = DateTime.fromIso("2023-02-09T06:20:17.573Z"); +log("Timezone is GMT${d.timezone() / 60}"); // output: Timezone is GMT-2 +log("UTC: ${t1.utc.toIso())}"); // output: 2023-02-09T06:21:03.000Z +``` + ### 1.2 Utility Functions diff --git a/docs/docs/04-standard-library/02-std/api-reference.md b/docs/docs/04-standard-library/02-std/api-reference.md index f630cf4c144..13f2a8e9452 100644 --- a/docs/docs/04-standard-library/02-std/api-reference.md +++ b/docs/docs/04-standard-library/02-std/api-reference.md @@ -190,6 +190,245 @@ to parse boolean from. +### Datetime + +Represents a local or UTC date object. + +#### Methods + +| **Name** | **Description** | +| --- | --- | +| toIso | Returns ISO-8601 string. | +| toUtc | Returns a Datetime represents the same date in utc. | + +--- + +##### `toIso` + +```wing +toIso(): str +``` + +Returns ISO-8601 string. + +##### `toUtc` + +```wing +toUtc(): datetime +``` + +Returns a Datetime represents the same date in utc. + +#### Static Functions + +| **Name** | **Description** | +| --- | --- | +| fromComponents | Create a Datetime from Datetime components. | +| fromIso | Create a Datetime from an ISO-8601 string. | +| systemNow | Create a Datetime from local system timezone. | +| utcNow | Create a Datetime from UTC timezone. | + +--- + +##### `fromComponents` + +```wing +datetime.fromComponents(c: DatetimeComponents); +``` + +Create a Datetime from Datetime components. + +###### `c`Required + +- *Type:* DatetimeComponents + +DatetimeComponents. + +--- + +##### `fromIso` + +```wing +datetime.fromIso(iso: str); +``` + +Create a Datetime from an ISO-8601 string. + +###### `iso`Required + +- *Type:* str + +ISO-8601 string. + +--- + +##### `systemNow` + +```wing +datetime.systemNow(); +``` + +Create a Datetime from local system timezone. + +##### `utcNow` + +```wing +datetime.utcNow(); +``` + +Create a Datetime from UTC timezone. + +#### Properties + +| **Name** | **Type** | **Description** | +| --- | --- | --- | +| dayOfMonth | num | Returns the day of month in the local machine time or in utc (1 - 31). | +| dayOfWeek | num | Returns the day in month of the local machine time or in utc (0 - 6). | +| hours | num | Returns the hour of the local machine time or in utc. | +| min | num | Returns the minute of the local machine time or in utc. | +| month | num | Returns the month of the local machine time or in utc (0 - 11). | +| ms | num | Returns the milliseconds of the local machine time or in utc *. | +| sec | num | Returns the seconds of the local machine time or in utc. | +| timestamp | num | Return a timestamp of non-leap year seconds since epoch. | +| timestampMs | num | Return a timestamp of non-leap year milliseconds since epoch. | +| timezone | num | returns the offset in minutes from UTC. | +| year | num | Returns the year of the local machine time or in utc. | + +--- + +##### `dayOfMonth`Required + +```wing +dayOfMonth: num; +``` + +- *Type:* num + +Returns the day of month in the local machine time or in utc (1 - 31). + +--- + +##### `dayOfWeek`Required + +```wing +dayOfWeek: num; +``` + +- *Type:* num + +Returns the day in month of the local machine time or in utc (0 - 6). + +--- + +##### `hours`Required + +```wing +hours: num; +``` + +- *Type:* num + +Returns the hour of the local machine time or in utc. + +--- + +##### `min`Required + +```wing +min: num; +``` + +- *Type:* num + +Returns the minute of the local machine time or in utc. + +--- + +##### `month`Required + +```wing +month: num; +``` + +- *Type:* num + +Returns the month of the local machine time or in utc (0 - 11). + +--- + +##### `ms`Required + +```wing +ms: num; +``` + +- *Type:* num + +Returns the milliseconds of the local machine time or in utc *. + +--- + +##### `sec`Required + +```wing +sec: num; +``` + +- *Type:* num + +Returns the seconds of the local machine time or in utc. + +--- + +##### `timestamp`Required + +```wing +timestamp: num; +``` + +- *Type:* num + +Return a timestamp of non-leap year seconds since epoch. + +--- + +##### `timestampMs`Required + +```wing +timestampMs: num; +``` + +- *Type:* num + +Return a timestamp of non-leap year milliseconds since epoch. + +--- + +##### `timezone`Required + +```wing +timezone: num; +``` + +- *Type:* num + +returns the offset in minutes from UTC. + +--- + +##### `year`Required + +```wing +year: num; +``` + +- *Type:* num + +Returns the year of the local machine time or in utc. + +--- + + ### Duration Represents a length of time. @@ -1812,5 +2051,127 @@ The length of the string. --- +## Structs + +### DatetimeComponents + +interface that is used for setting Datetime date. + +#### Initializer + +```wing +let DatetimeComponents = DatetimeComponents{ ... }; +``` + +#### Properties + +| **Name** | **Type** | **Description** | +| --- | --- | --- | +| day | num | day. | +| hour | num | hours. | +| min | num | minutes. | +| month | num | month. | +| ms | num | milliseconds. | +| sec | num | seconds. | +| tz | num | timezone offset in minutes from UTC. | +| year | num | year. | + +--- + +##### `day`Required + +```wing +day: num; +``` + +- *Type:* num + +day. + +--- + +##### `hour`Required + +```wing +hour: num; +``` + +- *Type:* num + +hours. + +--- + +##### `min`Required + +```wing +min: num; +``` + +- *Type:* num + +minutes. + +--- + +##### `month`Required + +```wing +month: num; +``` + +- *Type:* num + +month. + +--- + +##### `ms`Required + +```wing +ms: num; +``` + +- *Type:* num + +milliseconds. + +--- + +##### `sec`Required + +```wing +sec: num; +``` + +- *Type:* num + +seconds. + +--- + +##### `tz`Required + +```wing +tz: num; +``` + +- *Type:* num + +timezone offset in minutes from UTC. + +--- + +##### `year`Required + +```wing +year: num; +``` + +- *Type:* num + +year. + +--- diff --git a/examples/tests/sdk_tests/std/datetime.w b/examples/tests/sdk_tests/std/datetime.w new file mode 100644 index 00000000000..65f95260bd6 --- /dev/null +++ b/examples/tests/sdk_tests/std/datetime.w @@ -0,0 +1,75 @@ +bring cloud; +bring util; +bring math; + +let d1 = datetime.utcNow(); +let d2 = datetime.systemNow(); + +assert(math.floor(d2.timestamp) == math.floor(d1.timestamp)); + +let d3 = datetime.fromIso("2023-07-18T20:18:25.177+03:00"); + +assert(d3.timestampMs == 1689700705177); +assert(d3.hours == 17); +assert(d3.min == 18); +assert(d3.sec == 25); +assert(d3.ms == 177); +assert(d3.dayOfMonth == 18); +assert(d3.dayOfWeek == 2); +assert(d3.month == 6); +assert(d3.year == 2023); + + +let d4 = datetime.fromComponents(year: 2023, month: 6, day: 18, hour: 19, min: 18, sec: 25, ms: 177, tz: -120); + +assert(d4.timezone == -120); +assert(d4.timestampMs == 1689700705177); +assert(d4.hours == 19); +assert(d4.min == 18); +assert(d4.sec == 25); +assert(d4.ms == 177); +assert(d4.dayOfMonth == 18); +assert(d4.dayOfWeek == 2); +assert(d4.month == 6); +assert(d4.year == 2023); + +assert(d4.toUtc().hours == (d4.hours + (d4.timezone / 60))); + +test "inflight datetime" { + let d5 = datetime.utcNow(); + let d6 = datetime.systemNow(); + + assert(d2.timestamp == d1.timestamp); + + let d7 = datetime.fromIso("2023-07-18T20:18:25.177-03:00"); + let d8 = datetime.fromComponents(year: 2023, month: 6, day: 18, hour: 20, min: 18, sec: 25, ms: 177, tz: 180); // UTC-3:00 + + + assert(d7.timestampMs == 1689722305177); + assert(d7.hours == 23); + assert(d7.min == 18); + assert(d7.sec == 25); + assert(d7.ms == 177); + assert(d7.dayOfMonth == 18); + assert(d7.dayOfWeek == 2); + assert(d7.month == 6); + assert(d7.year == 2023); + assert(d8.hours == 20); + + assert(math.floor(d7.timestamp) == math.floor(d8.timestamp)); + assert(d4.toUtc().hours == (d4.hours + (d4.timezone / 60))); + assert(d8.toUtc().hours == (d8.hours + (d8.timezone / 60))); + + + let beforeSleep = datetime.systemNow(); + util.sleep(1s); + assert(math.floor(datetime.systemNow().timestamp - beforeSleep.timestamp) == 1); + +} + + + + + + + diff --git a/libs/wingc/src/type_check.rs b/libs/wingc/src/type_check.rs index 0fc972d24bb..36a1b5b63c7 100644 --- a/libs/wingc/src/type_check.rs +++ b/libs/wingc/src/type_check.rs @@ -3669,6 +3669,10 @@ impl<'a> TypeChecker<'a> { name: "Duration".to_string(), span: symbol.span.clone(), }), + "datetime" => Some(Symbol { + name: "Datetime".to_string(), + span: symbol.span.clone(), + }), "str" => Some(Symbol { name: "String".to_string(), span: symbol.span.clone(), @@ -4422,6 +4426,7 @@ pub fn fully_qualify_std_type(type_: &str) -> std::string::String { let type_name = match type_name { "str" => "String", "duration" => "Duration", + "datetime" => "Datetime", "bool" => "Boolean", "num" => "Number", _ => type_name, diff --git a/libs/wingc/src/type_check/jsii_importer.rs b/libs/wingc/src/type_check/jsii_importer.rs index a6abe2d29a2..bea9848fd17 100644 --- a/libs/wingc/src/type_check/jsii_importer.rs +++ b/libs/wingc/src/type_check/jsii_importer.rs @@ -90,7 +90,7 @@ impl<'a> JsiiImporter<'a> { PrimitiveType::Boolean => self.wing_types.bool(), PrimitiveType::Any => self.wing_types.anything(), PrimitiveType::Json => self.wing_types.json(), - PrimitiveType::Date => self.wing_types.anything(), // TODO: https://github.com/winglang/wing/issues/2102 + PrimitiveType::Date => self.wing_types.anything(), // TODO: https://github.com/winglang/wing/issues/3569 }, TypeReference::NamedTypeReference(named_ref) => { let type_fqn = &named_ref.fqn; diff --git a/libs/wingsdk/src/std/datetime.ts b/libs/wingsdk/src/std/datetime.ts new file mode 100644 index 00000000000..e88ff0d1bea --- /dev/null +++ b/libs/wingsdk/src/std/datetime.ts @@ -0,0 +1,227 @@ +import { Code, InflightClient } from "../core"; + +/** + * interface that is used for setting Datetime date + */ +export interface DatetimeComponents { + /** + * year + */ + readonly year: number; + /** + * month + */ + readonly month: number; + /** + * day + */ + readonly day: number; + /** + * hours + */ + readonly hour: number; + /** + * minutes + */ + readonly min: number; + /** + * seconds + */ + readonly sec: number; + /** + * milliseconds + */ + readonly ms: number; + /** + * timezone offset in minutes from UTC + */ + readonly tz: number; +} + +/** + * Represents a local or UTC date object + * @wingType datetime + */ +export class Datetime { + /** + * @internal + */ + public static _toInflightType(): Code { + return InflightClient.forType(__filename, this.name); + } + /** + * Create a Datetime from UTC timezone + * + * @returns a new `Datetime` from current time in UTC timezone + */ + public static utcNow(): Datetime { + return new Datetime(); + } + + /** + * Create a Datetime from local system timezone + * + * @returns a new `Datetime` from current time in system timezone + */ + public static systemNow(): Datetime { + const date = new Date(); + date.setTime(date.getTime() - date.getTimezoneOffset() * 60 * 1000); + + return new Datetime(date, date.getTimezoneOffset()); + } + + /** + * Create a Datetime from an ISO-8601 string + * + * @returns a new `Datetime` in UTC timezone + * @param iso ISO-8601 string + */ + public static fromIso(iso: string): Datetime { + return new Datetime(new Date(iso)); + } + + /** + * Create a Datetime from Datetime components + * + * @param c DatetimeComponents + * @returns a new `Datetime` + */ + public static fromComponents(c: DatetimeComponents): Datetime { + const date = new Date( + Date.UTC(c.year, c.month, c.day, c.hour, c.min, c.sec, c.ms) + ); + + return new Datetime(date, c.tz); + } + + /** @internal */ + private readonly _date: Date; + /** @internal */ + private readonly _timezoneOffset: number = 0; + + private constructor(date: Date = new Date(), timezoneOffset = 0) { + this._date = date; + this._timezoneOffset = timezoneOffset; + } + + /** + * Return a timestamp of non-leap year seconds since epoch + * + * @returns a number representing the current timestamp in seconds + */ + public get timestamp(): number { + return this.timestampMs / 1000; + } + + /** + * Return a timestamp of non-leap year milliseconds since epoch + * + * @returns a number representing the current timestamp in milliseconds + */ + public get timestampMs(): number { + // since converting between timezones/ declaring a date in a timezone other than the local or UTC + // isn't native to js, we keep the date in a UTC time, then retrieving back the the original timestamp, + // this way the date components (hours, month, day, minutes, etc..) are persistent + // and retrieved in the same order for all of the different constructing methods and the timestamp is correct. + return this._date.valueOf() + this._timezoneOffset * 60 * 1000; + } + + /** + * Returns the hour of the local machine time or in utc + * + * @returns a number representing the datetime's hour + */ + public get hours(): number { + return this._date.getUTCHours(); + } + + /** + * Returns the minute of the local machine time or in utc + * + * @returns a number representing the datetime's minute + */ + public get min(): number { + return this._date.getUTCMinutes(); + } + + /** + * Returns the seconds of the local machine time or in utc + * + * @returns a number representing the datetime's seconds + */ + public get sec(): number { + return this._date.getUTCSeconds(); + } + + /** + * Returns the milliseconds of the local machine time or in utc + * * + * @returns a number representing the datetime's milliseconds + */ + public get ms(): number { + return this._date.getUTCMilliseconds(); + } + + /** + * Returns the day of month in the local machine time or in utc (1 - 31) + * + * @returns a number representing the datetime's day of month + */ + public get dayOfMonth(): number { + return this._date.getUTCDate(); + } + + /** + * Returns the day in month of the local machine time or in utc (0 - 6) + * + * @returns a number representing the datetime's day of week + */ + public get dayOfWeek(): number { + return this._date.getUTCDay(); + } + + /** + * Returns the month of the local machine time or in utc (0 - 11) + * + * @returns a number representing the datetime's month + */ + public get month(): number { + return this._date.getUTCMonth(); + } + + /** + * Returns the year of the local machine time or in utc + * + * @returns a number representing the datetime's year + */ + public get year(): number { + return this._date.getUTCFullYear(); + } + + /** + * returns the offset in minutes from UTC + * + * @returns a number representing the datetime's offset in minutes from UTC + */ + public get timezone(): number { + return this._timezoneOffset; + } + + /** + * Returns a Datetime represents the same date in utc + * + * @returns a datetime representing the datetime's date in UTC + */ + public toUtc(): Datetime { + return new Datetime(new Date(this.timestampMs)); + } + + /** + * Returns ISO-8601 string + * + * @returns a ISO-8601 string representation of the datetime + */ + public toIso(): string { + return new Date(this.timestampMs).toISOString(); + } +} diff --git a/libs/wingsdk/src/std/index.ts b/libs/wingsdk/src/std/index.ts index fe6ed2b4460..f135327b652 100644 --- a/libs/wingsdk/src/std/index.ts +++ b/libs/wingsdk/src/std/index.ts @@ -1,5 +1,6 @@ export * from "./array"; export * from "./bool"; +export * from "./datetime"; export * from "./duration"; export * from "./generics"; export * from "./json"; diff --git a/tools/hangar/__snapshots__/test_corpus/sdk_tests/std/datetime.w_compile_tf-aws.md b/tools/hangar/__snapshots__/test_corpus/sdk_tests/std/datetime.w_compile_tf-aws.md new file mode 100644 index 00000000000..9bf11bbe3f1 --- /dev/null +++ b/tools/hangar/__snapshots__/test_corpus/sdk_tests/std/datetime.w_compile_tf-aws.md @@ -0,0 +1,249 @@ +# [datetime.w](../../../../../../examples/tests/sdk_tests/std/datetime.w) | compile | tf-aws + +## inflight.$Closure1.js +```js +module.exports = function({ $_d4_toUtc____hours, $d1_timestamp, $d2_timestamp, $d4_hours, $d4_timezone, $math_Util, $std_Datetime, $std_Duration, $util_Util }) { + class $Closure1 { + constructor({ }) { + const $obj = (...args) => this.handle(...args); + Object.setPrototypeOf($obj, this); + return $obj; + } + async handle() { + const d5 = (await $std_Datetime.utcNow()); + const d6 = (await $std_Datetime.systemNow()); + {((cond) => {if (!cond) throw new Error("assertion failed: d2.timestamp == d1.timestamp")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })($d2_timestamp,$d1_timestamp)))}; + const d7 = (await $std_Datetime.fromIso("2023-07-18T20:18:25.177-03:00")); + const d8 = (await $std_Datetime.fromComponents({ year: 2023, month: 6, day: 18, hour: 20, min: 18, sec: 25, ms: 177, tz: 180 })); + {((cond) => {if (!cond) throw new Error("assertion failed: d7.timestampMs == 1689722305177")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(d7.timestampMs,1689722305177)))}; + {((cond) => {if (!cond) throw new Error("assertion failed: d7.hours == 23")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(d7.hours,23)))}; + {((cond) => {if (!cond) throw new Error("assertion failed: d7.min == 18")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(d7.min,18)))}; + {((cond) => {if (!cond) throw new Error("assertion failed: d7.sec == 25")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(d7.sec,25)))}; + {((cond) => {if (!cond) throw new Error("assertion failed: d7.ms == 177")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(d7.ms,177)))}; + {((cond) => {if (!cond) throw new Error("assertion failed: d7.dayOfMonth == 18")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(d7.dayOfMonth,18)))}; + {((cond) => {if (!cond) throw new Error("assertion failed: d7.dayOfWeek == 2")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(d7.dayOfWeek,2)))}; + {((cond) => {if (!cond) throw new Error("assertion failed: d7.month == 6")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(d7.month,6)))}; + {((cond) => {if (!cond) throw new Error("assertion failed: d7.year == 2023")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(d7.year,2023)))}; + {((cond) => {if (!cond) throw new Error("assertion failed: d8.hours == 20")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(d8.hours,20)))}; + {((cond) => {if (!cond) throw new Error("assertion failed: math.floor(d7.timestamp) == math.floor(d8.timestamp)")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })((await $math_Util.floor(d7.timestamp)),(await $math_Util.floor(d8.timestamp)))))}; + {((cond) => {if (!cond) throw new Error("assertion failed: d4.toUtc().hours == (d4.hours + (d4.timezone / 60))")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })($_d4_toUtc____hours,($d4_hours + ($d4_timezone / 60)))))}; + {((cond) => {if (!cond) throw new Error("assertion failed: d8.toUtc().hours == (d8.hours + (d8.timezone / 60))")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })((await d8.toUtc()).hours,(d8.hours + (d8.timezone / 60)))))}; + const beforeSleep = (await $std_Datetime.systemNow()); + (await $util_Util.sleep((await $std_Duration.fromSeconds(1)))); + {((cond) => {if (!cond) throw new Error("assertion failed: math.floor(datetime.systemNow().timestamp - beforeSleep.timestamp) == 1")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })((await $math_Util.floor(((await $std_Datetime.systemNow()).timestamp - beforeSleep.timestamp))),1)))}; + } + } + return $Closure1; +} + +``` + +## main.tf.json +```json +{ + "//": { + "metadata": { + "backend": "local", + "stackName": "root", + "version": "0.17.0" + }, + "outputs": { + "root": { + "Default": { + "cloud.TestRunner": { + "TestFunctionArns": "WING_TEST_RUNNER_FUNCTION_ARNS" + } + } + } + } + }, + "output": { + "WING_TEST_RUNNER_FUNCTION_ARNS": { + "value": "[[\"root/Default/Default/test:inflight datetime\",\"${aws_lambda_function.testinflightdatetime_Handler_CCA19CA1.arn}\"]]" + } + }, + "provider": { + "aws": [ + {} + ] + }, + "resource": { + "aws_iam_role": { + "testinflightdatetime_Handler_IamRole_F29772B9": { + "//": { + "metadata": { + "path": "root/Default/Default/test:inflight datetime/Handler/IamRole", + "uniqueId": "testinflightdatetime_Handler_IamRole_F29772B9" + } + }, + "assume_role_policy": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Action\":\"sts:AssumeRole\",\"Principal\":{\"Service\":\"lambda.amazonaws.com\"},\"Effect\":\"Allow\"}]}" + } + }, + "aws_iam_role_policy": { + "testinflightdatetime_Handler_IamRolePolicy_BA52AB3F": { + "//": { + "metadata": { + "path": "root/Default/Default/test:inflight datetime/Handler/IamRolePolicy", + "uniqueId": "testinflightdatetime_Handler_IamRolePolicy_BA52AB3F" + } + }, + "policy": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Action\":\"none:null\",\"Resource\":\"*\"}]}", + "role": "${aws_iam_role.testinflightdatetime_Handler_IamRole_F29772B9.name}" + } + }, + "aws_iam_role_policy_attachment": { + "testinflightdatetime_Handler_IamRolePolicyAttachment_BBFA8051": { + "//": { + "metadata": { + "path": "root/Default/Default/test:inflight datetime/Handler/IamRolePolicyAttachment", + "uniqueId": "testinflightdatetime_Handler_IamRolePolicyAttachment_BBFA8051" + } + }, + "policy_arn": "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", + "role": "${aws_iam_role.testinflightdatetime_Handler_IamRole_F29772B9.name}" + } + }, + "aws_lambda_function": { + "testinflightdatetime_Handler_CCA19CA1": { + "//": { + "metadata": { + "path": "root/Default/Default/test:inflight datetime/Handler/Default", + "uniqueId": "testinflightdatetime_Handler_CCA19CA1" + } + }, + "environment": { + "variables": { + "WING_FUNCTION_NAME": "Handler-c8211bab", + "WING_TARGET": "tf-aws" + } + }, + "function_name": "Handler-c8211bab", + "handler": "index.handler", + "publish": true, + "role": "${aws_iam_role.testinflightdatetime_Handler_IamRole_F29772B9.arn}", + "runtime": "nodejs18.x", + "s3_bucket": "${aws_s3_bucket.Code.bucket}", + "s3_key": "${aws_s3_object.testinflightdatetime_Handler_S3Object_972D133E.key}", + "timeout": 30, + "vpc_config": { + "security_group_ids": [], + "subnet_ids": [] + } + } + }, + "aws_s3_bucket": { + "Code": { + "//": { + "metadata": { + "path": "root/Default/Code", + "uniqueId": "Code" + } + }, + "bucket_prefix": "code-c84a50b1-" + } + }, + "aws_s3_object": { + "testinflightdatetime_Handler_S3Object_972D133E": { + "//": { + "metadata": { + "path": "root/Default/Default/test:inflight datetime/Handler/S3Object", + "uniqueId": "testinflightdatetime_Handler_S3Object_972D133E" + } + }, + "bucket": "${aws_s3_bucket.Code.bucket}", + "key": "", + "source": "" + } + } + } +} +``` + +## preflight.js +```js +const $stdlib = require('@winglang/sdk'); +const $outdir = process.env.WING_SYNTH_DIR ?? "."; +const std = $stdlib.std; +const $wing_is_test = process.env.WING_IS_TEST === "true"; +const cloud = require('@winglang/sdk').cloud; +const util = require('@winglang/sdk').util; +const math = require('@winglang/sdk').math; +class $Root extends $stdlib.std.Resource { + constructor(scope, id) { + super(scope, id); + class $Closure1 extends $stdlib.std.Resource { + constructor(scope, id, ) { + super(scope, id); + this._addInflightOps("handle", "$inflight_init"); + this.display.hidden = true; + } + static _toInflightType(context) { + return $stdlib.core.NodeJsCode.fromInline(` + require("./inflight.$Closure1.js")({ + $_d4_toUtc____hours: ${context._lift((d4.toUtc()).hours)}, + $d1_timestamp: ${context._lift(d1.timestamp)}, + $d2_timestamp: ${context._lift(d2.timestamp)}, + $d4_hours: ${context._lift(d4.hours)}, + $d4_timezone: ${context._lift(d4.timezone)}, + $math_Util: ${context._lift(math.Util)}, + $std_Datetime: ${context._lift(std.Datetime)}, + $std_Duration: ${context._lift(std.Duration)}, + $util_Util: ${context._lift(util.Util)}, + }) + `); + } + _toInflight() { + return $stdlib.core.NodeJsCode.fromInline(` + (await (async () => { + const $Closure1Client = ${$Closure1._toInflightType(this).text}; + const client = new $Closure1Client({ + }); + if (client.$inflight_init) { await client.$inflight_init(); } + return client; + })()) + `); + } + _registerBind(host, ops) { + if (ops.includes("handle")) { + $Closure1._registerBindObject((d4.toUtc()).hours, host, []); + $Closure1._registerBindObject(d1.timestamp, host, []); + $Closure1._registerBindObject(d2.timestamp, host, []); + $Closure1._registerBindObject(d4.hours, host, []); + $Closure1._registerBindObject(d4.timezone, host, []); + } + super._registerBind(host, ops); + } + } + const d1 = (std.Datetime.utcNow()); + const d2 = (std.Datetime.systemNow()); + {((cond) => {if (!cond) throw new Error("assertion failed: math.floor(d2.timestamp) == math.floor(d1.timestamp)")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })((math.Util.floor(d2.timestamp)),(math.Util.floor(d1.timestamp)))))}; + const d3 = (std.Datetime.fromIso("2023-07-18T20:18:25.177+03:00")); + {((cond) => {if (!cond) throw new Error("assertion failed: d3.timestampMs == 1689700705177")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(d3.timestampMs,1689700705177)))}; + {((cond) => {if (!cond) throw new Error("assertion failed: d3.hours == 17")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(d3.hours,17)))}; + {((cond) => {if (!cond) throw new Error("assertion failed: d3.min == 18")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(d3.min,18)))}; + {((cond) => {if (!cond) throw new Error("assertion failed: d3.sec == 25")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(d3.sec,25)))}; + {((cond) => {if (!cond) throw new Error("assertion failed: d3.ms == 177")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(d3.ms,177)))}; + {((cond) => {if (!cond) throw new Error("assertion failed: d3.dayOfMonth == 18")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(d3.dayOfMonth,18)))}; + {((cond) => {if (!cond) throw new Error("assertion failed: d3.dayOfWeek == 2")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(d3.dayOfWeek,2)))}; + {((cond) => {if (!cond) throw new Error("assertion failed: d3.month == 6")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(d3.month,6)))}; + {((cond) => {if (!cond) throw new Error("assertion failed: d3.year == 2023")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(d3.year,2023)))}; + const d4 = (std.Datetime.fromComponents({ year: 2023, month: 6, day: 18, hour: 19, min: 18, sec: 25, ms: 177, tz: (-120) })); + {((cond) => {if (!cond) throw new Error("assertion failed: d4.timezone == -120")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(d4.timezone,(-120))))}; + {((cond) => {if (!cond) throw new Error("assertion failed: d4.timestampMs == 1689700705177")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(d4.timestampMs,1689700705177)))}; + {((cond) => {if (!cond) throw new Error("assertion failed: d4.hours == 19")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(d4.hours,19)))}; + {((cond) => {if (!cond) throw new Error("assertion failed: d4.min == 18")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(d4.min,18)))}; + {((cond) => {if (!cond) throw new Error("assertion failed: d4.sec == 25")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(d4.sec,25)))}; + {((cond) => {if (!cond) throw new Error("assertion failed: d4.ms == 177")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(d4.ms,177)))}; + {((cond) => {if (!cond) throw new Error("assertion failed: d4.dayOfMonth == 18")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(d4.dayOfMonth,18)))}; + {((cond) => {if (!cond) throw new Error("assertion failed: d4.dayOfWeek == 2")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(d4.dayOfWeek,2)))}; + {((cond) => {if (!cond) throw new Error("assertion failed: d4.month == 6")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(d4.month,6)))}; + {((cond) => {if (!cond) throw new Error("assertion failed: d4.year == 2023")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(d4.year,2023)))}; + {((cond) => {if (!cond) throw new Error("assertion failed: d4.toUtc().hours == (d4.hours + (d4.timezone / 60))")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })((d4.toUtc()).hours,(d4.hours + (d4.timezone / 60)))))}; + this.node.root.new("@winglang/sdk.std.Test",std.Test,this,"test:inflight datetime",new $Closure1(this,"$Closure1")); + } +} +const $App = $stdlib.core.App.for(process.env.WING_TARGET); +new $App({ outdir: $outdir, name: "datetime", rootConstruct: $Root, plugins: $plugins, isTestEnvironment: $wing_is_test }).synth(); + +``` + diff --git a/tools/hangar/__snapshots__/test_corpus/sdk_tests/std/datetime.w_test_sim.md b/tools/hangar/__snapshots__/test_corpus/sdk_tests/std/datetime.w_test_sim.md new file mode 100644 index 00000000000..f97bc041428 --- /dev/null +++ b/tools/hangar/__snapshots__/test_corpus/sdk_tests/std/datetime.w_test_sim.md @@ -0,0 +1,12 @@ +# [datetime.w](../../../../../../examples/tests/sdk_tests/std/datetime.w) | test | sim + +## stdout.log +```log +pass ─ datetime.wsim » root/env0/test:inflight datetime + + +Tests 1 passed (1) +Test Files 1 passed (1) +Duration +``` +