I am searching for a way to select just a calendar week with a DatePicker.
Is there a way to configure that control in a way, that it allows to pick a week and sends a DateTime element out of this week?
I detected the following entry with a list of format options, but week formatting seems not working:
http://scn.sap.com/community/developer-center/front-end/blog/2013/04/28/working-with-odata-dates
This code seems not working:
new sap.m.DatePicker({
value : {
path : "DateTime",
type : new sap.ui.model.type.Date({pattern: "w yy"})
}
}),
The binding is to OData property DateTime of type Edm:DateTime
Few things to be noticed:
Though SAPUI5 says it supports weeks in year, it doesn't currently! //I tested
why? in DateFormat.js file of SAPUI5
case "weekInYear":
sWeek = "";
//TODO getWeek does not exist on Date object
//-> this is a preparation for a future or custom week support
if (oDate.getWeek) {
sWeek += oDate.getWeek();
}
aBuffer.push(jQuery.sap.padLeft(sWeek, "0", oPart.iDigits));
break;
As you can see, its in TODO list!!
Workaround? Yes :
jQuery.sap.require("sap.ui.core.format.DateFormat");
//define getWeek function
Date.prototype.getWeek = function () {
var d = new Date(+this);
d.setHours(0, 0, 0);
d.setDate(d.getDate() + 4 - (d.getDay() || 7));
return Math.ceil((((d - new Date(d.getFullYear(), 0, 1)) / 8.64e7) + 1) / 7);
};
var oDateFormat = sap.ui.core.format.DateFormat.getDateInstance({
pattern: "w y"
});
var oDatePicker = new sap.m.DatePicker({
dateValue: new Date(),
displayFormat: "w y"
})
JSBin code piece is here
Related
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.')
}
I use Google sheet and Cryptofinance.ai to retreive cryptocurrency prices. I have one script that works well : it appends data periodically from one row in tab A to save them in a tab B so I can make graphs and charts.
Now I'd like to add date + 1 year in the next row. Idealy, each time the script is triggered, it make two new rows : The one with the data as it is now and the one with the date + 1 year.
If you curious and want to know why I want to do that is is to make projection price using this
formula in another tab : =TREND(filter(B2:B,B2:B<>""),filter(A2:A,B2:B<>""),filter(A2:A,(N(B2:B)=0)*(A2:A>0)))
Here is my script now:
// [START modifiable parameters]
var rangeToLog = 'Portefeuille!A28:L28';
var sheetToLogTo = 'Archive BTC/USD KRAKEN';
// [END modifiable parameters]
////////////////////////////////
/**
* Appends a range of values to the end of an archive sheet.
* A timestamp is inserted in column A of each row on the archive sheet.
* All values in rangeToLog go to one row on the archive sheet.
*
* #OnlyCurrentDoc
*/
function appendValuesToArchiveBTCUSDKRAKENSheet() {
// version 1.4, written by --Hyde, 30 January 2020
// - use Array.prototype.some() to skip empty rows when concating
// - see https://support.google.com/docs/thread/27095918?msgid=27148911
// version 1.3, written by --Hyde, 26 January 2020
// - see https://support.google.com/docs/thread/26760916
var ss = SpreadsheetApp.getActive();
var valuesToLog = ss.getRange(rangeToLog).getValues();
var logSheet = ss.getSheetByName(sheetToLogTo);
if (!logSheet) {
logSheet = ss.insertSheet(sheetToLogTo);
logSheet.appendRow(['Date time', 'Data']);
}
var rowToAppend = [new Date()].concat(
valuesToLog.reduce(function concatArrays_(left, right) {
var arrayContainsData = right.some(function isNonBlanky_(element, index, array) {
return element !== null && element !== undefined && element !== '';
});
return arrayContainsData ? left.concat(right) : left;
})
);
logSheet.appendRow(rowToAppend);
}
NOW :
What I want to do:
The easy fix is to simply add another appendRow() call at the end of your function with the one year from now value.
function appendValuesToArchiveBTCUSDKRAKENSheet() {
// ...
logSheet.appendRow(rowToAppend);
logSheet.appendRow([new Date(new Date().setFullYear(new Date().getFullYear() + 1))]);
}
A more complex solution, but with better execution time, would have you print both rows in a single setValues() call. This follows the best practice of using batch operations, but I suspect that the easier solution above is adequate for your purpose. I do encourage you, however, to try implementing the batch operation if you want to improve your apps script skills.
Finally, after some research I came to this :
function expCalc(){
delLastNRows();
appendValuesToArchiveBTCUSDKRAKENSheet();
}
function delLastNRows(n){
var n=n || 1;//allows you to delete last three rows without passing function a parameter.
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('Archive BTC/USD KRAKEN');
var lr=sh.getLastRow();
if(lr>=n){
for(var i=0;i<n;i++){
sh.deleteRow(sh.getLastRow());
}
}
}
// [START modifiable parameters]
var rangeToLog = 'Portefeuille!A28:L28';
var sheetToLogTo = 'Archive BTC/USD KRAKEN';
// [END modifiable parameters]
////////////////////////////////
/**
* Appends a range of values to the end of an archive sheet.
* A timestamp is inserted in column A of each row on the archive sheet.
* All values in rangeToLog go to one row on the archive sheet.
*
* #OnlyCurrentDoc
*/
function appendValuesToArchiveBTCUSDKRAKENSheet() {
// version 1.4, written by --Hyde, 30 January 2020
// - use Array.prototype.some() to skip empty rows when concating
// - see https://support.google.com/docs/thread/27095918?msgid=27148911
// version 1.3, written by --Hyde, 26 January 2020
// - see https://support.google.com/docs/thread/26760916
var ss = SpreadsheetApp.getActive();
var valuesToLog = ss.getRange(rangeToLog).getValues();
var logSheet = ss.getSheetByName(sheetToLogTo);
var sheet = ss.getSheets()[0]
if (!logSheet) {
logSheet = ss.insertSheet(sheetToLogTo);
logSheet.appendRow(['Date time', 'Data']);
}
var rowToAppend = [new Date()].concat(
valuesToLog.reduce(function concatArrays_(left, right) {
var arrayContainsData = right.some(function isNonBlanky_(element, index, array) {
return element !== null && element !== undefined && element !== '';
});
return arrayContainsData ? left.concat(right) : left;
})
);
logSheet.appendRow(rowToAppend);
logSheet.appendRow([new Date(new Date().setFullYear(new Date().getFullYear() + 1))]);
}
Works like a charm !
I want to add some quick filters using the ui of google sheets. Currently I want to allow the user to click "show last month" to only see the data of the last month. The dates are written in the first column.
Now I prefer to use the filter of google sheets before just printing the values into the sheet, to allow the user to further modify that filter.
Thus I am trying to build filterCriteria using SpreadsheetApp.newFilterCriteria().whenDateEqualToAny(dates) and I am parsing an array of valid dates. In the documentation it says I have to put a "Date[]" - doesn't that mean an array of dates?
Below the error message and my code:
Error message (linked to the line "var filterCriteria..."):
"Exception: The boolean condition can not have multiple values for equality checks for non-data source objects"
My code:
function showLastMonth() {
var ss = SpreadsheetApp.getActive()
var sheet = ss.getSheetByName('evaluation')
var now = new Date()
var thisYear = now.getFullYear()
var thisMonth = now.getMonth()
if(thisMonth == 0){var startMonth = 11; var startYear = thisYear - 1}
else{var startMonth = thisMonth - 1; var startYear = thisYear}
var startDate = new Date(startYear, startMonth, 1)
var endDate = new Date(thisYear, thisMonth, 0)
var dates = getDateArray(startDate, endDate)
var filter = sheet.getFilter()
if(filter == null ){
var range = sheet.getDataRange()
var filter = range.createFilter()
}
var filterCriteria = SpreadsheetApp.newFilterCriteria().whenDateEqualToAny(dates)
filter.setColumnFilterCriteria(1, filterCriteria)
}
getDateArray = function(startDate, endDate){
var startYear = startDate.getFullYear()
var startMonth = startDate.getMonth()
var dateArray = []; dateArray.push(startDate)
var date = startDate; var day = date.getDay()-1
while(date<endDate){
day++
date = new Date(startYear, startMonth, day)
if(date<=endDate){dateArray.push(date)}
}
return dateArray;
}
I believe your goal as follows.
You want to hide the rows of the values except for dates using the basic filter.
You want to achieve this using Google Apps Script.
Issue and workaround:
In the current stage, it seems that array of whenDateEqualToAny(array) is required to be the length of 1. I think that this is the reason of your issue. So for example, when var filterCriteria = SpreadsheetApp.newFilterCriteria().whenDateEqualToAny([dates[0]]) is used, no error occurs. This situation is the same with the setBasicFilter request of Sheets API. Unfortunately, it seems that this is the current specification. But, the official document says The acceptable values. which uses the plural form. Ref So I also think that this is not correct for the actual situation as mentioned by TheMaster's comment.
In order to achieve your goal, in this case, I would like to propose the following 2 patterns.
Pattern 1:
In this pattern, using setHiddenValues(), the values except for the values of dates in your script are set as the hidden values.
Modified script:
When your script is modified, please modify as follows.
From:
var filterCriteria = SpreadsheetApp.newFilterCriteria().whenDateEqualToAny(dates)
To:
var obj = dates.reduce((o, e) => Object.assign(o, {[`${e.getFullYear()}\/${e.getMonth() + 1}\/${e.getDate()}`]: true}), {});
var range = sheet.getRange("A1:A");
var dispValues = range.getDisplayValues();
var hiddenValues = range.getValues().reduce((ar, [a], i) => {
if (a instanceof Date && !obj[`${a.getFullYear()}\/${a.getMonth() + 1}\/${a.getDate()}`]) {
ar.push(dispValues[i][0]);
}
return ar;
}, []);
var filterCriteria = SpreadsheetApp.newFilterCriteria().setHiddenValues(hiddenValues).build();
Pattern 2:
In this pattern, using whenNumberBetween(), the values of dates in your script are shown. In this case, it is required to convert the date object to the serial number.
Modified script:
When your script is modified, please modify as follows.
From:
var filterCriteria = SpreadsheetApp.newFilterCriteria().whenDateEqualToAny(dates)
To:
var filterCriteria = SpreadsheetApp.newFilterCriteria().whenNumberBetween(
(dates[0].getTime() / 1000 / 86400) + 25569,
(dates.pop().getTime() / 1000 / 86400) + 25569
).build();
The conversion from the date object to the serial number was referred from this thread.
References:
setHiddenValues(values)
whenNumberBetween(start, end)
I'm new to Protractor and here I'm trying to test an angularjs date picker from Protractor.
I tried to find a way to do this and this article was the only thing I found and It is not very clear to use
If someone know how to test please help.
What I need is to select today's date.
Thanks in advance :)
edit -
alecxe, here is the screen shot of my date picker. Unfortunately cannot provide the link of the page. :(
<input
class="form-control ng-pristine ng-valid ng-not-empty ng-touched"
ng-model="invoice.fromdate"
data-date-format="yyyy-MM-dd"
data-date-type="string"
data-max-="" data-autoclose="1"
bs-datepicker=""
ng-change="dateRange()"
type="text">
I think you can avoid manipulating the datepicker manually and instead set the date either by just sending the keys with a today's date value:
var picker = element(by.model("invoice.fromdate"));
// get today's date
var today = new Date();
var dd = today.getDate();
var mm = today.getMonth()+1; //January is 0!
var yyyy = today.getFullYear();
if(dd<10) {
dd='0'+dd
}
if(mm<10) {
mm='0'+mm
}
today = mm+'/'+dd+'/'+yyyy;
picker.clear();
picker.sendKeys(today);
Or, by setting the associated model's value directly:
picker.evaluate("invoice.fromdate= '" + today + "'");
Two methods have been suggested so far: 1. sendKeys() 2. evaluate()
I'm a bit new to protractor but I think both of these have issues in the case of not having an input element that spawns the calendar, i.e.:
Sendkeys() works only if date is on an element and the uib-datepicker is a dropdown sort of deal. This didn't help me because my datepicker element is a standalone and isn't paired with an input element.
evaluate() doesn't update angular's actual model in the browser (which begs the question of how useful evaluate actually is...). According protractor docs, evaluate, "Evaluates the input as if it were on the scope of the current underlying elements." In my case I want to test whether the date generated by the datepicker gets to my enpdpoint via a post request and then back again (hence e2e) without getting effed (corrupted), therefore, I need my date to be on my angular model in the browser instance, not just in the browser-driver environment or whatever the runtime environment of the protractor test is. I could be wrong about this.
This expect() passes but the ng-form is invalid (i'm assuming b/c model in browser wan't actually updated to receive the date I'm trying to pass in.):
function convertToPickerDate(date) {
var date = new Date(date);
var dd = date.getDate();
var mm = date.getMonth() + 1; //January is 0!
var yyyy = date.getFullYear();
var yy = yyyy.toString().slice(2);
return mm + '/' + dd + '/' + yy;
}
// expect passes, but form is invalid - DON'T USE for standalone cal
it('should enter start date in date picker', function () {
offerStart = convertToPickerDate(myData.startDate);
var offerStartPicker = element(by.model('current.startDate'));
offerStartPicker.evaluate("current.startDate = '" + offerStart + "'");
offerStartPicker.evaluate("current.startDate").then(function (value) {
expect(value).toBe(offerStart);
});
})
but the ng-form that the element is on is invalid...
My solution uses css selection and arrow keys to select a date relative to today:
Shipment Start Date: <em id="offerStartPrint">{{current.startDate | date:'shortDate' }}</em>
<div id="offerStart"
name="offerStart"
uib-datepicker
ng-model="current.startDate"
class=""
ng-change="setStartDate()"
datepicker-options="startDateOptions"
required></div>
</div>
function convertToPickerDate(date) {
var date = new Date(date);
var dd = date.getDate();
var mm = date.getMonth() + 1; //January is 0!
var yyyy = date.getFullYear();
var yy = yyyy.toString().slice(2);
return mm + '/' + dd + '/' + yy;
}
it('should enter expiration date in date picker using tabs and arrows :)', function () {
// select today element on uib-datepicker calendar
// div#offerStart elem has date model
var calToday = element(by.css('div#offerStart table td button.active'));
calToday.sendKeys(protractor.Key.ARROW_DOWN); // one week away
calToday.sendKeys(protractor.Key.ARROW_DOWN); // two weeks away
calToday.click(); // if you remove this click no date is entered
var fortnightAway = new Date(Date.now() + 12096e5);
fortnightAwayString = convertToPickerDate(fortnightAway);
expect(element(by.id('offerStartPrint')).getText()).toBe(fortnightAwayString);
})
Left and right arrows can be used to increment/decrement date by one day at a time.
up/down arrows can be used to inc/dec one week at a time.
One could probably figure out how to arrow through months and years as well.
var data_picker = element(by.model("invoice.fromdate"));
// select current date with date function
var current_date = new Date();
var day = today.getDate();
var month = today.getMonth()+1; //By default January count as 0
var year = today.getFullYear();
if(day<10) {
day='0'+day
}
if(month<10) {
month='0'+month
}
current_date = month+'/'+day+'/'+year;
data_picker.clear(); // Note if you are facing error message related to clear. Comment this line
data_picker.sendKeys(today);
Hope this will work
I am trying to disable all the date in the DatePicker GWT component, here is my sample of code :
datePicker.addShowRangeHandler(new ShowRangeHandler<Date>() {
public void onShowRange(ShowRangeEvent<Date> event) {
System.out.println("First date : " + event.getStart());
System.out.println("Last date : " + event.getEnd());
System.out.println("First date from date picker : " + datePicker.getFirstDate());
System.out.println("Last date from date picker : " + datePicker.getLastDate());
// Disable all the date shown by the Calendar
List<Date> dateList = new ArrayList<Date>();
Date currentDate = event.getStart();
while(!currentDate.after(datePicker.getLastDate())) {
Date updateDate = CalendarUtil.copyDate(currentDate);
dateList.add(updateDate);
CalendarUtil.addDaysToDate(currentDate, 1);
}
for(Date date : dateList) {
System.out.println("Date selected : " + date);
System.out.println("date visibility : " + datePicker.isDateVisible(date));
}
}
});
Date visibility is always false , it keep telling me that all the date are not visible, but it should be true since it' between the first date and last date, anybody know a way to disable date in calendar?, so if tried the method setTransientOnEnables() on the datePicker for any of the date I keep getting an exception as the date arenot visible.
I had tried also impleenting my own DefaultClendarView but it requires protected class which is not available by GWT.
I had similar problems. I was trying to disable dates in the future.
I eventually found out that start and end dates are final variables. When I tried to change the start date, I got undefined behavior (In some cases my browser freezed completely.). The solution was to copy the start date and manipulate the copy instead of the start date directly..
This is what I ended up with:
datePicker.addShowRangeHandler(new ShowRangeHandler<java.util.Date>()
{
#Override
public void onShowRange(ShowRangeEvent<Date> event)
{
Date start = event.getStart();
Date temp = CalendarUtil.copyDate(start);
Date end = event.getEnd();
Date today = new Date();
while(temp.before(end))
{
if(temp.after(today) && datePicker.isDateVisible(temp))
{
datePicker.setTransientEnabledOnDates(false,temp);
}
CalendarUtil.addDaysToDate(temp, 1);
}
}
});
This should work in GWT 2.4. Earlier versions are not tested.