-
Notifications
You must be signed in to change notification settings - Fork 282
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[PORT] Add getNextViableDate, getPreviousViableDate, getNextViableTim…
…e, getPreviousViableTime pre-built functions (#2601) * init * init * init * init * init * init * init * init * add comments * refine * refine * fix error * refine * small fix * retrigger * add date functions * solve conflicts * retrigger * fix incorrect function description * fix type signatures Co-authored-by: hond <[email protected]>
- Loading branch information
1 parent
a8b0dc9
commit 87c0be3
Showing
11 changed files
with
405 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
94 changes: 94 additions & 0 deletions
94
libraries/adaptive-expressions/src/builtinFunctions/getNextViableDate.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
/** | ||
* @module adaptive-expressions | ||
*/ | ||
/** | ||
* Copyright (c) Microsoft Corporation. All rights reserved. | ||
* Licensed under the MIT License. | ||
*/ | ||
|
||
import { ExpressionEvaluator } from '../expressionEvaluator'; | ||
import { Expression } from '../expression'; | ||
import { ReturnType } from '../returnType'; | ||
import { ExpressionType } from '../expressionType'; | ||
import { FunctionUtils } from '../functionUtils'; | ||
import { MemoryInterface } from '../memory/memoryInterface'; | ||
import { Options } from '../options'; | ||
import { TimeZoneConverter } from '../timeZoneConverter'; | ||
import { tz } from 'moment-timezone'; | ||
import moment from 'moment'; | ||
import {TimexProperty} from '@microsoft/recognizers-text-data-types-timex-expression'; | ||
|
||
/** | ||
* Return the next viable date of a timex expression based on the current date and user's timezone. | ||
*/ | ||
export class GetNextViableDate extends ExpressionEvaluator { | ||
public constructor(){ | ||
super(ExpressionType.GetNextViableDate, GetNextViableDate.evaluator, ReturnType.String, FunctionUtils.validateUnaryOrBinaryString); | ||
} | ||
|
||
private static evaluator(expr: Expression, state: MemoryInterface, options: Options): {value: any; error: string} { | ||
let parsed: TimexProperty; | ||
let value: string; | ||
let error: string; | ||
let args: any[]; | ||
const currentTime = moment(new Date().toISOString()); | ||
let validYear = 0; | ||
let validMonth = 0; | ||
let validDay = 0; | ||
let convertedDateTime: moment.Moment; | ||
({args, error} = FunctionUtils.evaluateChildren(expr, state, options)); | ||
if (!error) { | ||
({timexProperty: parsed, error: error} = FunctionUtils.parseTimexProperty(args[0])); | ||
} | ||
|
||
if (parsed && !error) { | ||
if (parsed.year || !parsed.month || !parsed.dayOfMonth) { | ||
error = `${args[0]} must be a timex string which only contains month and day-of-month, for example: 'XXXX-10-31'.`; | ||
} | ||
} | ||
|
||
if (!error) { | ||
if (args.length === 2 && typeof args[1] === 'string') { | ||
const timeZone: string = TimeZoneConverter .windowsToIana(args[1]); | ||
if (!TimeZoneConverter.verifyTimeZoneStr(timeZone)) { | ||
error = `${args[1]} is not a valid timezone`; | ||
} | ||
|
||
if (!error) { | ||
convertedDateTime = tz(currentTime.utc(), timeZone); | ||
} | ||
} else { | ||
convertedDateTime = currentTime.utc(); | ||
} | ||
} | ||
|
||
if (!error) { | ||
const year = convertedDateTime.year(); | ||
const month = convertedDateTime.month() + 1; | ||
const dayOfMonth = convertedDateTime.date(); | ||
|
||
if (parsed.month > month || (parsed.month === month && parsed.dayOfMonth >= dayOfMonth)) { | ||
validYear = year; | ||
} else { | ||
validYear = year + 1; | ||
} | ||
|
||
validMonth = parsed.month; | ||
validDay = parsed.dayOfMonth; | ||
|
||
if (validMonth === 2 && validDay === 29) { | ||
while (!GetNextViableDate.leapYear(validYear)) { | ||
validYear += 1; | ||
} | ||
} | ||
} | ||
|
||
value = TimexProperty.fromDate(new Date(validYear, validMonth - 1, validDay)).timex; | ||
return {value, error}; | ||
} | ||
|
||
private static leapYear(year: number): boolean | ||
{ | ||
return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0); | ||
} | ||
} |
83 changes: 83 additions & 0 deletions
83
libraries/adaptive-expressions/src/builtinFunctions/getNextViableTime.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
/** | ||
* @module adaptive-expressions | ||
*/ | ||
/** | ||
* Copyright (c) Microsoft Corporation. All rights reserved. | ||
* Licensed under the MIT License. | ||
*/ | ||
|
||
import { ExpressionEvaluator } from '../expressionEvaluator'; | ||
import { Expression } from '../expression'; | ||
import { ReturnType } from '../returnType'; | ||
import { ExpressionType } from '../expressionType'; | ||
import { FunctionUtils } from '../functionUtils'; | ||
import { MemoryInterface } from '../memory/memoryInterface'; | ||
import { Options } from '../options'; | ||
import { TimeZoneConverter } from '../timeZoneConverter'; | ||
import { tz } from 'moment-timezone'; | ||
import moment from 'moment'; | ||
import {TimexProperty, Time} from '@microsoft/recognizers-text-data-types-timex-expression'; | ||
/** | ||
* Return the next viable time of a timex expression based on the current time and user's timezone. | ||
*/ | ||
export class GetNextViableTime extends ExpressionEvaluator { | ||
public constructor(){ | ||
super(ExpressionType.GetNextViableTime, GetNextViableTime.evaluator, ReturnType.String, FunctionUtils.validateUnaryOrBinaryString); | ||
} | ||
|
||
private static evaluator(expr: Expression, state: MemoryInterface, options: Options): {value: any; error: string} { | ||
let parsed: TimexProperty; | ||
let value: string; | ||
let error: string; | ||
let args: any[]; | ||
const currentTime = moment(new Date().toISOString()); | ||
let validHour = 0; | ||
let validMinute = 0; | ||
let validSecond = 0; | ||
let convertedDateTime: moment.Moment; | ||
const formatRegex = /TXX:[0-5][0-9]:[0-5][0-9]/g; | ||
({args, error} = FunctionUtils.evaluateChildren(expr, state, options)); | ||
if(!error) { | ||
if (!formatRegex.test(args[0] as string)) { | ||
error = `${args[0]} must be a timex string which only contains minutes and seconds, for example: 'TXX:15:28'` | ||
} | ||
} | ||
|
||
if (!error) { | ||
if (args.length === 2 && typeof args[1] === 'string') { | ||
const timeZone: string = TimeZoneConverter .windowsToIana(args[1]); | ||
if (!TimeZoneConverter.verifyTimeZoneStr(timeZone)) { | ||
error = `${args[1]} is not a valid timezone`; | ||
} | ||
|
||
if (!error) { | ||
convertedDateTime = tz(currentTime.utc(), timeZone); | ||
} | ||
} else { | ||
convertedDateTime = currentTime.utc(); | ||
} | ||
} | ||
|
||
if (!error) { | ||
({timexProperty: parsed, error: error} = FunctionUtils.parseTimexProperty((args[0] as string).replace('XX', '00'))); | ||
} | ||
|
||
if (!error) { | ||
const hour = convertedDateTime.hour(); | ||
const minute = convertedDateTime.minute(); | ||
const second = convertedDateTime.second(); | ||
|
||
if (parsed.minute > minute || (parsed.minute === minute && parsed.second >= second)) { | ||
validHour = hour; | ||
} else { | ||
validHour = hour + 1; | ||
} | ||
|
||
validMinute = parsed.minute; | ||
validSecond = parsed.second; | ||
} | ||
|
||
value = TimexProperty.fromTime(new Time(validHour, validMinute, validSecond)).timex; | ||
return {value, error}; | ||
} | ||
} |
94 changes: 94 additions & 0 deletions
94
libraries/adaptive-expressions/src/builtinFunctions/getPreviousViableDate.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
/** | ||
* @module adaptive-expressions | ||
*/ | ||
/** | ||
* Copyright (c) Microsoft Corporation. All rights reserved. | ||
* Licensed under the MIT License. | ||
*/ | ||
|
||
import { ExpressionEvaluator } from '../expressionEvaluator'; | ||
import { Expression } from '../expression'; | ||
import { ReturnType } from '../returnType'; | ||
import { ExpressionType } from '../expressionType'; | ||
import { FunctionUtils } from '../functionUtils'; | ||
import { MemoryInterface } from '../memory/memoryInterface'; | ||
import { Options } from '../options'; | ||
import { TimeZoneConverter } from '../timeZoneConverter'; | ||
import { tz } from 'moment-timezone'; | ||
import moment from 'moment'; | ||
import {TimexProperty} from '@microsoft/recognizers-text-data-types-timex-expression'; | ||
|
||
/** | ||
* Return the previous viable date of a timex expression based on the current date and user's timezone. | ||
*/ | ||
export class GetPreviousViableDate extends ExpressionEvaluator { | ||
public constructor(){ | ||
super(ExpressionType.GetPreviousViableDate, GetPreviousViableDate.evaluator, ReturnType.String, FunctionUtils.validateUnaryOrBinaryString); | ||
} | ||
|
||
private static evaluator(expr: Expression, state: MemoryInterface, options: Options): {value: any; error: string} { | ||
let parsed: TimexProperty; | ||
let value: string; | ||
let error: string; | ||
let args: any[]; | ||
const currentTime = moment(new Date().toISOString()); | ||
let validYear = 0; | ||
let validMonth = 0; | ||
let validDay = 0; | ||
let convertedDateTime: moment.Moment; | ||
({args, error} = FunctionUtils.evaluateChildren(expr, state, options)); | ||
if (!error) { | ||
({timexProperty: parsed, error: error} = FunctionUtils.parseTimexProperty(args[0])); | ||
} | ||
|
||
if (parsed && !error) { | ||
if (parsed.year || !parsed.month || !parsed.dayOfMonth) { | ||
error = `${args[0]} must be a timex string which only contains month and day-of-month, for example: 'XXXX-10-31'.`; | ||
} | ||
} | ||
|
||
if (!error) { | ||
if (args.length === 2 && typeof args[1] === 'string') { | ||
const timeZone: string = TimeZoneConverter .windowsToIana(args[1]); | ||
if (!TimeZoneConverter.verifyTimeZoneStr(timeZone)) { | ||
error = `${args[1]} is not a valid timezone`; | ||
} | ||
|
||
if (!error) { | ||
convertedDateTime = tz(currentTime.utc(), timeZone); | ||
} | ||
} else { | ||
convertedDateTime = currentTime.utc(); | ||
} | ||
} | ||
|
||
if (!error) { | ||
const year = convertedDateTime.year(); | ||
const month = convertedDateTime.month() + 1; | ||
const dayOfMonth = convertedDateTime.date(); | ||
|
||
if (parsed.month <= month || (parsed.month === month && parsed.dayOfMonth < dayOfMonth)) { | ||
validYear = year; | ||
} else { | ||
validYear = year - 1; | ||
} | ||
|
||
validMonth = parsed.month; | ||
validDay = parsed.dayOfMonth; | ||
|
||
if (validMonth === 2 && validDay === 29) { | ||
while (!GetPreviousViableDate.leapYear(validYear)) { | ||
validYear -= 1; | ||
} | ||
} | ||
} | ||
|
||
value = TimexProperty.fromDate(new Date(validYear, validMonth - 1, validDay)).timex; | ||
return {value, error}; | ||
} | ||
|
||
private static leapYear(year: number): boolean | ||
{ | ||
return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0); | ||
} | ||
} |
83 changes: 83 additions & 0 deletions
83
libraries/adaptive-expressions/src/builtinFunctions/getPreviousViableTime.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
/** | ||
* @module adaptive-expressions | ||
*/ | ||
/** | ||
* Copyright (c) Microsoft Corporation. All rights reserved. | ||
* Licensed under the MIT License. | ||
*/ | ||
|
||
import { ExpressionEvaluator } from '../expressionEvaluator'; | ||
import { Expression } from '../expression'; | ||
import { ReturnType } from '../returnType'; | ||
import { ExpressionType } from '../expressionType'; | ||
import { FunctionUtils } from '../functionUtils'; | ||
import { MemoryInterface } from '../memory/memoryInterface'; | ||
import { Options } from '../options'; | ||
import { TimeZoneConverter } from '../timeZoneConverter'; | ||
import { tz } from 'moment-timezone'; | ||
import moment from 'moment'; | ||
import {TimexProperty, Time} from '@microsoft/recognizers-text-data-types-timex-expression'; | ||
/** | ||
* Return the previous viable time of a timex expression based on the current time and user's timezone. | ||
*/ | ||
export class GetPreviousViableTime extends ExpressionEvaluator { | ||
public constructor(){ | ||
super(ExpressionType.GetPreviousViableTime, GetPreviousViableTime.evaluator, ReturnType.String, FunctionUtils.validateUnaryOrBinaryString); | ||
} | ||
|
||
private static evaluator(expr: Expression, state: MemoryInterface, options: Options): {value: any; error: string} { | ||
let parsed: TimexProperty; | ||
let value: string; | ||
let error: string; | ||
let args: any[]; | ||
const currentTime = moment(new Date().toISOString()); | ||
let validHour = 0; | ||
let validMinute = 0; | ||
let validSecond = 0; | ||
let convertedDateTime: moment.Moment; | ||
const formatRegex = /TXX:[0-5][0-9]:[0-5][0-9]/g; | ||
({args, error} = FunctionUtils.evaluateChildren(expr, state, options)); | ||
if(!error) { | ||
if (!formatRegex.test(args[0] as string)) { | ||
error = `${args[0]} must be a timex string which only contains minutes and seconds, for example: 'TXX:15:28'` | ||
} | ||
} | ||
|
||
if (!error) { | ||
if (args.length === 2 && typeof args[1] === 'string') { | ||
const timeZone: string = TimeZoneConverter .windowsToIana(args[1]); | ||
if (!TimeZoneConverter.verifyTimeZoneStr(timeZone)) { | ||
error = `${args[1]} is not a valid timezone`; | ||
} | ||
|
||
if (!error) { | ||
convertedDateTime = tz(currentTime.utc(), timeZone); | ||
} | ||
} else { | ||
convertedDateTime = currentTime.utc(); | ||
} | ||
} | ||
|
||
if (!error) { | ||
({timexProperty: parsed, error: error} = FunctionUtils.parseTimexProperty((args[0] as string).replace('XX', '00'))); | ||
} | ||
|
||
if (!error) { | ||
const hour = convertedDateTime.hour(); | ||
const minute = convertedDateTime.minute(); | ||
const second = convertedDateTime.second(); | ||
|
||
if (parsed.minute < minute || (parsed.minute === minute && parsed.second < second)) { | ||
validHour = hour; | ||
} else { | ||
validHour = hour - 1; | ||
} | ||
|
||
validMinute = parsed.minute; | ||
validSecond = parsed.second; | ||
} | ||
|
||
value = TimexProperty.fromTime(new Time(validHour, validMinute, validSecond)).timex; | ||
return {value, error}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.