Dart: Comparing two times from string - dart

Is there any way to compare two times in dart, suppose we have: 13:45 and 15:34, is there any way to find out that 15:34 is after 13:45.
I was looking at this question, and there are functions to check isBefore or isAfter, but is it possible to parse time without having to parse year, month and day?

You can convert them to datetime and compare. ie:
void main() {
var s1 = '13:45';
var s2 = '15:34';
var t1 = DateTime.parse('2000-01-01 ${s1}');
var t2 = DateTime.parse('2000-01-01 ${s2}');
print(t1.isBefore(t2));
}
EDIT: For a more direct, string sort like comparison (which I wouldn't suggest at all for Date\time values, unless you are 100% sure they are in sortable format) you could use compareTo(). ie:
print(s1.compareTo(s2) < 0);

Related

Function to check for duplicates based on condition

I have a simple Google sheet that records what sessions people are signed up for (3 concurrent sessions per day):
The same person cannot be in more than 1 session on a given day. I'd like to create a function in column B that checks for that situation and flags it, as in Susan, Keith, and Amy in the example above (I've highlighted in yellow the conditions that would trigger a flag).
If there were just one date, I'd use a countif (or maybe countifs?) to check for more than 1 TRUE for that date. But with multiple dates, I think some sort of iterative function or query is needed. I have a feeling I may be missing a simple formula, but it's eluding me. I may add more dates, so the solution needs to allow for n number of dates in the range.
UPDATE: My scenario has become a little more complex. I'm designating a potential role each person can play in each session and then using the checkboxes to indicate who is playing what role in each session. A given person can't be in more than 1 session per day (but a given person may be in 0 sessions on a given day). The below image shows this updated scenario, with the yellow highlights showing the conditions that I want flagged via the function in column B.
Here's a link to the Google sheet if you want to create a copy.
Given the use case provided, you can apply the formula below to B3 and drag the auto-complete handle:
=IF(ARRAYFORMULA(SUM(INT(C3:K3))) = COUNTUNIQUE($C$1:$1), "", "FLAG")
I'm converting the Boolean values to INT and summing them up. If the sum is equal to the count of unique days in the first row, then everything is fine, otherwise, FLAG!
In other words, if there are more (or less) checks than days, it should be flagged.
You can also set up a conditional formatting to paint the cell accordingly.
Alternatively, if you’d like to treat each scenario you can use =IFS() as below:
=IFS(ARRAYFORMULA(SUM(INT(C3:K3))) > COUNTUNIQUE($C$1:$1), "HIGHER", ARRAYFORMULA(SUM(INT(C3:K3))) < COUNTUNIQUE($C$1:$1), "LOWER", ARRAYFORMULA(SUM(INT(C3:K3))) = COUNTUNIQUE($C$1:$1), "OK")
References:
Sheets Functions documentation
IF
IFS
ARRAYFORMULA
SUM
INT
COUNTUNIQUE
EDIT:
Since the changes in the original scope significantly impacted my previous answer, here is a suggestion using a custom formula:
function checkFlags(){
var ss = SpreadsheetApp.getActive(); // get active Sheets
var ws = ss.getSheetByName("Sheet1"); // getting tab named "Sheet1"
var currentCellRange = ss.getActiveRange(); // getting active cell, in the context of a custom formula, it gets the one being calculated at the time
var rowIndex = currentCellRange.getRowIndex(); //getting current row number
var rowValues = ws.getRange(`${rowIndex}:${rowIndex}`).getValues()[0]; //getting row cells values
var sessionsList = []; //temp variable to store useful data from cells
for (var i = 0; i < rowValues.length; i++) { //reading cells on the row to create a date/flag array
var cell = rowValues[i]; //getting Range of current cell
if (typeof(cell) == 'boolean'){ //if the current cell has a boolean value, it is a session flag
var headerDate = ws.getRange(2, (i+2)).getDisplayValue(); //getting the header value on row 2 (current date for the session flag)
sessionsList.push({date: headerDate, session: cell});//storing date and session flag value on the temp variable
}
};
var groupBy = function(xs, key) { //handle function to proccess the sessionsList variable and group flag values by 'date'
return xs.reduce(function(rv, x) {
(rv[x[key]] = rv[x[key]] || []).push(x);
return rv;
}, {});
};
var tempGroupedArray = groupBy(sessionsList, 'date'); //grouping temp sessionsList by 'date'. This will return an array like [ { date: '<date>', session: true/false }, { date: '<date>', session: true/false }, ...]
for (dateFlags of Object.entries(tempGroupedArray)) {//looping through the `grouped by date` array
var tempCount = dateFlags[1].filter(x => x.session==true).length; //how many `trues` are for this date
if (tempCount > 1){ //if there is more than one session set as "true" for this date...
return 'FLAG'; //...immediately stop execution and return FLAG
}
};
//if it passed the loop above, it means there is no flags
return ''; //then return blank
}
NOTES: This custom formula will not update the result in the cell after a change on the flag values, you must delete/paste it to force if wanted.

Bombing out of google script due to an non declared array position

I have a very large 2 dimensional array (for this case lets just make it 20 rows x 5 columns). If I am on the nth row, I have to make check to see if the nth+1 row (lets say column 3) is less than the nth row. The problem is that the nth+1 row (data[nth+1] = []) has not been created so the script bombs.
(1) is there a way of telling if a row in an array has been created? or
(2) is there a way of telling the nth+1 array location has not been created? I tried isError_() but that just bombed script.
Example:
function tester() {
var data = [ [] , [] ];
data[1] = [];
data[1][1] = 10;
for (i=1 ; i < 5 ; i++) {
if (data[1][1] < data[i+1][1]) { Browser.msgBox("You have a problem", Browser.Buttons.OK);}
}
}
Also: does anyone have a better suggestion for a script editor than the google sheets script editor. It seems to be light years behind EXCELS VBA editor? EXCEL lets you pick the 3 or 4 variables you want to see and not the total list of all variable, which you then have to search through. Also, as you move through an function using breaks, the list of variable keeps changing and moving variable names around, quite confusing. Thank you for any suggestions.
Array length:
You can use the length property of the Array objects to limit the amount of iterations in your loop based on the length of your outer array, data.
You would have to change this:
for (i=1 ; i < 5 ; i++) {
To this:
for (var i = 1 ; i < data.length - 1; i++) {
Note:
If you initialize the loop with var i = 1, the first element in data gets ignored (the array indexes start at 0). Change that to var i = 0 if you want to avoid this.
Reference:
Array.prototype.length

Importing Url's of sheets shared with me into google sheets automatically whenever one is shared

I'm pretty new to excel or google sheets. The work place, that I work at does not have anything stream lined.
I'm trying to create my own work book that I can refresh everyday I log in so that I can have a list of things that I need to work on for that day.
One of the functions that I would like to have is, whenever a new sheet is shared with me on Google Sheets, I want the URL for that sheet to populate in one of the cells in my workbook automatically and arranged based on timestamp.
I was trying to search for this on Google, but I read that: shared with me docs are not stored anywhere specifically.
Any help or pointing me in the right direction is highly appreciated.
It is easy to fetch the files that have been shared with you. For that, you can simply call the Drive API's Files: list method specifying in the q parameter the sharedWithMe attribute.
Afterwards, you can use the SpreadsheetApp class to gather a spreadsheet and insert data into it. In this case, you can simply make several calls of apendRow() to insert the results.
Finally, properties can be used to store the status of the script (last date checked), so that it can know where to resume from. In this case below, we'll be saving the date in the LAST_DATE property.
Code.gs
var SPREADSHEET_ID = 'YOUR_SPREADSHEET_ID';
var SHEET_NAME = 'YOUR_SHEET_NAME';
function myFunction() {
var sheet = SpreadsheetApp.openById(SPREADSHEET_ID).getSheetByName(SHEET_NAME);
var lastDate = new Date(PropertiesService.getScriptProperties().getProperty('LAST_DATE'));
var currentDate = new Date();
var files = getFiles(lastDate);
for (var i=0; i<files.length; i++) {
var row = [
new Date(files[i].sharedWithMeDate),
files[i].title,
files[i].alternateLink,
files[i].sharingUser.emailAddress,
files[i].owners.map(getEmail).join(', ')];
sheet.appendRow(row);
}
console.log('lastDate: %s, currentDate: %s, events added: %d', lastDate, currentDate, files.length);
PropertiesService.getScriptProperties().setProperty('LAST_DATE', currentDate.toISOString());
}
function getEmail(user) {
return user.emailAddress;
}
function getFiles(lastSharedDate) {
var query = "sharedWithMe and mimeType = 'application/vnd.google-apps.spreadsheet'";
var res = Drive.Files.list({
q: query,
orderBy: "sharedWithMeDate desc",
fields: "*",
pageSize: 1000
});
// `query` parameter cannot compare sharedWithMeDate, so we do it afterwards
return res.items.filter(function (i) {
return (new Date(i.sharedWithMeDate) > lastSharedDate);
}).reverse();
}
You can set up the script to be ran periodically (i.e once a day, or more in case you'd need it) using Time-driven triggers.

Google script to send conditional emails based on cells in google sheets

I have a google sheet that I would like to have generate an email alert when one column is greater than the other. Specifically, column F > column G. Here is what I have so far, any advice would be greatly appreciated, as I do not have much skill writing functions.
function readCell() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Watch list");
var value = sheet.getRange("F2").getValue();
var value1 = sheet.getRange("G2").getValue();
if(value>value1) MailApp.sendEmail('example#gmail.com', 'subject', 'message');
};
Currently this only attempts to compare cell F2 to cell G2. Is there a way to make the function compare the entire F column against column G, and generate an email for each individual case where Fx > Gx ?
Thank you!!
You have to loop all over the range.
first instead of getting the content of one cell you'll need to get the content of all the column:
var value = sheet.getRange("F2").getValue();
become that
var values = sheet.getRange("F2:F").getValues();
(same for value1)
then you need to create an empty table that will collect the results:
var results = [];
and now you need to loop throught all the values:
for(var i=0;i<values.length;i++){
//do the comparaison and store result if greater for example
}
then you may send the result.
all put together it give something like that:
function readCell() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Watch list");
var values = sheet.getRange("F2:F").getValues();
var value1s = sheet.getRange("G2:G").getValues();
var results = [];
for(var i=0;i<values.length;i++){
if(values[i]<value1s[i]){
results.push("alert on line: "+(i+2)); // +2 because the loop start at zero and first line is the second one (F2)
}
}
MailApp.sendEmail('example#gmail.com', 'subject', results.join("\n"));
};
If you want to trigger that function automatically you'll also need to change the way you call the spreadsheet (instead of getActive.... you'll need to use openById)

Working with dates in breeze

I'm having some trouble working with dates.
I have an object with a date field:
public DateTime FechaInicio{get; set;}
This definition generates the following field in the database:
FechaInicio datetime not null
Making the request to the web service I get the date ( in the JSON ) in the following format:
"FechaInicio": "1982-12-02T00: 00:00"
And calling FechaInicio() on tne entity returns a javascript Date object.
Creating a new entity I get the following value:
createPalanca var = function () {
MetadataStore var = manager.metadataStore;
metadataStore.getEntityType palancaType = var ("Toggle");
palancaType.createEntity newPalanca = var ();
manager.addEntity (newPalanca);
//Here: newPalanca.FechaInicio () has the value in this format: 1355313343214
//Expected Date object here
newPalanca return;
};
After all, my real question is: What format should I use to assign new values ​​to date type fields?
Edit:
After doing some tests, I noticed that if I assign a Date object to the property, everything seems fine until we got to this line:
saveBundleStringified var = JSON.stringify (saveBundle);
saveBundle content is:
FechaInicio: Thu Dec 20 2012 00:00:00 GMT+0100 (Hora estándar romance)
and the saveBundleStringified:
"FechaInicio": "2012-12-19T23:00:00.000Z" <- I guess this is utc format
What finally is stored in the database is: 2012-12-19 23:00:00.0000000
When the result of the call to SaveChanges are returned , they are merged with the entities in cache at the function updateEntity which does this check: if (!core.isDate(val)) that returns false.
As a consequence it is created a new Date object with the wrong date:
function fastDateParse(y, m, d, h, i, s, ms){ //2012 12 19 23 00 00 ""
return new Date(y, m - 1, d, h || 0, i || 0, s || 0, ms || 0);
}
Correct me if I'm wrong, but I think that's the problem.
Sorry for taking so long...
There were bugs with Breeze's DateTime timezone serialization and the default DateTime values used for newly constructed entities with non-nullable date fields. These are fixed as of v 0.77.2. Please confirm if this set of fixes works for you.
And thanks for finding these.
And to answer your question, all date properties on your object should be set to javascript Dates. Breeze should handle all of the serialization issues properly.
Dates always scare me. My immediate instinct is that the browser and server are not on the same TimeZone; how that could be I don't know. In any case, it's bound to happen and I recall all kinds of fundamental problems with coordinating client and server on datetime. I think the usual recommendation has always been to keep everything in UTC and adjust what you display to the user in local time.
I rather doubt this is a helpful answer. I'm not sure what part Breeze should play in resolving this. Would welcome a suggestion that we can circulate and build consensus around.
Also can you clarify this statement:
When the result of the call to SaveChanges are returned , they are merged with the entities in cache at the function updateEntity which does this check: if (!core.isDate(val)) that returns false. As a consequence it is created a new Date object with the wrong date
What do you mean by "the wrong date"? And are you saying that Breeze thinks the incoming date value is in an invalid format (as opposed to being a date other than the one you expected)?
Yes, #Sascha, Breeze is using the Web Api standard for JSON formatting (Json.Net) and it is set for ISO8601 format as opposed to the wacky Microsoft format (which escapes me as I write this).
Breeze/Web Api seem to need the dates in some special format (ISO8601). Any other format did not work for me. moment.js solved the problem for me with setting and reading. Formatting is also nicely done if you use Knockout to display the date with a special binding.
entity.someDate(moment().utc().toDate()) // example
and it works.
You could also use this:
Date.prototype.setISO8601 = function(string) {
var regexp = "([0-9]{4})(-([0-9]{2})(-([0-9]{2})" +
"(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?" +
"(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?";
var d = string.match(new RegExp(regexp));
var offset = 0;
var date = new Date(d[1], 0, 1);
if (d[3]) {
date.setMonth(d[3] - 1);
}
if (d[5]) {
date.setDate(d[5]);
}
if (d[7]) {
date.setHours(d[7]);
}
if (d[8]) {
date.setMinutes(d[8]);
}
if (d[10]) {
date.setSeconds(d[10]);
}
if (d[12]) {
date.setMilliseconds(Number("0." + d[12]) * 1000);
}
if (d[14]) {
offset = (Number(d[16]) * 60) + Number(d[17]);
offset *= ((d[15] == '-') ? 1 : -1);
}
offset -= date.getTimezoneOffset();
time = (Number(date) + (offset * 60 * 1000));
this.setTime(Number(time));
};

Resources