DEV Community

Mayank Goyal
Mayank Goyal

Posted on • Originally published at cloudblogger.co.in on

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.

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.

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();
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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 2016 13:30:00");
const date2 = new Date("Wed, 27 July 2016 07:45:00 UTC");
const date3 = new Date("27 July 2016 13:30:00 UTC+05:45");
Enter fullscreen mode Exit fullscreen mode

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

var ms = Date.parse("27 July 2016 13:30:00 UTC+05:45"); 
System.log(ms); // 1469605500000 (timestamp)
Enter fullscreen mode Exit fullscreen mode

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(2016, 6, 27, 13, 30, 0);
Enter fullscreen mode Exit fullscreen mode

or you can even pass the Unix Epoch number directly:

const date = new Date(1647678776796);
Enter fullscreen mode Exit fullscreen mode

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);

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("2016-07-27T07:45:00.000Z"); // Fri Sep 02 2022 07:45:00 GMT-0000 (GMT)
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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

const date = new Date("2016-07-27T07:45:00Z"); // Invalid Date
Enter fullscreen mode Exit fullscreen mode

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();
Enter fullscreen mode Exit fullscreen mode

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

var monthDateYear = (month+1) + "/" + date + "/" + year;
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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

var mmddyyyy = pad(month + 1) + "/" + pad(date) + "/" + year;
Enter fullscreen mode Exit fullscreen mode

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

var ddmmyyyy = pad(date) + "-" + pad(month + 1) + "-" + year;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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).

.gist table { margin-bottom: 0; }

<span>
  This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
  <a href="https://github.co/hiddenchars" target="_blank">Learn more about bidirectional Unicode characters</a>
</span>
Show hidden characters






| | 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"); |
| | } |

view rawvro_getCurrentDateInISOFormat.js hosted with ❤ by GitHub

Get the number of seconds since the Unix/ECMAScript Epoch

var seconds = Math.floor(Date.now() / 1000);
Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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");
}
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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();
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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 = "2016-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
Enter fullscreen mode Exit fullscreen mode

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--;
}
Enter fullscreen mode Exit fullscreen mode

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.

.gist table { margin-bottom: 0; }

<span>
  This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
  <a href="https://github.co/hiddenchars" target="_blank">Learn more about bidirectional Unicode characters</a>
</span>
Show hidden characters






| | // To test a function and get back its return |
| | function printElapsedTime(fTest) { |
| | var StartTime = Date.now(), |
| | vReturn = fTest(), |
| | EndTime = Date.now(), |
| | difference = EndTime–StartTime |
| | |
| | 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) |
| | } |

view rawvRO_function_execution_time.js hosted with ❤ by GitHub

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.

.gist table { margin-bottom: 0; }

<span>
  This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
  <a href="https://github.co/hiddenchars" target="_blank">Learn more about bidirectional Unicode characters</a>
</span>
Show hidden characters






| | 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 |

view rawvRO_OOB_Date_functions.js hosted with ❤ by GitHub

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.

References

Top comments (0)