XPages - Date comparison is wrong - xpages

For some reason my code is returning the backwards answer in my date comparison. (SSJS)
I have 2 code blocks, one is below, the other simply changes the line if(dtCreated < dtCutoff) to if(dtCreated > dtCutoff)
try{
var sdf = new java.text.SimpleDateFormat("dd-MM-yyyy");
var dtCreated = document1.getItemValueDate("CreatedDate");
var dtCutoff = new Date(2002, 03, 22, 00, 30);
dtCreated = dtCreated == null?"":sdf.format(dtCreated);
dtCutoff = dtCutoff == null?"":sdf.format(dtCutoff);
print("ONE: Created: " + dtCreated);
print("ONE: Cutoff: " + dtCutoff);
if(dtCreated < dtCutoff) {
print ("1.1 created before cutoff return true");
return true;
}else{
print ("1.2 created before cutoff return false")
return false;
}
}catch(e){
openLogBean.addError(e,this.getParent());
}
For some reason, it seems to be getting the result mixed up, where by the created date is after the cutoff and date yet it says created date is before the cutoff date, and vice versa.
Any ideas why? Date stuff has always been my achilles heel. Each code block is used in the loaded property of a custom control. My end goal is to show 1 custom control or the other if a document was created before or after a certain date.
Print from the console is below, thanks:
HTTP JVM: ONE: Created: 26-02-2020
HTTP JVM: ONE: Cutoff: 22-04-2002
HTTP JVM: 1.2 created before cutoff return false
HTTP JVM: TWO: Created: 26-02-2020
HTTP JVM: TWO: Cutoff: 22-04-2002
HTTP JVM: 2.1 created after cutoff return true

The problem is that you're comparing text strings, not dates. As such "22...." is earlier alphabetically than "26....". To compare, you either want to get the field value as a Java date and use .before(). This answer covers getting a Java date from a field Set a Java date Object from a Notes DateTime Object. Alternatively, create a Domino DateTime for dtCutOff and use the Domino DateTime's timeDifferenceDouble() method.

Related

How to set time in Netsuite using suitescript 2.0?

I can set time for timeofday type fields both UI/API.
I can set time for the time type field INITIAL TIME BUDGET as 16:55 using colon(:) separator in UI for Task.
I could not set time for that field as below using suitescript,
function load(recordType, id) {
return record.load({
type: recordType,
id: id
});
}
var recordType = "task"
var id = "123"
var objectRecord = load(recordType, id);
objectRecord.setValue("estimatedtime", "16:55");
var updatedId = objectRecord.save({});
I get this error
You have entered an Invalid Field Value 16:55 for the following field: estimatedtime
I tried the following cases,
"16:55" - Invalid Field Value
16:55 - UNEXPECTED_ERROR
16.55 - No error, but set as "estimatedtime":"16:33"
How to set time for time type field?
You need to create a Date object. For example, say you pass "13:00", you'll need to do something like:
dateStr = "13:00";
d = new Date();
dateParts = dateStr.split(":");
d.setHours(+dateParts[0]);
d.setMinutes(+dateParts[1]);
And then:
objectRecord.setValue("estimatedtime", d);
you have to set only hour value.
Format has to 24 hours.
objectRecord.setValue("estimatedtime", 23);

Error message "cannot find function getFullYear(...)" when entering date and trying to save the record

We are trying in a RESTLet to access the sublist "demandplandetail" from a NetSuite Item Demand Plan. Everything goes fine until a certain point. We are able to load it and process the demandplan for 2020. However, here it gets frustrating.
We know (can see from NetSuite) that there is data also for 2021. However, to access that from SuiteScript seems very difficult.
1st solution) The item demand plan has the field "year". OK, just set that to 2021, save and reload the record. Result: saving ignored, year still is 2020.
2nd solution) Set the year using a Date object as in:
var demandPlan = record.load(...)
var d = new Date();
demandPlan.setValue({
fieldId: 'year',
value: d
});
Gives the following:
:"TypeError: Cannot find function getFullYear in object NaN. (NLRecordScripting.scriptInit$lib#59)","stack":["setDatesForMonthAndYear(NLRecordScripting.scriptInit:108)","anonymous(N/serverRecordService)"
on saving the record. I also get the same using (various) strings adhering to acceptable date formats (as in '1/1/2021'). I have also tried the format package giving me a date string -> the same result.
Also read somewhere that you may need to set the start date (field 'startdate') in the record. Tried several variations but it stubbornly refuses :(.
Wonder if anyone has seen anything similar?
Best Regards,
Toni
Hi Please try the below code also check if you're passing date object to the field not the date string.
function formatDate() {
var dateROBD = format.parse({
value: new Date(),
type: format.Type.DATE
});
// this line optional if you want to try with or else ignore this
dateROBD = convertUTCDateToLocalDate(new Date(dateROBD));
return dateROBD;
}
function convertUTCDateToLocalDate(date) {
var newDate = new Date(date.getTime() + date.getTimezoneOffset() * 60 * 1000);
var offset = date.getTimezoneOffset() / 60;
var hours = date.getHours();
newDate.setHours(hours - offset);
return newDate;
}
OK, mystery solved. Turned out that this is not supported in SuiteScript 2.0 but you need to use 1.0.

Wrong date format with toLocaleString on server side

Using this on a server side (a Firebase function, nodejs )
var d=new Date();
var date = d.toLocaleString('default', { month: 'long'}) + ", " + d.getFullYear();
I am expecting to get March, 2020 , since this is what i get on the JS client side, but instead when run on the server side i get - M03, 2020 .
I tried the following code:
const date = require('date-and-time');
var d = new Date();
var myDate = d.toLocaleString('default', { month: 'long'}) + ", " + d.getFullYear();
console.log(myDate);
Output:
March, 2020
Now, if you are trying to store a Javascript Date object into Firebase, this object will be stored as a Timestamp object. I think this would explain the reason why you are noticing some discrepancies in the format.
Optionally, you can convert the Date object to String and store it in Firebase as such. This is more human-readable than ISO 8601 and Timestamp - 0001-01-01T00:00:00Z
You can read more about this in the following documentation about Timestamp and Data types. Moreover, there exists a Timestamp built-in method toDate() that returns a new Date corresponding to a certain timestamp, if conversion is needed.

How to check if a value displays in particular format in XML response in soapui

I am trying to use using script assertion or by groovy code to check if a value under an element in xml response exits in particular format.
Sample response :
<ns5:price>99.99</ns5:price>
<ns5:date>2016-04-04</ns5:date>
<ns5:quantity>1</ns5:quantity>
For example, I want to check if any price exists and in format 5,4, same for date to see if date in format yyyy-mm-dd and quantity is not 0.
All the values are dynamic.
I am wondering if we can use using a script assertion or can use point and click with soap ui pro.
I am just learning soapui pro and groovy.
Thanks.
You can create an script assertion in your SOAP testStep and make the validations there. In the script assertion you can parse the response using a XmlSlurper, then get the desired nodes using findAll and perform all the asserts. You can do it using something like:
// from script assertion get the response
def response = messageExchange.getResponseContent()
// parse the XML
def xml = new XmlSlurper().parseText(response)
// get all prices
def prices = xml.'**'.findAll { it.name() == 'price' }
// check that each one has at "max 5 digits.max 4 digits"
prices.each { assert it ==~ /\d{0,5}\.\d{0,4}/ }
// get all dates
def date = xml.'**'.findAll { it.name() == 'date' }
// check the date has yyyy-MM-dd format
date.each { assert it ==~ /\d{4}\-\d{2}\-\d{2}/ }
// get all quantities
def quantity = xml.'**'.findAll { it.name() == 'quantity' }
// check that all quantities are > 0
quantity.each { assert it.text().toInteger() > 0 }
NOTE: To add an script assertion to your request, click on Assertions tab on left down corner of your SOAP Request panel:
Then right click on it and select add Assertion:
In a new panel select Script from a left side menu and then Script Assertion on the right options:
Finally use the code provided and make your checks :):

getColumnValues vs cycle through a NotesViewNavigator

in this post Return from first column of a categorized view when using readers fields I raised the issue that if I do getColumnValue(0) on a categorized view I just the unique category values, but because of Reader fields there could be categories that the user does not have access to the documents under it. The other option is to create a NotesViewNavigator and iterate through the navigator and build a treeMap of the values.
My concern is that the view could contain thousands of entries and it would have to cycle through all the entries to build the category list which would typically have maybe 10 -12 entries.
So my question is what is the performance hit and scalability of the NotesViewNavigator process and/or is there a better way to get the categories in a view and recognize the users Reader rights.
New Edits
Can't seem to get this to work. I have a single categorized view and use this code WFSUtils.sysOut() simply prints to the console.
vw.setAutoUpdate(false);
var nav:NotesViewNavigator = vw.createViewNav();
nav.setEntryOptions(NotesViewNavigator.VN_ENTRYOPT_NOCOUNTDATA);
nav.setBufferMaxEntries(400);
nav.setMaxLevel(0);
var rtn:java.util.TreeMap=new java.util.TreeMap();
var entry:NotesViewEntry = nav.getFirst();
try{
while (entry != null){
WFSUtils.sysOut("Entry not null");
var thisCat:String = entry.getColumnValues().firstElement().toString();
WFSUtils.sysOut("thisCat = " + thisCat);
rtn.put(thisCat,"Nothing");
WFSUtils.sysOut("did put " + thisCat)
var tEntry:NotesViewEntry = nav.getNextCategory(entry);
entry.recycle();
entry = tEntry;
tEntry.recycle();
}
viewScope.put("vsCats", rtn.keySet());
}catch(e){
WFSUtils.sysOut("Error in getCategory " + e.toString())
}
the console print out is this:
25/08/2014 11:47:36 AM HTTP JVM: Get Navigator
25/08/2014 11:47:36 AM HTTP JVM: Entry not null
25/08/2014 11:47:36 AM HTTP JVM: thisCat = Approved~Bill Fox^WFS Automated Back end Process Example
25/08/2014 11:47:36 AM HTTP JVM: did put Approved~Bill Fox^WFS Automated Back end Process Example
25/08/2014 11:47:36 AM HTTP JVM: Error in getCategory Method NotesViewNavigator.getNextCategory(lotus.domino.local.ViewEntry) not found, or illegal parameters
The view has 9 categories so I would expect it to do 9 getNextCategories. I changed it to do getNext and the console out put is:
25/08/2014 11:52:42 AM HTTP JVM: Get Navigator
25/08/2014 11:52:43 AM HTTP JVM: Entry not null
25/08/2014 11:52:43 AM HTTP JVM: thisCat = Approved~Bill Fox^WFS Automated Back end Process Example
25/08/2014 11:52:43 AM HTTP JVM: did put Approved~Bill Fox^WFS Automated Back end Process Example
25/08/2014 11:52:43 AM HTTP JVM: Entry not null
25/08/2014 11:52:43 AM HTTP JVM: Error in getCategory Exception occurred calling method NotesViewEntry.getColumnValues()
25/08/2014 11:52:43 AM HTTP JVM: null
so it fails on the getColumnValues which worked on the first time through but not the second - not sure where the JVM: null is coming from.
any ideas greatly appreciated.
It looks like the View-design-level option "Don't show empty categories" does this for you - I'd previously assumed it was just a tip-off to the client to hide them, but it looks like it affects the behavior of ViewNavigator as well (which otherwise would show the full categories as well).
Once you have that checked, something like this may do the trick:
List<String> categories = new ArrayList<String>();
View view = database.getView("Some View");
view.setAutoUpdate(false);
ViewNavigator nav = view.createViewNav();
nav.setEntryOptions(ViewNavigator.VN_ENTRYOPT_NOCOUNTDATA);
nav.setBufferMaxEntries(400);
nav.setMaxLevel(0);
ViewEntry entry = nav.getFirst();
while (entry != null) {
Vector<?> columnValues = entry.getColumnValues();
String category = String.valueOf(columnValues.get(0));
categories.add(category);
entry.recycle(columnValues);
ViewEntry tempEntry = entry;
entry = nav.getNext();
tempEntry.recycle();
}
I believe that that should be the fastest/safest way to do it at that point. setMaxLevel(0) means that the first/next operations will include only categories (or whatever is your top level), while the other ViewNavigator settings are for performance tweaking.
No, I don't think you have to cycle through all the entries. Without having Domino Designer at hand right now, this is a bit of a rough guess (usually I do a quick test drive before answering here), but I'm quite confident it should work like this:
Just get to the first entry which in your case must be a category, then use .getNextSibling or .getNextCategory (careful if the view has multiple category levels!) jumping from category to category, and skipping all the other entries.
Depending on how the view index is set up, you might also check if there are any children available.
Just to be complete: make sure you set the parent view's AutoUpdate property to false; depending on the size of the view you might also want to experiment with various cache sizes; and of course don't forget to recycle, but you know that, I guess ;)
See also here (= AutoUpdate), here (= recycle properly) and here (= performance tip).
Hope this helps

Resources