dialogflow sys.date-time parameter format question - dialogflow-es

I'm making an app on Dialogflow and need to extract date-time info from user. So I specified a required parameter called "date-time" with #sys.date-time entity in my intent. However, when I tried to extract this parameter in my fulfillment code, I found that this parameter structure is not the same every time when I extract it. For example, when I type 12:30am into the chatbot, the returned API json response contained this:
"parameters": {
"date-time": "2019-11-27T00:30:00-08:00",
"log": "5"
},
So I can directly read date-time parameter value by parameters['date-time']
However, if I type "yesterday at 2pm" into chatbot, the returned parameter structure is this:
"parameters": {
"date-time": {
"date_time": "2019-11-25T14:00:00-08:00"
},
"log": "log"
},
See that the "date-time" parameter is wrapped inside an extra "date-time" object. This is really annoying because now i need to consider these two cases in my fulfillment code. Does anyone know why this happened? And is this a bug on my side? Thanks!

You may have found the answer to this by now, but going through Googles documentation here I found you have to consider a variety of cases when using the #sys.date-time entity. So there's nothing wrong on your end.
An extra "date_time" is used when a date and time were specified, whereas if its a period of time there's a "startDate" and "endDate" that you have to look out for inside the original "date_time" object as well.
From looking at the examples in that document I've outlined some of the cases below.
specific time (e.g.12:30am) or specific date (e.g. December 12) = single date_time object
time period (date or time e.g. April or morning) = "startDate" and "endDate" entry in a date_time object
specific date + specific time (e.g. yesterday at 2pm) = "date_time" entry in a date_time object
date + time period (e.g. yesterday afternoon) = "startDateTime" and "endDateTime" in a date_time object
Hope that helps!

Related

Importing date without local time transformation

I am getting a date in DD-MMM-YY format, and am using dayjs to convert it to standard date format in nodejs.
However, the returned date is 1 day earlier than the input date.
I was told this is probably due to some difference in the server local time.
I can easily just add a day to the date, but as this will be a global function that works in multiple time zones, I just want to get the date "as is" without any automatic adjustments.
This is my function:
const convertDate = (date,format,zone) => {
dayjs.tz.setDefault(zone);
console.log(date);
console.log(dayjs(date));
console.log(dayjs.utc(date).$d);
console.log(dayjs.tz(date,format,zone).$d);
var newDate = dayjs.tz(date,zone);
//newDate.setDate(newDate.getDate());
return newDate;
}
No matter which methods I use or which zone I set, the date comes out as one day earlier than the input date.
For example, for a date of 01-APR-03 I get:
2003-03-31T21:00:00.000Z
I want the time to just be 2003-04-01T00:00:00.000Z.
Following comments, I have tried the following approach, but the result is the same:
const fixMonthName = (s) => s.replace(/[A-Z]{2}-/, (m) => m.toLowerCase());
const d = dayjs.utc(fixMonthName("22-FEB-02"), "DD-MMM-YY");
console.log(d);
const s = d.toISOString();
console.log(s); //{result:
M {
'$L': 'en',
'$u': true,
'$d': 2002-02-21T22:00:00.000Z,
'$x': {},
'$y': 2002,
'$M': 1,
'$D': 21,
'$W': 4,
'$H': 22,
'$m': 0,
'$s': 0,
'$ms': 0
}}
2002-02-21T22:00:00.000Z
Let's recap the problem:
You have a date-only string value of 01-APR-03 (equivalent to 2003-04-01).
You're then parsing it as timestamp, treating it as if it were 2003-04-01T00:00:00.000 (local time). This is the cause of the logical error.
Then you're looking at a UTC representation (2003-03-31T21:00:00.000Z in your example), and wondering why it's been shifted. (Z means UTC)
Fundamentally, a date and a timestamp are two different concepts. If you conflate them, you will have complications in your code such as the one you described.
A date can be thought of as a half-open range of timestamps (from the start of one day, to just before the start of the next). In other words, logically the following is true:
'2003-04-01' == ['2003-04-01T00:00:00.000', '2003-04-02T00:00:00.000')
If you parse a date-only value to an object that represents a timestamp, you are choosing to assign a point-in-time within that range. Thus, if you pick the very start of the range, you can easily shift into a different day when viewing that from another time zone.
Note that the JavaScript Date object is misnamed. It isn't a date, it's a timestamp.
A day.js object also represents a timestamp, as do most other libraries including Moment, Luxon, date-fns, and many others.
There are a few different solutions to this problem:
You can pick a time in the middle of the range which is less likely to be shifted to a different date when viewed from another time zone. For example, 12:00:00 noon. (Though this isn't perfect, as there are some time zones that go up to UTC+14.)
You can avoid treating a date as a timestamp, by keeping it in an object or string that represents it as a whole date.
Unfortunately, this isn't a concept that has caught on well in JavaScript yet. The language and most libraries do not handle it this way. (One notable exception is js-joda, which has a LocalDate data type.) However, this will eventually be coming to the JavaScript language itself via the Temporal proposal, which adds Temporal.PlainDate.
You can ignore the time portion of a timestamp and only look at the date part, but this only works if you lock all your operations to UTC rather than local time. In other words, treat '2003-04-01' as if it were '2003-04-01T00:00:00.000Z' and never convert it to local time or another time zone.
If you were using just the JavaScript Date object, then you would do:
const d = new Date('2003-04-01T00:00:00.000Z'); // the Z parses as UTC
const s = d.toISOString(); // this always emits UTC
But since you have a custom date format to parse and want to use day.js, you can do something like the following:
Define a function to work around day.js's parsing case sensitivity issue. (You need Apr, not APR.)
const fixMonthName = (s) => s.replace(/[A-Z]{2}-/, (m) => m.toLowerCase());
Parse the input string using day.js's UTC mode
const d = dayjs.utc(fixMonthName('01-APR-03'), 'DD-MMM-YY');
Get the output as a string however you would like, using any of day.js's display functions:
const s = d.toISOString(); // "2003-04-01T00:00:00.000Z"
// or
const s = d.format('YYYY-MM-DD'); // "2003-04-01"
Note that if you need a JavaScript Date object, do not use $d but instead call .toDate(). From there, make sure you are only using the UTC representation of the Date object. Keep in mind that while some environments will emit UTC when logging a Date object to the console (as if you called .toISOString(), other environments will emit the local time equivalent (as if you called .toString().

Filter google calendar event list with the query parameter "q"

I'm trying to filter a list of recently updated events from my Google Calendar with the parameter q= "status ='confirmed'" but it returns nothing.
I first had my block of code like this :
def main():
watchEvents(monday) # monday is in isoformat : "2021-09-13T00:00:00Z"
def watchEvents(day):
page_token = None
while True:
events = service.events().list(calendarId='primary', pageToken=page_token, updatedMin=day).execute()
for event in events['items']:
print (event['summary'])
page_token = events.get('nextPageToken')
if not page_token:
break
But the parameter updatedMin=day outputs an error Traceback (most recent call last): print (event['summary']) KeyError: 'summary', because cancelled events don't have those properties.
Here is an example of a cancelled event when I try the API on the google site:
"items": [
{
"kind": "calendar#event",
"etag": "\"xxxxxxx\"",
"id": "xxxxx",
"status": "cancelled"
}
I don't want those type of events where the status are "cancelled" so I tried the parameter q= "status ='confirmed'" in my code :
events = service.events().list(calendarId='primary', pageToken=page_token, updatedMin=day, q= "status ='confirmed'").execute()
But now it returns an empty list, even when I try the API on the google site :
{
"kind": "calendar#events",
"etag": "\"xxxxx\"",
"summary": "FirstName Name private",
"updated": "2021-09-16T10:04:02.008Z",
"timeZone": "Europe/Brussels",
"accessRole": "owner",
"defaultReminders": [
{
"method": "popup",
"minutes": 30
}
],
"nextSyncToken": "XXXXXXXXX=",
"items": []
}
So my questions are :
What is the syntax to filter the status of the events ?
Or is there another way to get a list of the last updated items?
Answer:
The Google Calendar API always returns cancelled events for events: list when either updateMin or syncToken are specified in the request. If you wish to remove updated items that have been deleted, this will need to be done locally.
More Information:
As per the documentation on the event resource: (emphasis my own):
Property name
Value
Description
Notes
status
string
Status of the event. Optional. Possible values are: • "confirmed" - The event is confirmed. This is the default status.• "tentative" - The event is tentatively confirmed.• "cancelled" - The event is cancelled (deleted). The list method returns cancelled events only on incremental sync (when syncToken or updatedMin are specified) or if the showDeleted flag is set to true. The get method always returns them.
writable
and from events: list:
Parameter name
Value
Description
updatedMin
datetime
Lower bound for an event's last modification time (as a RFC3339 timestamp) to filter by. When specified, entries deleted since this time will always be included regardless of showDeleted. Optional. The default is not to filter by last modification time.
You can use a syncToken to retrieve updates from the last time you made a sync request, but even then cancelled events will be returned.
Additionally, it appears that the event status can't be specified using the q parameter to have results filtered in the response.
The q parameter works somewhat strangely, in that you set it to a string that serves as a keyword which gets searched for in the following fields of the events: summary, description, location, attendee's displayName, attendee's email.
So, let's say you want to get events that take place at the location Times Square. You would use the following sort of statement:
events = service.events().list(calendarId='primary', pageToken=page_token, q='Times Square').execute()
Now hopefully you don't have an event taking place in Paris that has an attendee with the display name Times Square, or else that event will also be included in the events result set -- since, sadly, you can't specify which particular field q's search should apply to.

Change date format in dialogflow

I`m currently trying to build up a chatbot/agent with dialogflow and have honestly no knowledge about anything in the programming business/IT stuff. I´m a student who had a guestlecture where we were shown how to create Chatbots haha. But I was interested and sat down and tried to create one for my work. A simple bot that tells the customer about the opening times and gives out some information to save us some phone calls. So far so good. I want to include the function to book a table and my problem is the following:
I´ve read many questions about changing the date and time format to receive a format like "4pm on Thursday" instead of "2020-12-26T16:00:00+01:00".
So as I said I have no clue so far how the change the code to get a different output so my question would be if you could tell me where exactly I have to do that or where I can find a solution for that. Don´t get me wrong I´d love to know how to do it so yeah I´d be so happy if you could save that christmas present :)
Best regards
Mo
So, your question is vague and lacks details.
If you want to convert "2020-12-26T16:00:00+01:00" to "4pm on Thursday" in your local time here are helper functions to achieve that:
function convertParametersDateTime(date, time){
return new Date(Date.parse(date.split('T')[0] + 'T' + time.split('T')[1].split('+')[0]));
}
// A helper function that adds the integer value of 'hoursToAdd' to the Date instance 'dateObj' and return a new Data instance.
function addHours(dateObj, hoursToAdd){
return new Date(new Date(dateObj).setHours(dateObj.getHours() + hoursToAdd));
}
// A helper funciton that converts the Date instance 'dateObj' into a string that represents this time in English.
function getLocaleTimeString(dateObj){
return dateObj.toLocaleTimeString('en-US', {hour: 'numeric', hour12: true});
}
// A helper dunction that converts the Date instance 'dateObj' into a string that represents this date in English
function getLocaleDateString(dateObj){
return dateObj.toLocaleDateString('en-US', {weekday: 'long', month: 'long', day: 'numeric'});
}
Those are the helper functions. You have to call them inside the Fulfillment function for your intent. Here's a very simple example:
function makeAppointment (agent) {
// Use the Dialogflow's date and time parameters to create Javascript Date instances, 'dateTimeStart' and 'dateTimeEnd',
// which are used to specify the appointment's time.
const dateTimeStart = convertParametersDateTime(agent.parameters.date, agent.parameters.time);
const dateTimeEnd = addHours(dateTimeStart, appointmentDuration);
const appointmentTimeString = getLocaleTimeString(dateTimeStart);
const appointmentDateString = getLocaleDateString(dateTimeStart);
agent.add(`Here's the summary of your reservation:\nDate&Time: ${appointmentDateString} at ${appointmentTimeString}`);
}
The codes might include some syntax errors. Those functions give what you are looking for but you would have to adjust them according to your needs.

TypeORM: How does TypeORM compare timestamps?

I am using TypeORM to run this query:
SELECT "subagreementlog"."created_at" AS "subagreementlog_created_at" FROM "subagreement_logs" "subagreementlog" WHERE "subagreementlog"."subagreement_id" = $1 AND "subagreementlog"."created_at" > $2 LIMIT 1 -- PARAMETERS: ["0d71866e-3b78-4321-8ae8-dc39ffe82dbc","2020-11-12T13:57:16.618Z"]
I am looking for a record where the "created_at" value is greater than "2020-11-12T13:57:16.618Z" but this is actually returning the same value as if I was saying equal to or greater than.
result is: { subagreementlog_created_at: 2020-11-12T13:57:16.618Z }
Looking for guidance as to why this may be the case.
Also, here is the definition for said field in the Entity
#CreateDateColumn({ name: "created_at" })
#Field(_ => GraphQLISODateTime, {
description: "Timestamp the subagreement was changed"
})
public createdAt!: Date;
Have you tried increasing your parameter value? For example, rather than
2020-11-12T13:57:16.618Z try 2020-11-12T13:57:17.618Z (+1 second)
I believe you will still get a match even though the data is clearly before the parameter.
If you get a match I suspect what is happening is that you are storing data in one timezone (UTC likely) but using a local time for your parameter. I do not know TypeORM but maybe it converts timezones on reads and writes but does not convert parameters.
Just a guess but I hope it helps.

Range Keys in CouchDB Views

I'm using CouchDB for storing data about events. Each event has a start date/time and end date/time. I'd like to create a view now, that allows me to get a list of all events that happen on a specific date/time. But the events don't have a single dates, they can rather range over several days.
Now I don't know how I can reflect this in my view function. Unfortunately, I need granularity on minute level, so emitting a key for each minute might not be a valid solution. So how can I do that?
Thanks in advance!
Ok, here's a solution anyway! I just ping-ponged with Jan (Lehnardt) of CouchDB and he told me that I can emit() multiple times within a map. Something I did not know up until now.
To make it easier for myself, I'm assuming your end and start time are TIMESTAMP values already. If not, you need to convert them in your map or generally switch to them.
I'm also gonna assume that an event starts at a full minute (e.g. 16:51:00) and not at 16:51:23. Same on the end date.
Example document:
{
"_id" : "super-random-id",
"name" : "event 1",
"start" : "TIMESTAMP",
"end" : "TIMESTAMP"
}
Here's the map:
function (doc) {
if (doc.start == undefined || doc.end == undefined) {
return;
}
var current = doc.start;
while (current <= doc.end) {
emit(current, doc.id);
current = current + 60; // increment by 1 minute
}
}
Then it should be easy to query with startkey and endkey. You could probably add an _list here.
I found finally a good solution using GeoCouch: http://www.diretto.org/2010/08/efficient-time-based-range-queries-in-couchdb-using-geocouch/

Resources