I'm currently struggling with figuring out what's wrong with a Event insert I'm trying to accomplish in Flutter using Google Calendar V3 API. Initially I thought it's a matter of RFC3339 vs ISO8601 date formats, but I'm grasping at straws.
Unhandled Exception: DetailedApiRequestError(status: 400, message: Bad Request) is what I'm getting from:
import 'package:googleapis/calendar/v3.dart';
import 'package:googleapis_auth/auth.dart';
import 'package:googleapis_auth/auth_io.dart';
...
var calendar = await getCalendar();
var ac = await getOrCreateCredentials();
var client = await getClient(ac);
var calendarId = await storage.read(key: "calendar_id");
var capi = CalendarApi(client);
EventCreator ec = new EventCreator();
ec.displayName = "Display Name";
EventDateTime edt = new EventDateTime();
int hour = int.parse(ds.hour.split(":")[0]);
int min = int.parse(ds.hour.split(":")[1]);
DateTime x = ds.data.add(Duration(hours: hour, minutes: min));
edt.dateTime = x;
edt.timeZone = x.timeZoneName;
EventDateTime edtEnd = new EventDateTime();
DateTime y = x.add(Duration(hours: 1));
edtEnd.dateTime = y;
edtEnd.timeZone = y.timeZoneName;
Event e = new Event();
e.created = DateTime.now();
e.creator = ec;
e.description = d.var + " \n" + d.var;
e.summary = "Summary";
e.etag = d.var;
e.location = d.var;
e.start = edt;
e.end = edtEnd;
try {
capi.events.insert(e, calendarId);
The full JSON response contains nothing else except global domain, badrequest and HTTP 400 code.
I also tried .toUtc() on the DateTime objects to make them RFC3339 compliant, but still the same error presents.
Later Edit
The issue is indeed related to the time, the Dart DateTime class does not format the time in a way Google likes (2021-04-12T08:30:00+03:00 which I've deduced from other languages' API implementations, and the source code of the package which does a .toString() of the DateTime basically).
The way around this is to create the EventDateTime from a JSON object, and to use a hacky Dart extension. I apologize for the naming but it's annoying.
extension FuckyDateTime on DateTime {
Map<dynamic, dynamic> fuckyDateTime() {
Map<dynamic, dynamic> x = new Map();
String formatted = this.year.toString() +
'-' +
(this.month.toString().length == 1
? '0' + this.month.toString()
: this.month.toString()) +
'-' +
(this.day.toString().length == 1
? '0' + this.day.toString()
: this.day.toString()) +
'T' +
(this.hour.toString().length == 1
? '0' + this.hour.toString()
: this.hour.toString()) +
':' +
(this.minute.toString().length == 1
? '0' + this.minute.toString()
: this.minute.toString()) +
':' +
(this.second.toString().length == 1
? '0' + this.second.toString()
: this.second.toString()) +
'+' +
'03:00';
x.putIfAbsent('dateTime', () => formatted);
x.putIfAbsent('timeZone', () => 'Europe/Bucharest');
return x;
}
}
and EventDateTime edt = new EventDateTime.fromJson(x.fuckyDateTime()); where x is a DateTime object.
The issue is indeed related to the time, the Dart DateTime class does not format the time in a way Google likes (2021-04-12T08:30:00+03:00 which I've deduced from other languages' API implementations, and the source code of the package which does a .toString() of the DateTime basically). Fair mention that Dart DateTime does provide a String of ISO8601, Google wants an RFC3339 compliant date.
The way around this is to create the EventDateTime from a JSON object, and to use a hacky Dart extension. I apologize for the naming but it's annoying.
extension FuckyDateTime on DateTime {
Map<dynamic, dynamic> fuckyDateTime() {
Map<dynamic, dynamic> x = new Map();
String formatted = this.year.toString() +
'-' +
(this.month.toString().length == 1
? '0' + this.month.toString()
: this.month.toString()) +
'-' +
(this.day.toString().length == 1
? '0' + this.day.toString()
: this.day.toString()) +
'T' +
(this.hour.toString().length == 1
? '0' + this.hour.toString()
: this.hour.toString()) +
':' +
(this.minute.toString().length == 1
? '0' + this.minute.toString()
: this.minute.toString()) +
':' +
(this.second.toString().length == 1
? '0' + this.second.toString()
: this.second.toString()) +
'+' +
'03:00';
x.putIfAbsent('dateTime', () => formatted);
x.putIfAbsent('timeZone', () => 'Europe/Bucharest');
return x;
}
}
and EventDateTime edt = new EventDateTime.fromJson(x.fuckyDateTime()); where x is a DateTime object.
Related
I want to build an app for my pupil which generates tasks out of sentence blocks.
For example I created two classes, apple and pear, with nearly the same structure. They return a question built out of the sentence blocks which are defined in the classes. In both classes is a GenerateQuestion()-function for that.
Now I want to build some kind of overclass, which picks a random class of i.e. apple or pear and then returns the strings from the functions. The functions names are the same, but I can't figure out how to get data from a random choosen class. Hoping for help. Thanks in advance.
Update: Here is the code I wrote so far (I tried to translate it properly):
import 'dart:math';
int randomminmax1 = 0;
int randomminmax2 = 0;
int randomminmax3 = 0;
List classes = [apple, pear];
class overClass {
static pickClass(){
int randomClassItem = Random().nextInt(classes.length);
print(classes[randomClassItem]);
return classes[randomClassItem];
}
}
class apple {
static String giveQuestion() {
randomminmax1 = 2 + Random().nextInt(15 - 2);
randomminmax2 = randomminmax1 * (2+Random().nextInt(12 - 2));
randomminmax3 = 2 + Random().nextInt(30 - 2);
List value_1 = [" boxes", " bags", " bucket"];
List verbs = ["cost","have a price of", "are offered for"];
List value_2 = ["Euro"];
List questionWords = [""];
int randomIndexValue1 = Random().nextInt(value_1.length);
int randomIndexVerbs = Random().nextInt(verbs.length);
int randomIndexValue2 = Random().nextInt(value_2.length);
String value = randomminmax1.toString() + value_1[randomIndexValue1].toString() + " apples" + verbs[randomIndexVerbs].toString() + " " + randomminmax2.toString() + " " + value_2[randomIndexValue2].toString() + ".\n";
String question = "How much are " + randomminmax3.toString() + value_1[randomIndexValue1].toString() + "?\n";
return value + question;
}
static String giveAnswer(){
double result = (randomminmax2/randomminmax1)*randomminmax3;
return result.toStringAsFixed(2) + " Euro.";
}
}
class pear {
static String giveQuestion() {
randomminmax1 = 2 + Random().nextInt(15 - 2);
randomminmax2 = randomminmax1 * (2+Random().nextInt(12 - 2));
randomminmax3 = 2 + Random().nextInt(30 - 2);
List value_1 = [" boxes", " bags", " bucket"];
List verbs = ["cost","have a price of", "are offered for"];
List value_2 = ["Euro"];
List questionWords = [""];
int randomIndexValue1 = Random().nextInt(value_1.length);
int randomIndexVerbs = Random().nextInt(verbs.length);
int randomIndexValue2 = Random().nextInt(value_2.length);
String value = randomminmax1.toString() + value_1[randomIndexValue1].toString() + " pears" + verbs[randomIndexVerbs].toString() + " " + randomminmax2.toString() + " " + value_2[randomIndexValue2].toString() + ".\n";
String question = "How much are " + randomminmax3.toString() + value_1[randomIndexValue1].toString() + "?\n";
return value + question;
}
static String giveAnswer(){
double result = (randomminmax2/randomminmax1)*randomminmax3;
return result.toStringAsFixed(2) + " Euro.";
}
}
static String giveAnswer(){
double result = (randomminmax2/randomminmax1)*randomminmax3;
return result.toStringAsFixed(2) + " Euro.";
}
}
Can you try to create a superclass that all question classes will inherit and then get the subclasses and programmatically call functions. Try to see here
At least I managed to give my values directly from the classes into the list. But then I got problems with the int-variables, which were built wrong.
My "solution": I converted my classes into isolated flutter widgets, which works fine, except the problem that I'm not able to put the widgets into a list, from where they are picked randomly...but therefore I'll write a new post.
Thank you Moustapha for your help (the superclass idea sounds good, but way too hard to code for me) ;)!
I am trying to create a pop up to warn a user they must update a part in inventory if the part date is more than 90 days old. The date on the sheet (Cell Q5) is autofilled from another sheet, but that shouldn't matter. The value for the cell on the spreadsheet is 9/2/2021. I've tried many things, but currently I am getting the value for Q5 showing up as NaN .
function CheckInvDate() {
var ss = SpreadsheetApp.getActive().getId();
var partsrange = Sheets.Spreadsheets.Values.get(ss, "BOM!A5:Q5");
var currentDate = new Date();
var parthist = new Date();
parthist.setDate(currentDate.getDate() -90);
for (var i = 0; i < partsrange.values.length; i++){
var name = partsrange.values [i][1]
var partdate = partsrange.values [i][16]
var parthisttime = new Date(parthist).getTime();
var partdatetime = new Date(partdate).getTime();
Logger.log("History " + parthisttime)
Logger.log("Current " + partdatetime)
SpreadsheetApp.flush()
// if (parthist > partdate == "TRUE") {
// SpreadsheetApp.getUi().alert('The price on '+ name + ' is out of date. Please update price and try again.')
// }
}
}
My last log was
[22-07-06 11:50:55:851 EDT] History 1649346655850
[22-07-06 11:50:55:853 EDT] Current NaN
I've seen a number of responses on Stack Overflow, but I can't understand them. They seem to refer to variables that I don't see in code, or commands I haven't seen before and I'm not sure if they are in date.
Try this:
function CheckInvDate() {
const ss = SpreadsheetApp.getActive();
const vs = Sheets.Spreadsheets.Values.get(ss.getId(), "BOM!A5:Q5").values;
let d = new Date();
d.setDate(d.getDate() - 90)
const dv = d.valueOf();
const oldthan5 = vs.map(r => {
if (new Date(r[16]).valueOf() < dv) {
return r;
}
}).filter(e => e);
SpreadsheetApp.getUi().showModelessDialog(HtmlService.createHtmlOutput(`<textarea rows="12" cols="100">${JSON.stringify(oldthan5)}</textarea>`).setWidth(1000), "Older Than 90 Days");
}
This outputs a dialog with the rows older than 90 days
I went to try this on my script again after lunch, and for whatever reason I am no longer getting the NaN value. I made one change on the if statement to fix the logic, and now it is working correctly. Not sure what I did, but apparently the coding gods were unhappy with me before.
The only part I changed was
if (parthisttime > partdatetime) {
SpreadsheetApp.getUi().alert('The price on '+ name + ' is out of date. Please update price and try again.')
}
So I have like kind of a homemade economy thing and when I added a working command and when it works it picks a random number and stuff but when it adds the number to the old currency it's adding like for ex 123+123 = 123123 when it supposed to be 246 I don't know how to fix this I tried everything and nothing has worked for me
if (message.content.toLowerCase().startsWith(prefixS.prefix + 'work')) {
const inventoryS = await inventory.findOne({ userID: message.author.id, guildID: message.guild.id });
if (inventoryS.item1 === 'true') {
const payment = Math.floor(Math.random() * 125) + 25;
inventoryS.currency += payment
inventoryS.save()
message.channel.send({ embeds: [new Discord.MessageEmbed().setTitle('After a long day of work your balance is').setDescription(`__Your balance__\n > Money: ${inventoryS.currency}`).setColor('BROWN')] })
}
}
Both of them must be Numbers to do addition, otherwise it will add as strings
inventoryS.currency = parseInt(inventoryS.currency) + parseInt(payment)
it is possible that your inventoryS.currency is a string value
let a = '123' //a string
let b = 123 //an integer
a += b
console.log(a) //logs 123123
you will need to parse it to an integer before adding
let a = '123'
let b = 123
a = parseInt(a) + b
console.log(a)
more references here
My code is based on the example of google code:
https://developers.google.com/maps/articles/phpsqlinfo_v3
and was working fine.
I need to change a former 'gid' (Integer) field to 'id' (String) to get saved to the database and used to display a new labeled symbol on the map.
The strange thing is, that the url, that is build in the code to call the addrow.php file is OK. When I capture this string with alert(url), and I manually use this string, the new data is added to the database.
In my script, the call seems to fail (responseCode == 200 && data.length <=1), since no data is written to the database and the alert from the 'else-clause' is displayed as short pop-up.
Here's the code I use in my project (to save data from a form):
//save new marker to Postgis-database and add new markerwithlabel on the fly
function saveData(){
var gender = escape(document.getElementById("gender").value);
var hoehe = InZahl(document.getElementById("hoehe").value);
var breite = InZahl(document.getElementById("breite").value);
var id = escape(document.getElementById("id").value);
var vital = document.getElementById("vital").value;
var typ = document.getElementById("typ").value;
var ein_mehr = document.getElementById("ein_mehr").value;
var st_durchm = document.getElementById("st_durchm").value;
var frucht = document.getElementById("frucht").value;
var anmerk = document.getElementById("anmerk").value;
var latlng = marker.getPosition();
var url = "./mapdata/addrow.php?gender=" + gender +
"&hoehe=" + hoehe + "&lat=" + latlng.lat() + "&lng=" + latlng.lng() +
"&breite=" + breite + "&id=" + id + "&typ=" + typ + "&ein_mehr=" +ein_mehr + "&st_durchm=" + st_durchm +
"&frucht=" + frucht +
"&vital=" + vital + "&anmerk=" + anmerk;
downloadUrl(url, function (data, responseCode) {
if (responseCode == 200 && data.length <=1) {
infowindow.close();
marker.setDraggable(false);
marker.setIcon('./images/mm_purple.png');
marker.labelContent = id;
marker.setMap(map);
downloadUrl("./mapdata/getxml_get_last.php", function (data1) {
var xml = parseXml(data1);
var ms = xml.documentElement.getElementsByTagName("m");
var gid = ms[0].getAttribute("gid");
var html_n = "<div id='InfoWindow'><p style='font-weight:bold;'>" + id + "</p> \n\<p>Höhe:" + hoehe + " Breite: "+ breite +
"<br />\n\Typ: "+typ+" Stämme: "+ein_mehr+" St-Durchm: "+ st_durchm + "<br />\n\Vitalität: "+vital+" Fruchtbehang: "+frucht+
"<p/>\n\<p style='text-align:right;'><a href='sm_juniperus.php?operation=ssearch&ResetFilter=0&SearchField=gid&FilterType=%3D&FilterText="+ gid +
"' target='_blank'> Daten editieren </a></p></div>";
infowindow.setContent(html_n);
bindInfoWindow(marker, map, infowindow, html_n);
(function(i, marker, gid) {
var origIcon = marker.getIcon();
new LongPress(marker, 1000);
google.maps.event.addListener(marker, 'longpress', function(e) {
marker.setDraggable(true);
marker.setIcon(mmcross);
});
google.maps.event.addListener(marker, 'dragend', function(){
updatePosition(marker, gid);
marker.setIcon(origIcon);
});
})(i,marker,gid);
//add new marker to markerCluster-Array and to markerArray
markerCluster.addMarker(marker,false);
markerArray.push(marker);
i++;
}); // End add new marker
}
else {
alert("Your data couldn't be saved!");
}
}); // End downloadUrl
}; // END saveData()
As I said, my code worked fine, but after 3 evenings passed to solve this, I thought it would be time to ask for help.
If anybody has an idea, where the mistake lies, I would apreciate any hint.
Just to confirm, you're aware that you by doing
if (responseCode == 200 && data.length <=1) {
you are saying 'if the request is successful and the data it returns is only one character or below in length'? I am unsure if this is intended or not, because this way the code inside the if statement is only ran if the response is successful but contains only 1 or 0 characters.
I can't seem to get the timestamp in my phonegap application. A simple call to Date.now(), e.g. the following, results in NaN.
console.log("lastEditedOn: " + Date.now().toString() );
LogCat:
01-26 18:28:59.997: I/Web Console(17970): LastEditedOn: NaN:220
Can anyone see what I am doing wrong?
Cheers,
Don
Managed to get the correct timestamp with this:
var d = new Date();
var lastEditedOn;
lastEditedOn = d.getTime();
console.log(lastEditedOn);
Cheers,
Don
You cannot directly toString the Date.now() because it returns the milliseconds from midnight, Jan 1 1970.
You need to convert them like this:
function printDate() {
var temp = new Date();
var dateStr = padStr(temp.getFullYear()) +
padStr(1 + temp.getMonth()) +
padStr(temp.getDate()) +
padStr(temp.getHours()) +
padStr(temp.getMinutes()) +
padStr(temp.getSeconds());
debug (dateStr );
}
function padStr(i) {
return (i < 10) ? "0" + i : "" + i;
}