Working with Date and Time in vRO

Manipulation of Date & Time is overwhelmingly difficult. Mostly because there are so many formats, standards and handling techniques. Being a vRO programmer, you can’t run away from this date manipulation, be it for Reports creation, REST Calls, Data fetching or Interacting with other servers. Ask any programmer about their experience handling dates and time zones and they will probably share some war stories. Handling date and time fields is certainly not rocket science but can often be tedious and error-prone.

In this article, we will explore some of the key concepts that are necessary for manipulating date and time values correctly, formats that are convenient for storing DateTime values and transferring them over APIs, and more. You can consider it as a complete guide to understand the DateTime concepts in vRealize Orchestrator using the system-provided classes.

If you are sending and receiving data through a REST API, you will eventually need to convert the date to a string and vice versa because JSON doesn’t have a native data structure to represent DateTime. 

Advertisements

Intrinsic Date() Class

vRO provides a Date() class to satisfy almost all the date and time hunger. It has a constructor that takes variety of inputs to start off. There are various methods and functions take allows quick shape-shifting of date and time. However, It may lack some quirky features that you may look out for. Let’s start off by taking a look at this Date class in a more comprehensive way.

It starts here. You call the constructor and you will get the current date and time. BOOM!🚀

const currentDate = new Date();

If you don’t pass anything to the Date constructor, the date object returned contains the current date and time.

You can then format it to extract only the date part as follows:

const currentDate = new Date();
const currentDayOfMonth = currentDate.getDate();
const currentMonth = currentDate.getMonth(); // Be careful! January is 0, not 1
const currentYear = currentDate.getFullYear();
const dateString = currentDayOfMonth + "-" + (currentMonth + 1) + "-" + currentYear;
System.log(dateString)
//Output = "19-03-2022"

Caution It’s not getYear(), but getFullYear()


If you instead want to get the current time stamp, you can create a new Date object and use the getTime() method.

const currentDate = new Date();
const timestamp = currentDate.getTime();
System.log(timestamp); // 1647678776796

Tip In JavaScript, a time stamp is the number of milliseconds that have passed since January 1, 1970, which is also known as Unix/ECMAScript Epoch format.


You can also take an input of Type Date in workflow or action and handle it in your scripts just like any other Date object.

Parsing a Date

Converting a string to a JavaScript date object is done in different ways.

The Date object’s constructor accepts a wide variety of date formats:

const date1 = new Date("Wed, 27 July 2022 13:30:00");
const date2 = new Date("Wed, 27 July 2022 07:45:00 UTC");
const date3 = new Date("27 July 2022 13:30:00 UTC+05:30");

or we can also use Date.parse(), that will return timestamp as string

var ms = Date.parse("27 July 2022 13:30:00 UTC+05:30"); 
System.log(ms); // 1469605500000 (timestamp)

Note that you do not need to include the day of week because JS can determine the day of the week for any date.

You can also pass in the year, month, day, hours, minutes, and seconds as separate arguments:

const date = new Date(2022, 6, 27, 13, 30, 0);

or you can even pass the Unix Epoch number directly:

const date = new Date(1647678776796);

that means to get the zeroth timestamp i.e. Jan 1st of 1970 UTC+0, pass 0 as a parameter to Date()

const date = new Date(0);

or you can also use System.getDateFromFormat() to convert a string to Date object. Check more here.

d = System.getDateFromFormat("2019-01-01T01:45:00.100", "yyyy-MM-dd'T'HH:mm:ss.SSS");
System.log(d);
Advertisements

Working with ISO 8601 Format (YYYY-MM-DDTHH:mm:ss.SSSZ)

Of course, you can always use this specific ISO date format:

const date = new Date("2022-07-27T07:45:00.000Z"); // Fri Sep 02 2022 07:45:00 GMT-0000 (GMT)

Get Current Date in ISO complete format

Many a times, we need Dates in a complete ISO format [YYYY-MM-DDTHH:mm:ss.SSSZ], for making REST calls etc. We can use the toISOString() or toJSON() methods of the Date object to convert the local DateTime to UTC.

const dateFromUI = "12-13-2022";
const timeFromUI = "15:20";
const dateParts = dateFromUI.split("-");
const timeParts = timeFromUI.split(":");
const date = new Date(dateParts[2], dateParts[0]-1, dateParts[1], timeParts[0], timeParts[1]);
const dateISO = date.toISOString();
System.log(dateISO); //2022-12-13T15:20:00.000Z

Caution Not all variations of ISO 8601 format are supported by Date() constructor in vRO.

const date = new Date("2022-07-27T07:45:00Z"); // Invalid Date

If you are sure of the format you want to use, it is best to extract individual bits using the JavaScript functions we covered above and create a string yourself.

var currentDate = new Date();
var date = currentDate.getDate();
var month = currentDate.getMonth(); 
var year = currentDate.getFullYear();

We can get the date in MM/DD/YYYY format as

var monthDateYear  = (month+1) + "/" + date + "/" + year;

The problem with this solution is that it can give an inconsistent length to the dates because some months and days of the month are single-digit and others double-digit. This can be problematic, for example, if you are displaying the date in a table column, because the dates don’t line up.

We can address this by using a “pad” function that adds a leading 0.

function pad(n) {
    return n<10 ? '0'+n : n;
}

Now, we get the correct date in MM/DD/YYYY format using:

var mmddyyyy = pad(month + 1) + "/" + pad(date) + "/" + year;

If we want DD-MM-YYYY instead, the process is similar:

var ddmmyyyy = pad(date) + "-" + pad(month + 1) + "-" + year;

Let’s up the ante and try to print the date in “Month Date, Year” format. We will need a mapping of month indexes to names:

var monthNames = [
    "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
];
var dateWithFullMonthName = monthNames[month] + " " + pad(date) + ", " + year;

It is easy to determine the day of week from 0 (Sunday) to 6 (Saturday). The first day is always Sunday, so let’s add that in:

var daysOfWeek = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
//or
//var completeDaysOfWeek = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
ordinalDateWithDayOfWeek = daysOfWeek[currentDate.getDay()] + ", " + ordinalDate;

By now, you might understand how to get bits of information out of dates and how to pad them. Now, let’s create an ISO format from scratch like I have done here (contains +00:00 instead of Z as per my requirement).

function getCurrentDateInISOFormat() {
//Desired Format 2016-06-14T00:00:00.000+03:00
var date = new Date();
System.log("Current Date: " + date.toGMTString());
//yy=date.getFullYear().toString().substr(2,2);
var yyyy = date.getFullYear();
var mm = (date.getMonth() + 1 < 10 ? "0" : "") + (date.getMonth() + 1);
var dd = (date.getDate() < 10 ? "0" : "") + date.getDate();
var HH = (date.getHours() < 10 ? "0" : "") + date.getHours();
var MM = (date.getMinutes() < 10 ? "0" : "") + date.getMinutes();
var SS = (date.getSeconds() < 10 ? "0" : "") + date.getSeconds();
var milli = "";
if (date.getMilliseconds() < 10)
milli = "00" + date.getMilliseconds();
else if (date.getMilliseconds() < 100 && date.getMilliseconds() > 10)
milli = "0" + date.getMilliseconds();
else
milli = date.getMilliseconds();
System.log(yyyy + "-" + mm + "-" + dd + "T" + HH + ":" + MM + ":" + SS + "." + milli + "+00:00");
return (yyyy + "-" + mm + "-" + dd + "T" + HH + ":" + MM + ":" + SS + "." + milli + "+00:00");
}

Get the number of seconds since the Unix/ECMAScript Epoch

var seconds = Math.floor(Date.now() / 1000);

Working with past and future dates

The best way to work and calculate present and future dates is by using Unix Epoch format which is conveniently the number of milliseconds after midnight January 1, 1970 till the given date expressed as a string which is IETF format. Let’s see few examples.


Important It should be noted that the maximum Date is not of the same value as the maximum safe integer (Number.MAX_SAFE_INTEGER is 9,007,199,254,740,991). Instead, it is defined in ECMA-262 that a maximum of ±100,000,000 (one hundred million) days relative to January 1, 1970 UTC (that is, April 20, 271821 BCE ~ September 13, 275760 CE) can be represented by the standard Date object (equivalent to ±8,640,000,000,000,000 milliseconds).


Get current time in milliseconds

// vRO System method
System.getCurrentTime() //1647861957381 
//or
//Javascript method
Date.now() //1647861957381 
//or
var date = new Date(); //allows any Date to be used 
System.log(date.valueOf()); //1647861957381

Lets say you want to fetch the date 4 days later relative to today, you can convert the today’s date in Unix Epoch format and add 4 x 24 x 60 x 60 x 1000 milliseconds to it and you will get a date exactly 4 days ahead with same time of the day, that because you have not changed enough milliseconds to modify the time.

var date = new Date(); //Thu Mar 21 2022 11:42:06 GMT-0000 (GMT)
System.log(date.valueOf());
var frameOfTime = date.valueOf() + (4*24*60*60*1000);
var date = new Date(frameOfTime); //Thu Mar 25 2022 11:42:06 GMT-0000 (GMT)

Now, let’s say you want to go back in time 4 hours back, You will subtract 4 x 60 x 60 x 1000 milliseconds.

var date = new Date(); //Thu Mar 21 2022 11:42:06 GMT-0000 (GMT)
var frameOfTime = date.valueOf() - (4*60*60*1000);
var date = new Date(frameOfTime); //Thu Mar 25 2022 07:42:06 GMT-0000 (GMT)
Advertisements

Comparing Dates

First, we need to create date objects. Fortunately, <, >, <=, and >= all work. So comparing July 19, 2014 and July 18, 2014 is as easy as:

const date1 = new Date("July 19, 2022");
const date2 = new Date("July 28, 2022");
if(date1 > date2) {
    System.log("First date is more recent");
} else {
    System.log("Second date is more recent");
}

Checking for equality is trickier, since two date objects representing the same date are still two different date objects and will not be equal. Comparing date strings is a bad idea because, for example, “July 20, 2022” and “20 July 2022” represent the same date but have different string representations. The snippet below illustrates the first point:

const date1 = new Date("June 10, 2003");
const date2 = new Date(date1);
const equalOrNot = date1 == date2 ? "equal" : "not equal";
System.log(equalOrNot);

This will output not equal.

This particular case can be fixed by comparing the integer equivalents of the dates (their time stamps) as follows:

date1.getTime() == date2.getTime();

Moreover, vRO is not very good with timezones. So, the best is that we should ignore the user’s time zone and use UTC while creating the date object. There are two ways to do it:

  • Create an ISO formatted date string from the user input date and use it to create a Date object. Using a valid ISO date format to create a Date object while making the intent of UTC vs local very clear.
const userEnteredDate = "12/20/1989";
const parts = userEnteredDate.split("/");
const userEnteredDateISO = parts[2] + "-" + parts[0] + "-" + parts[1];
const userEnteredDateObj = new Date(userEnteredDateISO + "T00:00:00.000Z");
const dateFromAPI = new Date("1989-12-20T00:00:00.000Z");
const result = userEnteredDateObj.getTime() == dateFromAPI.getTime(); // true

This also works if you don’t specify the time since that will default to midnight (i.e., 00:00:00Z):

const userEnteredDate = new Date("1989-12-20");
const dateFromAPI = new Date("1989-12-20T00:00:00.000Z");
const result = userEnteredDate.getTime() == dateFromAPI.getTime(); // true

Remember: If the date constructor is passed a string in correct ISO date format of YYYY-MM-DD, it assumes UTC automatically.

  • JavaScript provides a neat Date.UTC() function that you can use to get the UTC time stamp of a date. We extract the components from the date and pass them to the function.
const userEnteredDate = new Date("12/20/1989");
const userEnteredDateTimeStamp = Date.UTC(userEnteredDate.getFullYear(), userEnteredDate.getMonth(), userEnteredDate.getDate(), 0, 0, 0);
const dateFromAPI = new Date("1989-12-20T00:00:00.000Z");
const result = userEnteredDateTimeStamp == dateFromAPI.getTime();
System.log(result); //true

Finding the Difference Between Two Dates

A common scenario you will come across is to find the difference between two dates.

We discuss two use cases:

FINDING THE NUMBER OF DAYS BETWEEN TWO DATES

Convert both dates to UTC time stamp, find the difference in milliseconds and find the equivalent days.

const dateFromAPI = "2022-02-10T00:00:00.000Z";
const now = new Date();
const datefromAPITimeStamp = (new Date(dateFromAPI)).getTime();
const nowTimeStamp = now.getTime();
const microSecondsDiff = Math.abs(datefromAPITimeStamp - nowTimeStamp);
// Math.round is used instead of Math.floor to account for certain DST cases
// Number of milliseconds per day =
//   24 hrs/day * 60 minutes/hour * 60 seconds/minute * 1000 ms/second
const daysDiff = Math.round(microSecondsDiff / (1000 * 60 * 60  * 24));
System.log(daysDiff); //2231

FINDING USER’S AGE FROM THEIR DATE OF BIRTH

Note: We have a non-standard format. Read the API doc to determine if this means 12 Oct or 10 Dec. Change to ISO format accordingly.

const birthDateFromAPI = "12/10/1989";
const parts = birthDateFromAPI.split("/");
const birthDateISO = parts[2] + "-" + parts[0] + "-" + parts[1];
const birthDate =  new Date(birthDateISO);
const today = new Date();
var age = today.getFullYear() - birthDate.getFullYear();
if(today.getMonth() < birthDate.getMonth()) {
    age--;
}
if(today.getMonth() == birthDate.getMonth() && today.getDate() < birthDate.getDate()) {
    age--;
}
Advertisements

Find Execution time of a f(n)

You can use these logics to get more purposeful result. You can calculate the execution time of a function you just created and may optimize it.

// To test a function and get back its return
function printElapsedTime(fTest) {
var StartTime = Date.now(),
vReturn = fTest(),
EndTime = Date.now(),
difference = EndTimeStartTime
System.log("Elapsed time: "+difference+" milliseconds") //5001 milliseconds
return vReturn
}
var yourFunctionReturn = printElapsedTime(sort)
function sort(){ // your function
const array1 = [1, 30, 4, 21, 100000];
array1.sort();
System.log(array1);
System.sleep(5000)
}

Extras

vRO does provide various methods to represent date and time in various formats out-of-the-box. Let’s have a look on their output.

var date = new Date(Date.UTC()); //Mon Jan 01 1900 00:00:00 GMT-0000 (GMT)
System.log(date.toString()); //Fri Aug 23 1999 14:53:51 GMT-0000 (GMT)
System.log(date.toTimeString()); //14:53:51 GMT-0000 (GMT)
System.log(date.toLocaleTimeString()); //2:53:51 PM GMT
System.log(date.toLocaleDateString()); //January 6, 2009
System.log(date.toDateString()); //Tue Jan 06 2009
System.log(date.valueOf()); //1455062400000
System.log(date.toUTCString()); // Wed, 10 Feb 2016 00:00:00 GMT

Summary

  • Date and time in JavaScript are represented with the Date object. We can’t create “only date” or “only time”: Date objects always carry both.
  • Months are counted from zero (yes, January is a zero month).
  • Days of week in getDay() are also counted from zero (that’s Sunday).
  • Dates can be subtracted, giving their difference in milliseconds. That’s because a Date becomes the timestamp when converted to a number.
  • Use Date.now() to get the current timestamp fast.
Advertisements

References

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s