Bixby Developer Center

References

DateTime (viv.time)

Many Bixby capsules need to not only work with date and time values, but need to be able to handle complicated requests from users. For example, "3:00 pm next Tuesday"; "4 weeks from now"; "in 3 hours"; "starting Saturday afternoon and ending Wednesday morning". To handle dates and times, Bixby provides the viv.time library capsule. This offers a set of concepts and actions that allow natural language date-time expressions to be converted to fully resolved objects, and provides a special abstract structure concept for training.

Note

While the built-in JavaScript Date object is supported, the platform-provided dates JavaScript API provides convenience functions for working with date and time models, as well as for returning valid viv.time concepts.

Types are always in the viv.* namespace, and in the viv.time.* namespace unless another namespace is specified (such as viv.rating.*). All properties have a cardinality of min (Required), max (One) unless otherwise specified.

This reference lists out several of the models available in this library capsule. Some sections contain tables listing information about those concepts or actions.

Date and Time Concepts

The viv.time library includes the following major concepts. (There are many other concepts used internally in viv.time, and some of the models below have private fields used for processing, but the ones below are the ones your capsule is most likely to interact with.)

Date

A precise date: for example, March 23, 2018. It can optionally include a "fuzzy" period (for example, ±3 days), which your function can use if appropriate. (For example, a search for airline flights might specify a departure date, but also include flights on the day before and the day after.)

PropertyTypeKindNotes
yearYearintegerrange 1900–2100
monthMonthintegerrange 1–12
dayDayintegerrange 1–31
fuzzyFactorFuzzyFactorstructurerole-of Period (Optional)

Time

A precise point in time during a day, without a date specified. It can optionally include a "fuzzy" period (for example, ±3 minutes), which your function can use if appropriate.

PropertyTypeKindNotes
hourHourintegerrange 0–23
minuteMinuteintegerrange 0–59
secondSecondintegerrange 0–59
millisecondMillisecondintegerrange 0–999
timezoneTimeZoneIdstring(1)
fuzzyFactorFuzzyFactorstructurerole-of Period (Optional)
namedTimeNamedTimeenum(2)
  1. A TimeZoneId is a string in the "Area/Location" format defined by the IANA Time Zone Database, such as "America/Los_Angeles" or "Asia/Seoul".
  2. A NamedTime field which allows users to use "fuzzy" descriptions like "mid-afternoon" and "happy hour". The conversion to a more precise time specification is handled by the library.

DetachedTime

A DetachedTime is similar to a Time concept, but does not require a time zone to be set.

PropertyTypeKindNotes
namedTimeNamedTimeenum
hourHourintegerrange 0–23
minuteMinuteintegerrange 0–59
secondSecondintegerrange 0–59
millisecondMillisecondintegerrange 0–999
amPMAmPmenumAm or Pm
timezoneDateTimeZonestring

Note that DetachedTime does not have the role of Time, so the concepts cannot be used interchangeably.

DateTime

A structure containing both a required date and time, as well as the Unix time expressed in milliseconds.

PropertyTypeKindNotes
dateDatestructure
timeTimestructure
utcInstantUTCInstantintegermilliseconds from epoch
calculatedFromNowCalculatedFromNowboolean(1)
  1. The calculatedFromNow field indicates whether a Date, DateTime, or any Interval type is calculated from now by using a DateTimeExpression such as "in the next 3 hours" or "tomorrow".

Period

A structure representing a span of time, for example, 3 years 5 months 2 days and 7 hours. This is frequently used as a structure within other structures, such as the fuzzyFactor for Date and Time concepts.

Note

A period cannot be converted to a millisecond duration without associating it with a DateTime, since '1 month' will vary depending on the month.

PropertyTypeKindNotes
periodYearsPeriodYearsinteger
periodMonthsPeriodMonthsinteger
periodWeeksPeriodWeeksinteger
periodDaysPeriodDaysinteger
periodNightsPeriodNightsinteger(1)
periodHoursPeriodHoursinteger
periodMinutesPeriodMinutesinteger
periodSecondsPeriodSecondsinteger
periodMillisecondsPeriodMillisecondsinteger
  1. The periodNights field is useful for travel searches such as "I want to stay for three nights". It equates to one day longer than the number of nights: a period of three nights is a period of four days.

DateInterval

An interval with a start Date field and an end Date field: for example, March 23, 2018 to March 26, 2018.

PropertyTypeKindNotes
startStartDatestructure (Date)
endEndDatestructure (Date)

TimeInterval

An interval with a start Time field and an end Time field, with no date specified: for example, 10:00 am to 11:00 am.

PropertyTypeKindNotes
startStartTimestructure (Time)
endEndTimestructure (Time)

DateTimeInterval

An interval with a start DateTime field and an end DateTime field. This is the most complete representation of an interval from one millisecond instant to another instant, complete with time zone.

PropertyTypeKindNotes
startStartDateTimestructure (DateTime)
endEndDateTimestructure (DateTime)

DurationPeriod

This is a transient variant of Period, and should be used by actions as the input type for a duration.

DateTimeExpression

A convenience structure containing the four major viv.time input types.

PropertyTypeKindNotes
dateDatestructure
dateTimeDateTimestructure
dateIntervalDateIntervalstructure
dateTimeIntervalDateTimeIntervalstructure

This is an abstraction designed for natural language input; read Training below for more details. All properties in DateTimeExpression are optional, and will be populated appropriately based on the understood NL input.

Using Date and Time Models

The most common way for your capsule to interact with viv.time is by using it to translate a user's spoken input, like "7:30 pm", "next Saturday", or "January 13th through January 15th", into an appropriate model like Time, Date, or DateInterval. Typically, your capsule will handle this by:

  1. Creating training examples that use DateTimeExpression.
  2. Using a constructor action that takes the DateTimeExpression as an input and outputs a specific viv.time model, like Date or DateInterval, for use by other actions.

Training

While it's possible to train your capsule using any of the viv.time concepts as utterance annotations, it's usually best to use viv.time.DateTimeExpression rather than Date, DateTime, or either of the interval types.

Annotating the datetime value in the utterance "how likely is it that it will rain this weekend in las vegas" as a viv.time.DateTimeExpression

Because "this weekend" in the above example is annotated as a DateTimeExpression, this could match utterances such as "March 8th", "four weeks from now", "tomorrow at 8pm", or "Christmas morning". This gives your capsule tremendous flexibility in understanding user requests involving dates and times with very little work on your part. Bixby will simply provide the proper DateTime concept to your action.

DateTimeExpression Utterances

Here's the Aligned NL for a few utterances in the Earthquake Finder sample capsule that invoke a FindEarthquakes action:

show (earthquakes)[g:viv.earthquake.Earthquake] around
(San Francisco)[v:viv.geo.LocalityName]
(on October 17, 1989)[v:viv.time.DateTimeExpression]

show (earthquakes)[g:viv.earthquake.Earthquake] of at least
(5.0)[v:viv.earthquake.Magnitude:5.0] magnitude around
(San Francisco)[v:viv.geo.LocalityName]
(last month)[v:viv.time.DateTimeExpression]

find (earthquakes)[g:viv.earthquake.Earthquake] in
(Puerto Rico)[v:viv.geo.CountryDivisionName:'Puerto Rico']
(yesterday afternoon)[v:viv.time.DateTimeExpression]

The first of these queries would resolve to a Date, and fill in the date field of the returned DateTimeExpression. The second would resolve to a DateInterval; the third would resolve to a DateTimeInterval. When you train on DateTimeExpression, only one of the four fields will be set at a time, based on the value derived from the user's utterance. Your JavaScript action implementation must test for values in each field of DateTimeExpression and take appropriate action.

var config = require("config")
var console = require("console")
var http = require("http")
var dates = require("dates")
var utils = require('Utils.js')


module.exports.function = function FindEarthquakes(dateTimeExpression, searchRegion, minMagnitude, maxMagnitude, approxMagnitude, eventType) {

var url = "https://earthquake.usgs.gov/fdsnws/event/1/query"

var args = {
format: "geojson",
limit: 2000,
orderby: "magnitude"
};

// Extract info from DateTimeExpression and add to args
if (dateTimeExpression) {
utils.extractStartAndEnd(dateTimeExpression, args)
}

// Compute and add searchRegion args
if (searchRegion) {
utils.searchRegionSetup(searchRegion, args)
}

if (minMagnitude) {
args.minmagnitude = minMagnitude
}
if (maxMagnitude) {
args.maxmagnitude = maxMagnitude
}
if (approxMagnitude) {
args.minmagnitude = approxMagnitude - 0.25
args.maxmagnitude = approxMagnitude + 0.25
}

var ret = []
try {
// Looping logic to generate separate API calls for each of the eventType inputs specified by the user.
// ********************************************************************************
if (eventType.length != 0) {
for (var j = 0; j < eventType.length; j++) {
args.eventtype = eventType[j];
// Find earthquakes
utils.findQuake(url, args, ret)
}
}
// ********************************************************************************
else {
// Find earthquakes
utils.findQuake(url, args, ret)
}
} catch (err) {
console.log("ERR: " + JSON.stringify(err));
}
return ret
}

View master on GitHub

Actions

You can find an example of a constructor action for DateTimeExpression in the Space Resorts Sample Capsule.

action (ConstructDateIntervalFromDateTimeExpression) {
type (Constructor)
collect {
input (dateTimeExpression) {
type (time.DateTimeExpression)
min (Required)
default-select {
with-rule {
select-first
}
}
}
}
output (DateInterval)
}

View master on GitHub

The utterance that matches DateTimeExpression could specify a specific date, a range of specific dates, or a description of a date or dates, such as "next weekend". The ConstructDateIntervalFromDateTimeExpression action takes a DateTimeExpression and returns a DateInterval.

Bixby Views Components

Bixby Views provide input components that include interactive components for selecting dates, times, and durations.

  • The date picker returns a viv.time.Date concept.

  • The time picker returns a viv.time.Time concept.

  • The calendar returns either a viv.time.Date or a viv.time.DateInterval concept.

  • The duration picker returns a viv.time.Period concept.

The components are customizable, letting you select the initial values and the range of allowed values. They require you to import viv.time into your capsule.

For details and examples of how to use the view components, read the linked entries in the Reference Guides.

Advanced Topics

The following are more advanced topics while working with this library.

Handling Dates and Times in JavaScript

The other side of handling dates and times is using them in your JavaScript implementations. The concepts from viv.time will be passed to your functions as JavaScript objects, and can be manipulated easily.

Depending on your capsule's design, you might need to perform other date and time functions, particularly when working with external APIs. Tasks such as converting to JSON or parsing dates are provided in Bixby's JavaScript API. Bixby's dates class can create ZonedDateTime objects, which have a variety of methods that include date/time addition and subtraction, comparisons, conditional tests, and formatting functions.

The JavaScript implementation for the ConstructDateIntervalFromDateTimeExpression action above examines the properties in the DateTimeExpression and either returns the DateInterval component or converts the DateTimeInterval component into a DateInterval:

import console from 'console';
export default function ({dateTimeExpression}) {
console.log('dateTimeExpression:', dateTimeExpression);
if (dateTimeExpression.dateInterval) {
return {
start: dateTimeExpression.dateInterval.start,
end: dateTimeExpression.dateInterval.end,
};
}
if (dateTimeExpression.dateTimeInterval) {
return {
start: dateTimeExpression.dateTimeInterval.start.date,
end: dateTimeExpression.dateTimeInterval.end.date,
};
}
if (dateTimeExpression.date) {
//using same date for both start and end. This is not a valid case,should throw checkedError
return {
start: dateTimeExpression.date,
end: dateTimeExpression.date,
};
}
return null; //TODO handle error cases
};

View master on GitHub

Initializing Date & Time Concepts

Your capsule might need to initialize date and time concepts to specific values. A way to do this is to use default-init to initialize a concept in an action.

Suppose your capsule allows users to set ranges of dates. The Space Resorts capsule handles this for booking by implementing a DateInterval model with a role-of the DateInterval concept:

structure (DateInterval) {
role-of (time.DateInterval)
}

View master on GitHub

This is initialized in the CreateItem action by setting a default-init with a goal of GetDateInterval, which ensures the user is prompted to select the start and end dates of the reservation.

    input (dateInterval) {
type (DateInterval)
min (Required)
default-init {
intent { // Prompt for the interval
goal: GetDateInterval
}
}
}

View e76bba4 on GitHub

The GetDateInterval action, in turn, has an intent with a goal of DateInterval:

action (GetDateInterval) {
description (Prompt user to enter a date interval)
type (Constructor)
collect {
computed-input (dateInterval) {
type (DateInterval)
min (Required)
compute {
intent {
goal { @prompt-behavior(AlwaysElicitation) DateInterval }
}
}
}
}
output (DateInterval) {
evaluate { $expr(dateInterval) }
}
}

View master on GitHub

In another scenario, JavaScript might be used, for example, to perform an InitializeDuration action that outputs a Duration model with a role-of Period set to one hour.

action (InitializeDuration) {
type (Search)
output (Duration)
}

The JavaScript code simply returns the proper values for the duration:

export function initializeDuration() {
return {
periodHours: 1,
periodMinutes: 0,
periodSeconds: 0,
}
}

Now, the InitializeDuration action could be used as a goal in a default-init block.

Similar initialization goal actions can be created for other viv.time concepts. These are particularly useful when initializing Bixby Views components like duration and date pickers.

There are instances where the date or time expression you are using is ambiguous. The Resolving Ambiguous Utterances topic below goes into more depth on how to resolve these.

Resolving Ambiguous Utterances

Some utterances might refer to more than one possible date. Suppose today's date is Tuesday, July 14th, 2020, and the user refers to July 6th. Do they mean July 6th of this year (2020), or July 6th of next year (2021)? If they say "Friday", they might mean the upcoming Friday ("make a reservation for Friday") but might mean last Friday ("show me photos I took Friday").

The viv.time library doesn't have the context to make that distinction, but your capsule does. In cases where there's an ambiguity, DateTimeExpression will return multiple values in the appropriate property of the returned structure.

  • If the utterance is absolutely unambiguous ("July 6th, 2020", "Last Monday"), the library returns one value.
  • If the utterance is an ambiguous date ("July 6th", "Monday"), the library will return two values: the nearest future match and the nearest past match, in that order. It will not return today's date.
  • If the utterance is a specific time ("5:30 pm"), the library will return two values: the time today and the time yesterday.
  • If the utterance is a datetime that's ambiguous with respect to dates and times ("Monday at 2"), the library will return four values: the nearest future date with AM and PM values, and the nearest past date with AM and PM values.
  • If the utterance is a time (with no date) that's ambiguous with respect to AM or PM ("5 o'clock"), the library will return four values: the nearest future matching time, the nearest past matching time, the next nearest future matching time, and the next nearest past matching time.

When you receive multiple values, your capsule should choose the appropriate one based on context, or prompt the user for clarification.

If today's date is Tuesday July 14, 2020 at 2pm, these utterances would return the following value(s) when matched to a DateTimeExpression:

UtteranceReturn TypeReturn Value(s)
July 6th, 2020Date2020-07-06
July 6thDate2021-07-06, 2020-07-06
August 6thDate2020-08-06, 2019-08-06
January 6thDate2021-01-06, 2020-01-06
July 2020DateInterval2020-07-01 to 31
JulyDateInterval2020-07-01 to 31, 2021-07-01 to 31
AugustDateInterval2020-08-01 to 31, 2019-08-01 to 31
This FridayDate2020-07-17
MondayDate2020-07-20, 2020-07-13
Monday at 2DateTime2020-07-20 2am, 2020-07-20 2pm,
2020-07-13 2am, 2020-07-13 2pm
5:30 pmDateTime2020-07-14 5:30pm, 2020-07-13 5:30pm
5 o'clockDateTime2020-07-14 5pm, 2020-07-14 5am,
2020-07-15 5am, 2020-07-13 5pm
TuesdayDate2020-07-21, 2020-07-07
YesterdayDate2020-07-13
TomorrowDate2020-07-15
This WednesdayDate2020-07-15
This MondayDate2020-07-20
This TuesdayDate2020-07-21
Last MondayDate2020-07-06
ChristmasDate2020-12-25, 2019-12-25
EasterDate2021-04-04, 2020-04-12

Bixby can resolve most international holidays, including dynamically-scheduled ones such as Easter. The return values follow the same rules as the examples above when users ask for a date in the future or the past:

  • If the date of the holiday is in the past, the returned dates will be for next year and the current year.
  • If the date of the holiday is in the future or today, the returned dates will be for the current year and the past year.

The return values from DateTimeExpression will always be the same type, one of Date, DateTime, DateInterval, or DateTimeInterval.

The Time Test Harness Capsule

You can try various DateTimeExpression utterances and see their return values by using the Time Test Harness Capsule in Bixby's Capsule Samples Collection. Run the test harness in the Device Simulator. The harness will show you several data points for any given phrase:

  • What part of the phrase (if any) is identified as a viv.time.DateTimeExpression
  • How many values are returned and what type they are
  • The resolved object(s) returned by viv.time
  • The value dialog fragment of the response(s)

The Simulator open, showing two results for the DateTimeExpression "Christmas week"

You can look in the Debug Console to see the actual returned objects. You can also check the Conversation tab in the Debug console to see how much of your phrase is being interpreted as a DateTimeExpression; the text harness will try to interpret the entire phrase as one, so if your utterance is only partially tagged (or not tagged at all), it is likely not a supported expression.

By default, the Simulator uses the current date and time. You can override this and choose a specific date and time to be "current" for testing purposes in the Simulator's Settings tab.

The DateTime library behaves identically across device types. The test harness currently only supports en locales, but you could add new language targets to the capsule.bxb file and add some training examples in the new language.

Video Tutorial: Date and Time Entry Using Bixby

The following video demonstrates how to use the timeTestHarness capsule.