My MWLUG presentation: Elementary!

MWLUG 2017 - Elementary! Yesterday I presented at MWLUG, and I want to share my presentation with both the ones attending and anyone who was not able to be there. I am posting two version, one with just the slides, and one with speaker notes, where I tried to capture the content, if not the exact verbiage of the session. I hope to be able to post the demo database with the code later this week or early next week.  

1 Comment

My presentation at MWLUG

Tomorrow, August 8, you are welcome to attend my presentation "Elementary!" at MWLUG 2017. In about 45 minutes I will show how to easily incorporate Watson functionality in your own applications, both on the web and in your Notes client applications. I will be using Node-RED and IBM BlueMix to do this, and I think many will be surprised how easy it is, and how little code is needed. For example I will implement translation from English to Spanish with two (2) lines of server side code. To call this from the web you just need another handful of lines. I hope to see you tomorrow at 5pm!

0 Comments

A few openings left for MWLUG 2017 

There are a a few openings available for MWLUG in a couple of weeks. The conference is taking place August 8-10 in Alexandria, VA. It is shaping up to be a great experience, with over 50 sessions, two free workshops  as well as social events and two round table discussions with IBM on the future of development. Among the many great presenters you will find 20 IBM Champions, as well as several IBMers. The early bird registration has expired, but if you are a previous attendee, you get $25 off the regular price of $100. If you haven't registered yet, don't miss out on this great conference! I hope to see you at MWLUG. My session Elementary - Incorporating BlueMix, Node-RED and Watson in Domino applications will be Tuesday, August 8 at 5pm.

0 Comments

Load and Modify External File in NetSuite

When building a suitelet in NetSuite you can either inject HTML, CSS and Javascript in a field, or generate a full HTML page and render it into the suitelet. No matter which method you use, you normally have to write line after line of SuiteScript code where you build the HTML using string concatenation. This is not only difficult and tedious to write, making sure you match all the single and double quotes and semi colons, it also makes the code much harder to maintain. What if you could just create a regular HTML file, put it in the File Cabinet and then render it into a suitelet? And what if you could use one line of code to inject values from NetSuite in the correct place in the HTML? This could be search results from the use of my search function. That is what the function looks like: /** * Load file from NetSuite File Cabinet and replace placeholders with actual values * * Version Date Author Remarks * 1.00 07 Nov 2016 kmartinsson Created class/function * 1.01 08 Nov 2016 kmartinsson Consolidated setValue and setHTML into * one method and added noEscape parameter */ // ***** Read and process external file, replacing placeholders with proper values ***** function ExternalFile(filename) { //Get the file by path/name, can also be internal id var fileId = filename; // Load file content and store data var file = nlapiLoadFile(fileId); var data = file.getValue(); this.content = data; this.setValue = function(placeholder, value, noEscape) { // Check if noEscape is passed, if it is and if true then don't escape value. // This is needed when value contains HTML code. if (typeof noEscape == "undefined") { this.content = this.content.replace(new RegExp(placeholder, 'g'), nlapiEscapeXML(value)); } else { if (noEscape == true) { this.content = this.content.replace(new RegExp(placeholder, 'g'), value); } else { this.content = this.content.replace(new RegExp(placeholder, 'g'), nlapiEscapeXML(value)); } } } this.getContent = function() { return this.content; } } Reference this function in your Suitescript 1.0 code like this: // Load extrenal HTML file var html = new ExternalFile("SuiteScripts/BinTransfer.html"); // Insert NetSuite URL for CSS files var cssFileName = nlapiLoadFile("SuiteScripts/css/drop-shadow.css").getURL(); html.setValue("%cssDropShadow%", cssFileName, true); cssFileName = nlapiLoadFile("SuiteScripts/css/animate.css").getURL(); html.setValue("%cssAnimate%", cssFileName, true); // Insert array returned from a search html.setValue("%binarray%", JSON.stringify(binArray), true); // Replace placeholders with values html.setValue("%showAll%", "false"); html.setValue("%company%", companyName); The last (optional) argument "noEscape" decides if the value should be URL encoded (false/omitted) or not (true) using the function nlapiEscapeXML(). In most cases you don't need to specify this argument, but if you need to pass HTML or other code into the function you need to set it to true to avoid the code being modified. As you can see in my example above, I get the NetSuite URL for my CSS files as well. Instead of hard coding the NetSuite URL into the HTML page, I calculate it and insert it when the page is loaded. Not only does it make the page easier to read the code, it also makes it much easier to maintain. This is…

0 Comments

Easy NetSuite Search

In an attempt to expand my knowledge to other platforms than Notes and Domino, I have now been working with NetSuite for a number of months. I have mainly been working with the ERP part of the cloud based system. The language used is called SuiteScript, and it is Javascript with a NetSuite-specific API to work directly with the databases. Knowing Javascript makes it easy to get started, just like knowing Visual Basic makes it easy to learn Lotusscript. And just like with Lotusscript, you have to learn the NetSuite specific functions. Since I like my code clean and easy to read (which will make future maintenance easier), I have created a number of functions to encapsulate NetSuite functionality. The first one I created was to search the database. The search in NetSuite is done by defining the columns (i.e. fields) to return as an array of search column objects. Then an array of search filters is created, and finally the search function is called, specifying what record type to search and passing the two arrays to it as well. This is a lot of code, and with several searching in a script it can be very repetetive, not to mention hard to read. Here is an example of a traditional NetSuite search: var filters = []; filters.push(new nlobjSearchFilter('item', null, 'anyof', item)); filters.push(new nlobjSearchFilter('location', null, 'noneof', '@NONE@')); var columns = []; columns.push(new nlobjSearchColumn('internalid')); columns.push(new nlobjSearchColumn('trandate').setSort()); columns.push(new nlobjSearchColumn('location')); var search = nlapiSearchRecord('workorder', '', filters, columns); Using my function, the code wold be simplified to this: var search = new Search('workorder'); search.addFilter('item', null, 'anyof', item); search.addFilter('location', null, 'noneof', '@NONE@'); search.addColumn('internalid')); search.addColumn('trandate',true); // Sort on this column search.addColumn('location'); var search = search.getResults(); The function also support saved searches. Simply add the following line: search.useSavedSearch('custsearch123'); There is a limitation in SuiteScript so that a maximum of 1000 records can be returned by a normal search. There is a trick to bypass this, but it requires some extra coding. So I thought why not add this into the function as default? So I did. Below is the code for the search function. I usually put it in a separate file and reference it as a library in the scripts where I want to use it. This first version does not support more advanced functionality like formulas in the filters. But for most searches this function will be usable. /** * Module Description * * Version Date Author Remarks * 1.00 11 Nov 2016 kmartinsson * 1.05 27 May 2017 kmartinsson Added support for record type in constructor * */ //***** Encapsulate search functionality ***** function Search(recordtype) { this.columns = []; this.filters = []; // If record type/ID is passed, no need to set it later if (recordtype == null || recordtype == "") { this.recordType = null; } else { this.recordType = recordtype; } // Set internal id of saved search to null this.internalId = null; // *** Set array of column names to return this.setColumns = function(columnArray) { for (var i = 0; i…

1 Comment

IBM Connect 2017 – I will be speaking in San Francisco

I will be speaking at IBM Connect in San Francisco now in February. Rob Novak has resurrected "The Great Code Giveaway" and asked me to present it together with him. Who would turn down that opportunity? So some time between February 21 and 23 you can see Rob and me on stage at Moscone West. The exact time and location has not been announced yet. I hope to see you in San Francisco and that you will find our presentation and code useful!

1 Comment

New life for “old” technology

A few weeks ago I visited the town of Antigua in Guatemala for 5 days. My wife used to live in Guatemala, working for a non-profit organization back in the late 1990's, and she wanted to show me how beautiful the country is. Of course my wife was absolutely right. The town was colorful and relaxing, people were very nice and the food was delicious. When I in the past heard "Guatemala" I thought of rain forests and hot and humid conditions. But in Antigua the temperature was perfect, about 70° F (21° C) during the day and 55° F (13° C) at night. We slept with open windows every night, with a view of one of the nearby volcanoes. No need for air conditioning, we could just enjoy the clean fresh air. But what is really amazing is how resourceful people in Guatemala are. They reuse things in a very clever way, with the most striking being the "chicken bus", the local transportation system between cities. When American school buses get old they are sold at auctions for a couple of thousand dollars. Many of them are purchased by Guatemalans who drive them down through Mexico to Guatemala. There they are fitted with upgraded powerful diesel engines (often the same ones used to power semi-trucks), repainted and outfitted with additional lights (sometimes neon lights), roof racks for cargo and plenty of chrome. Often they get a new hood from a semi-truck as well. The US truck manufacturer International used to have a truck manufacturing plant in Guatemala, but it was closed down some years ago. This left the country with an abundance of very competent mechanics, especially diesel engine mechanics. They are now passing their knowledge on to the next generation. On an interesting note, IC Bus, one of the major manufacturer of the yellow American school buses, is a division within International and the school buses share much of the design with the International trucks. And this is what the end result looks like:   https://youtu.be/TuLDmSo24NY So what does this have to do with IBM Notes and Domino, you may ask? Well, the same way as you can take a boring and generic workhorse like a yellow school bus and give it a second life by converting it into a colorful and useful source of transportation, you can modernize and update your old and perhaps a bit dated Notes application to something new exciting and attractive that your users would like to use. Take your Notes application from this: To this modern web application: Just like the mechanics in Guatemala replaces the old worn-out engine with a new powerful truck engine, your Domino data engine can be replaced with a new engine, for example from LDC Via, if you want to get away from Domino as a server platform. But Domino is a very competent and powerful NoSQL database/server and will work well for most users. So like old worn out yellow school buses, your Notes applications can be given a…

2 Comments

IBM Notes, Domino and the future

As some may already know I was recently laid off after 14 years as a Notes and Domino developer at my workplace. I suspected for a while that some staff reduction would be coming soon, but I was a bit surprised that I was included since I am the only Notes developer in the company. I had for a while considered to do consulting and freelance development. My wife as well as several friends have been encouraging me for years. So this was just the push I needed. I am starting my own company, Demand Better Solutions, where I will focus on Notes and Domino Development, application modernization and migration as well as building brand new web applications and websites. I realize that me being laid off is just a business decision. It is not personal. Several of the business critical applications at my former employer are developed using IBM Notes, but the executives have for years been talking about moving away from the platform. Of course they don't realize the huge amount of work needed to do this, but never the less this was/is their ultimate goal. The reason is that they feel (based on what they hear from other executives) that Notes is old technology. The fact that IBM has been slow in modernizing the interface, and that many of the templates still look like back in 1999 when version 5.0 was released does not help this perception. Last fall all our email at my old job was moved to Outlook, and ever since I have heard users complaining about missing Notes and certain functionality they were used to. A lot of integration between Notes applications and Notes mail were also lost, and I had to re-create it in different ways. You often hear stories about people complaining about the Notes client, but most of our users wanted nothing but to get it back... My old employer also uses Visual FoxPro, a product where the last version was released in 2004. It has officially been discontinued by Microsoft, but we use it for several important applications. So I don't think that even a product being discontinued is driving a huge number of migrations. It is the perception of how modern the product is that matters. And that perception is almost 100% the way the product looks. To a user the interface is the product. Create a modern looking application and nobody will question (or care) what tool was used to build it. The last 3-4 years I have been learning new web technologies, like jQuery, Bootstrap, Ajax, JSON. I have been able to use much of that at work, as well as in several side projects. I also started learning C# and .net. After the layoff I sat down and started looking at (among others) php and mySQL as well as researched frameworks like AngularJS. As a developer I have to keep up with new technologies, or I will be left behind. But it is hard when you work full-time, have side work and then have…

2 Comments

Updated MailNotification class – Now with HTML email support and web links

I have updated my MailNotification class with some additional functionality I needed at work. Since our mail system now is Outlook/Exchange, and therefore the Notes doc links don't work anymore, I am in the process of converting all my email notifications into HTML email. The doc links are now made into HTML links, pointing to a notes:// or http:// address. I simply added a new class, HTMLmail. It is based on the old NotesMail class, but I override a few functions that are different. This makes it very easy to update the emails I am generating in my Lotusscript agents, in most cases I only have to replace NotesMail with HTMLmail in the declaration and instantiation: Dim maildoc As HTMLMail Set maildoc = New HTMLMail() When I had doc links in the email I also had to modify the code where I generate it. The method takes three arguments: the NotesDocument to link to, the Alt/Title attribute for the link (to be displayed when hovering over the link) and the text of the link: Call maildoc.AppendDocLink(doc,"Click to open",doc.ClaimNumber(0)) In order to generate the links I created a Link class, where you can set what protocol you want to use ("notes" or "http") you want the link to use, you can change the port from the default of 80, and you can even force the link to point to a different server. I use this class in the AppendDocLink method in the HTMLmail class. Here is a short code sample, it is just a function to create a mail notification for an insurance claim. The claim document is passed to the function and a mail is sent to the adjuster and his/her manager. Sub SendNotification(doc as NotesDocument) '*** Create a new object and set the sender, recipients and subject Set maildoc = New HTMLMail() maildoc.Principal = |"System Notification" <noreply@example.com>| Call maildoc.AddMailTo(doc.GetItemvalue("Adjuster")(0)) Call maildoc.AddMailCC(GetManagerName(doc.GetItemValue("Adjuster")(0))) maildoc.Subject = "30 DAY ALERT - " & doc.GetItemValue("ClaimNumber")(0) '*** Build body content, including a link to the document Call maildoc.AppendText("Claim number ") Call maildoc.AppendDocLink(doc,"Click to open",doc.GetItemValue("ClaimNumber")(0)) Call maildoc.AppendText(" was received on ") Call maildoc.AppendText(Format$(doc.GetItemValue("Received_Date")(0),"mm/dd/yyyy") & ". ") Call maildoc.AppendText("This claim has been opened for 30 days. ") Call maildoc.AppendText("Please confirm all appropriate actions has been performed.") Call maildoc.AddNewLine(2) '*** Add no-reply notification to the end and send the email maildoc.NoReply = True Call maildoc.Send() '*** Flag the NotesDocument as processed and save it to avoid duplicate notifications doc.Warning30daySent = "Yes" Call doc.Save(True,True) End Sub That's pretty much it.  Enjoy the code, and as usual I do not guarantee anything. Use on your own risk, as always. If you like this code and use it, let me know. Option Public Option Declare Class NotesMail Public maildoc As NotesDocument Public body As NotesRichTextItem Private p_subject As String Private p_sendto List As String Private p_copyto List As String Private p_blindcopyto List As String Private p_principal As String Public NoReply As Boolean Public mailbox As NotesDatabase Public Sub New() Dim session As New NotesSession Dim mailservername As String ' We must use mail.box on current server. mailservername…

2 Comments

MWLUG in Austin – I will be presenting again

I have been selected to present at MWLUG in Austin on August 17-19. My presentation will be kind of part two of my presentation last year in Atlanta. It will focus less on the basics and go more into the fun and more advanced stuff. Kind of an extended version of my Connect 2016 presentation. The title is "Think Outside The Box - Part 2", and I will discuss and show how you can build a modern web front-end using standard techniques like Javascript/jQuery and frameworks like Bootstrap and jQuery Mobile and have it work against a Domino backend. I will demonstrate how to easily read data from and write data to the Domino database, and how to consume data using free plugins like BootstrapTable and FullCalendar. I will also discuss the difference between JSON and JSONP and why the latter usually is better when building this type of integration. You will leave with a sample database containing the source code all the demos I will be showing as well as Lotusscript script libraries with classes I built to easily build agents that will interact with the website. The idea is that you should be able to attend my session in Austin even if you haven't seen any previous presentation. I will assume you have basic web design skills (HTML, CSS and a working understanding of Javascript) but you don't have to be an expert at all. I also recommend some Lotusscript knowledge, as I will be providing all attendees with plenty of code to bring home and start using yourself. I hope to see you in Austin in August! If you haven't registered yet, go ahead and do it now! There are still seats left.

0 Comments

My Connect 2016 presentation & demo database

As I promised, I would post my IBM Connect 2016 presentation on my blog. Presentation (PDF): {link}  Demo database (ZIP): {link} You can also find the presentation on SlideShare.net. To the right you see the database design, you want to look in the Agent section for the agents and in the Pages section for the HTML pages. Note: You need to sign the database with an ID that have the proper rights. Otherwise the code will not work. Enjoy!  

6 Comments

Free Code – Clean groups in Domino Directory

The other day I had to clean up the groups in our Domino Directory. Many groups still contained names of terminated users, they had not been cleaned/maintained properly. We also removed some groups over time, but some of them were still listed as members of other groups. So I wrote a small Lotuscript agent to perform this cleanup. I am posting it below in case someone needs it. As always: no guarantees, use at your own risk, etc. Update: As some commenters pointed out, there are some issues with the code. First of all, I was using a view my company added to name.nsf. The view PeopleByFirstName has the following selection formula: SELECT Type = "Person" & TerminationDate="" The field TerminationDate is one we added to the person document. This field is either blank (for current employees) or contains the date they were terminated (and then they are filtered out of most views). Also as Christian points out, any groups that contains external users would be clenaed out. In the past when I worked at a company that used mail groups with external users, those groups were kept in a separate (secondary) Domino Directory, names_ext.nsf. So this is something to keep in mind if you choose to use this code. Finally I have updated the code with a few more lines. It will now ignore server groups, and also get a list of all servers and make sure they are included as group members when the groups are processed. Thanks for pointing out the problems with the code!   Dim session As New NotesSession Dim db As NotesDatabase Dim view As NotesView Dim doc As NotesDocument Dim userNames List As String Dim groupNames List As String Dim serverNames List As String Dim groups List As NotesDocument Dim tmp As String Dim tmpname As NotesName Set db = New NotesDatabasesession.CurrentDatabase.Server,"names.nsf") '*** Get all existing groups and put in a list Set view = db.getView("Groups") Set doc = view.GetFirstDocument() Do Until doc Is Nothing Set groups(doc.UniversalID) = doc    tmp = doc.GetItemValue("ListName")(0)    groupNames(tmp) = tmp    Set doc = view.GetNextDocument(doc) Loop '*** Get all active users and put in a list Set view = db.getView("PeopleByFirstName") Set doc = view.GetFirstDocument() Do Until doc Is Nothing    tmp = doc.GetItemValue("FullName")(0)    Set tmpname = New NotesName(tmp)    userNames(tmpname.Common) = tmpname.Common    Set doc = view.GetNextDocument(doc) Loop '*** Get all servers and put in a list Set view = db.getView("Servers") Set doc = view.GetFirstDocument() Do Until doc Is Nothing    tmp = doc.GetItemValue("ServerName")(0)    Set tmpname = New NotesName(tmp)    serverNames(tmpsname.Common) = tmpname.Common    Set doc = view.GetNextDocument(doc) Loop '*** Loop though list of groups and process each one ForAll g In groups '*** Check that not server group If g.GetItemValue("GroupType")(0)<>"4" Then    tmp = ""        '*** Store existing list of group members in a backup field       Call g.ReplaceItemValue("MembersBackup",g.GetItemValue("Members"))        '*** Loop through all members of the group       ForAll m In g.GetItemValue("Members")          Set tmpname = New NotesName(m)           '*** If the…

8 Comments

Calling a Notes web agent from another server using JSONP

In my MWLUG presentation (as well as in a couple of entries on this blog) I talk about how you can access Domino data from a regular webpage using jQuery and a Lotusscript agent returning data as JSON. The issue with this solution is that the web page must be on the same web application path as the Domino agent. You can't do what's known as cross-domain Ajax. For example if the Domino server is domino.texasswede.com but you have the webpage hosted at www.texasswede.com, it will not work. The security in Javascript does not allow calls across servers like that. There is however an easy solution, and it is called JSONP. What you do is to return not JSON but a call-back function with the JSON data as the argument. So instead of returning this: { "firstName":"Karl-Henry", "lastname":"Martinsson","email":"texasswede@gmail.com" } you would have the Lotuscript agent return this: personCallBack({ "firstName":"Karl-Henry", "lastname":"Martinsson","email":"texasswede@gmail.com" }) Let's assume we call the agent GetPersonData.jsonp.  On the calling side (in the jQuery code) you would then use this code: $.ajax({ url : "http://domino.texasswede.com/database.nsf/GetPersonData.jsonp?OpenAgent", dataType:"jsonp" }); Finally you write the Javascript call-back function that will accept the data: function personCallBack(data) { $("#firstName").html(data["firstName"]);     $("#lastName").html(data["lastName"]);     $("#emailAddress").html(data["email"]); } You can of course make this as advanced as you like but this is the basics. I have updated the JSON class I use for stuff like this to include a method to return JSONP. The new function is called SendJSONPToBrowser() and takes a string with the name of the call-back function as argument, for example like this: Call json.SendJSONPToBrowser("personCallBack") Below is the updated class (if you downloaded my sample database from MWLUG you have the older version of it). Enjoy!   %REM Library Class.JSON by Karl-Henry Martinsson Created Oct 9, 2014 - Initial version Updated Nov 6, 2015 - Added JSONP support Description: Class to generate simple JSON from values %END REM Option Public Option Declare Class JSONdata Private p_json List As String Public Sub New() '*** Set default value(s) me.p_json("ajaxstatus") = "" End Sub %REM Property Set success Description: Set success to true or false %END REM Public Property Set success As Boolean If me.success Then Call me.SetValue("ajaxstatus","success") Else Call me.SetValue("ajaxstatus","error") End If End Property %REM Property Get success Description: Not really used... %END REM Public Property Get success As Boolean If me.p_json("ajaxstatus") = |"success"| Then me.success = True Else me.success = False End If End Property %REM Sub SetMsg Description: Set msg item %END REM Public Sub SetMsg(message As String) Call me.SetValue("msg",message) End Sub Public Sub SetErrorMsg(message As String) Call me.SetValue("errormsg",message) me.success = False End Sub Public Sub SetValue(itemname As String, value As String) Dim tmp As String Dim delimiter As String '*** Check for quote (double and single) and fix value if needed tmp = Replace(value,Chr$(13),"<br>") tmp = FullTrim(Replace(tmp,Chr$(10),"")) If InStr(tmp,|"|)>0 Then If InStr(tmp,|'|)>0 Then tmp = Replace(tmp,|"|,|"|) delimiter = |"| Else delimiter = |'| End If Else delimiter = |"| End If '*** Store value with delimiter in list me.p_json(itemname) = delimiter & tmp & delimiter End Sub Public Sub SetData(itemname As String, value As…

0 Comments

MWLUG schedule now available!

The session schedule for MWLUG in Atlanta is now online. The conference is less than 4 weeks, and there is a very strong lineup of speakers. Many have been presenting in the Best Practices track at Lotussphere fo years, and this conference is well worth attending. The cost is only $50, and there are still inexpensive flights left. Registration is still open, as I write this. I will present my session AD102 Break out of the box - Integrate existing Domino data with modern websites on Wednesday afternoon, starting at 4.30pm. Hope to see you in Atlanta!

0 Comments

Microsoft releases Visual Studio 2015

Microsoft today released the latest version of their development environment Visual Studio. There are even free versions, including the complete IDE Visual Studio Community and the code editor Visual Studio Code (available for Widnows, Linux and OSX). Visual Studio now includes even more tools for cross platform mobile development for iOS  and Android. There is even an Android emulator included. The web development part supports tools and frameworks like Angular, Bootstrap, jQuery, Backbone and Django. And naturally the IDE also supports Windows, including Windows 10 (expected to be released at the end of the month). I have been using tools in the Visual Studio family for many years, I started with a beta of Visual Basic 1.0 a long time ago, and used all version up to and including VB 6.0. I also played around some with Visual C++ and even Visual J++. After that I focused mainly on Lotus Notes development, but recently I have started some C#/.NET projects at work using Visual Studio Community 2013.

0 Comments

MWLUG in Atlanta – I will be presenting!

It is less than 7 weeks left until MWLUG, the Midwest Lotus User Group conference. This year the conference takes place in Atlanta, between August 19 and 21. During the three days there will be over 40 technical session and workshops on collaboration, receptions and networking opportunities, as well as access to experts of IBM solutions, both from IBM and other companies. The topics includes application development, system administration, best practices, customer buisness cases and innovation/future plans by IBM. Breakfast and lunch is included for two days as well. And all this for the cost of only $50 per person! The event takes place at Ritz-Carlton in downtown Atlanta. There is a block of rooms reserved at a special conference rate of $149.00 per night. One of the sessions will also mark my personal debute as a speaker at a conference. I will present "Break out of the box - Integrate existing Domino data with modern websites" where I will talk about how to integrate websites built either within Domino or on other platforms with backend data that resides in a Domino database. I will talk about how you can build a modern looking website using tools like jQuery and Bootstrap and seamlessly integrate them with existing data on your trusty Domino server using JSON and Ajax. I will also provide plenty of example code ready for you to bring home and start playing with. A number of IBM Champions will be presenting, as well as IBMers and other industry experts. So no matter your interest, I am sure you will find plenty of good sessions. I am sure I will have a hard time picking which sessions to attend! So what are you waiting for? Go to http://www.mwlug.com and register! See you there!  

1 Comment

Code – Get date range as years, months and days

There is a question in the IBM DeveloperWorks forum for Notes/Domino 8 about how to calculate the number of years, months and days between two dates. Then the poster wanted to calculate the sum of two such date ranges and return that as years, months and days as well. Since the lack of formatting in the forum makes it hard to read the code, I decided to simply post it here on my blog. As always, there are several ways to write the code. One could for example use Mod (a very under-used function that many developers don't even know about) to help calculate the number of years, months and days. I also include a function I use to calculate the number of business days between two dates. This could be used to calculate how long a ticket has been open in a help desk system, where you usually don't want to include Saturday and Sunday in the count. Simply change diffOne = Days(startDate,endDate) to diffOne = BusinessDays(startDate,endDate). Enjoy! Option Public Option Declare Type Components yearCount As Integer monthCount As Integer dayCount As Integer End Type Sub Initialize '*** Declare variable for componentized date Dim compOne As Components Dim compTwo As Components Dim compSum As Components '*** Declare variables for day difference count Dim diffOne As Integer Dim diffTwo As Integer '*** Declare start and end date variables Dim startDate As String Dim endDate As String '*** First date range startDate = "01/01/2011" endDate = "03/02/2013" diffOne = Days(startDate,endDate) Call DayCountToComponents(diffOne, compOne) MsgBox compOne.yearCount & " years " & _ compOne.monthCount & " months " & compOne.dayCount & " days" '*** Second date range startDate = "04/03/2012" endDate = "08/17/2015" diffTwo = Days(startDate,endDate) Call DayCountToComponents(diffTwo, compTwo) MsgBox compTwo.yearCount & " years " & _ compTwo.monthCount & " months " & compTwo.dayCount & " days" '*** Sum of first and second date range Call DayCountToComponents(diffOne + diffTwo, compSum) MsgBox compSum.yearCount & " years " & _ compSum.monthCount & " months " & compSum.dayCount & " days" End Sub %REM Function DayCountToComponents Description: Convert day count to years, month and days %END REM Function DayCountToComponents(dayCount As Integer,components As Components) As Boolean Dim daysLeft As Integer On Error GoTo errHandler components.yearCount = Int(dayCount/365) daysLeft = dayCount - components.yearCount * 365 components.monthCount = Int(daysLeft/30) daysLeft = dayCount - (components.yearCount * 365) - (components.monthCount * 30) components.dayCount = daysLeft '*** Return DayCountToComponents = True exitFunction: Exit Function errHandler: DayCountToComponents = True Resume exitFunction End Function %REM Function Days Description: Get the number of days between two dates %END REM Function Days(startDate As Variant,endDate As Variant) As Integer Days = Int(CDbl(CDat(endDate))-CDbl(CDat(startDate))) End Function %REM Function BusinessDays Description: Get the number of business days (Monday-Friday) between two dates %END REM Function BusinessDays(startDate As Variant,endDate As Variant) As Integer Dim startDT As NotesDateTime Dim endDT As NotesDateTime Dim cnt As Integer On Error GoTo errHandler Set startDT = New NotesDateTime(startDate) Set endDT = New NotesDateTime(endDate) cnt = 0 Do Until CDbl(startDT.Lslocaltime) > CDbl(endDT.Lslocaltime) If Weekday(startDT.Lslocaltime)<7 Then If Weekday(startDT.Lslocaltime)>1…

1 Comment

End of content

No more pages to load