Working with Dates

Modified on Tue, Nov 19 at 2:38 PM

Dates and Timestamps

There are two data types for working with dates and time:

  • Date – This is measured in milliseconds from 1/1/1970.  Captures the date.  If a Date field is not initialized – not set to something – it will have the value 1/1/1970   (that is, a zero or unset date is January 1, 1970).   Most “date arithmetic” is done with Date values.
  • Timestamp – This captures both “date” and “time”.


Date & Time Data Types

There are two data types relating to dates:

  • “Date” Data Types
    1. Date – Date/Time measured in milliseconds from 1/1/1970 00:00
    2. Timestamp – Date/Time measured in microseconds from 1/1/1970 00:00

 

Roughly, “Date” fields hold date information – and may or may not include time.  “Timestamps” contain both date and time information.   The "zero" date - an unset or 'empty' date - will appear as 1/1/1970.


These are not interchangeable:  you cannot compare a Date field to a Timestamp field.  You can convert a Timestamp to a Date using the “toDate” function (see below).  You can cannot convert Dates (or anything else) to a Timestamp – there is no “toTimestamp” function.


All ‘date arithmetic’ is done using the Date data type.


Making Dates


You can convert a String to a Date using the rw:toDate function.  The String has to be in the form “m/d/yyyy” (or mm/dd/yyyy).   E.g. rw:toDate(‘12/21/2024’)


Getting Dates from Users (The Date Parameter Type in REportWriter)


The Date parameter type presents the user with a Calendar popup and returns a parameter with a Date data type.  This can be used, as is, as a Date – it does not need to be converted.


The Zero or “Empty” Date


Dates – and Timestamps – that have no value, that is, they are “empty”, will print out as January 1, 1970.   This is the “zero date”.  If you see a date printed as 1/1/1970 it is because it has not been set to any actual date.   (It would be quite rare for 1/1/1970 to be “real” – perhaps as a staff member’s birth date). The zero Timestamp is 1/1/1970 00:00am.


Time (e.g. 12:45pm) can be represented either as a Timestamp or a Date with 'empty' or zero month, day and year fields.  A Date with time but no date will print out like this example:   1/1/1970 12:45pm     To suppress the 'empty' month, day and year fields, use the 'rw:formatDate' function to only print the time fields - see below.

 

 

Printing Dates & Timestamps

The formatDate function is used to format a Date or a Timestamp field for output.  This is required to make sure the Date or Timestamp prints the way you want it to.

                             rw:formatDate(Date dateToPrint, String outputFormat)

Expression

What it will do

rw:formatDate(row.dateOfBirth, ‘MM/dd/yyyy’)

Gives the date as 01/01/2007 to 12/31/2007.

rw:formatDate(row.dateOfBirth, ‘M/dd’)

Gives students’ birthdays as 1/1 to 12/31

rw: formatDate (row.startTime, ‘M/d/yyyy hh:mma’)

Gives date and time in the format 1/1/2024 11:45am    

 

Some Relevant Format Characters

The most usual date/time format characters include:

Characters

What it will do

Letter type

M

Single digit month when possible: 1 to 12

Upper case M

MM

Two digit month:  01 to 12

Upper case M

MMM

Month abbreviation: Jan to Dec    

Upper case M

MMMM

Month spelled out:  January to December

Upper case M

MMMMMSingle Letter Month   S for SeptemberUpper case M's

d

Single digit day:  1 to 31

Lower case d

dd

Double digit day: 01 to 31

Lower case d

yy

Two digit year:  24, 25

Lower case y

yyyy

Four digit year: 2024, 2025

Lower case y

mm

Minutes: 01 to 60

Lower case m

hh

Hours: 01 to 12

Lower case h

a

am or pm marker    Only use the single ‘a’

Lower case a

 

Some other interesting ones include:

Characters

What it will do

Letter type

D

Day in year

Upper case D

H

Hours in the 24 hour day:  00 to 23

Upper case H

z

Timezone

Lower case z

E
Tue - 3 letter day of week
3 capital E's
EEEETuesday - Day of week written out4 capital E's
EEEEET - 1 letter day of week5 capital E's
EEEEEETu - 2 letter day of week6 capital E's
c
2 - numeric day of week where Monday=1 Lower case c
w
45 - Week of the yearLower case w
W3 - Week of the month
Upper case W
Q02 - numeric quarter of yearUpper case Q
QQQQ2 - Alpha quarter of year abbreviation3 upper case Q's
QQQQ2nd Quarter - Quarter of year in a phrase4 upper case Q's

 

There are many more format characters.  To find the full repertoire of date format characters, go here and scroll down:   https://unicode-org.github.io/icu/userguide/format_parse/datetime/
 

Comparing Dates

One of the most common things to do is to compare dates to determine which is earlier, which is later.   The dateCompare function is used for this and IT DOES NOT RETURN A BOOLEAN VALUE:  it returns an integer value.

                             rw:dateCompare(Date startDate, Date compareDate)


The first argument to the function “dateCompare” is the starting date, the date against which the second date will be compared.

  • Dates are Equal:  If the compareDate is the same date as the startDate, dateCompare returns 0 (zero).
  • compareDate is earlier than the startDate:  dateCompare returns < 0  (a random value less than zero).   Note that the definition says it will return -1:  this is not always true.  Test for <0.
  • compareDate is after/later than the startDate: dateCompare returns > 0 (a random value > 0.


How to use dateCompare

Use two columns to do this to reduce the computing load:

  • Put the actual compare in one column:  rw:dateCompare(row.startingDate, param.compareDate)
  • In a second column, use the result of the first column to decide what to do, using the “nested Conditional statements” technique:

${row.theResult == 0 ? ‘Dates are Equal’ :  row.theResult < 0 : ‘Date is EARLIER’ : ‘Date is LATER’}

            Or

${row.theResult == 0 ? ‘Dates are Equal’ :  row.theResult < 0 : ‘Date is EARLIER’ : row.theResult > 0 ? ‘Date is LATER’ : ‘uh oh. Something is wrong’}


Always test the result of dateCompare using <0 and >0 and not ‘== -1’ or ‘== 1’.


Date Arithmetic

Adding or Subtracting “Days” from a Start Date

The “dateAddDays” function can be used to calculate a new Date either before or after a start date.


Format:  rw:dateAddDays(Date startDate, int offsetNumberOfDays)               


This will add the integer value “offsetNumberOfDays” to the “startDate” field, which must be a Date.


Expression

What it will do

rw:dateAddDays(param.startDate, -20)    

Find the date 20 days before the start date (-20)

rw:dateAddDays(row.startingDate,rw:toInteger(param.numberOfDays))

Adds the # of days entered by the user in the “numberOfDays” parameter to the startingDate column. Note that the parameter has to first be converted to an Integer.

rw:dateAddDays(row.startingDate,row.offset)

Add the value in the “offset” column to the Date value in the startingDate column.

 

Finding the Number of Days or School Days between Two Dates

There are two functions that can be used to calculate the number of days between two dates:

  • getNumberOfDays – This returns the number of days between two dates, inclusive of the two dates.  Both values must have the “Date” data type:  

rw:getNumberOfDays(Date date1, Date date2)

  • getNumberOfSchoolDays – This returns the number school days between two dates, inclusive, using the school’s calendar.   Both values must have the “Date” data type:  

rw:getNumberOfSchoolDays(Date date1, Date date2)


Expression

What it will do

rw:getNumberOfDays (rw:toDate(‘1/1/2025’), rw:toDate(‘1/2/2025’))    

This will return the Integer 2.   Note the required use of the “toDate” function to convert the Strings to Dates.

rw:getNumberOfDays (row.startDate,row.endDate)

This returns the number of days between the startDate and the endDate.

rw:getNumberOfSchoolDays (row.schoolStartDate,row.schoolEndDate)

Get the # of school days between the schoolStartDate and the schoolEndDate fields.

 

 

All Date Functions:
String convertMinutesToFriendly(Integer minutes)
 

Return as a string the number of minutes and hours based on mintes. 61 would return 1 hour 1 minute.
 Usage: ${rw:convertMinutesToFriendly(minutes)}


Date dateAddDays(Date startingValue, int offset)
 

Adds int1 days to Date1
 Usage: ${rw:dateAddDays(startingValue, offset)}


Integer dateCompare(Date startingDate, Date compareDate)
 

Returns an integer representing the comparison of two dates. 0 if they are the same, -1 if Date1 < Date2 and 1 if Date1 > Date2
 Usage: ${rw:dateCompare(startingDate, compareDate)}


Date dateFindDayOfWeek(Date startingValue, String dayToFind, int weekOffset)
 

Return a date that is the next or previous day in the week by name. String1 is the day of the week to find (Monday, Tuesday etc...). int1 is 0 for this week, -1 for last week etc.
 Usage: ${rw:dateFindDayOfWeek(startingValue, dayToFind, weekOffset)}


String formatDate(Date value, String pattern)
 

Returns a formatted string for Date or Timestamp types using the pattern (e.g. 'MM/dd/yyyy').
 Usage: ${rw:formatDate(value, pattern)}


int getAgeAsOfDate(Date asOfDate, Date birthDate)
 

Determine someone's age as of date. 1/1/2017, 1/1/2022 would return 5
 Usage: ${rw:getAgeAsOfDate(asOfDate, birthDate)}


int getDayIndex(String dayToFind)
 

Return a number representing the name of a day of the week. It looks at just the first 2 characters to decide. Su=1, Mo=2, Tu=3, We=4, Th=5, Fr=6, Sa=7
 Usage: ${rw:getDayIndex(dayToFind)}


int getDayOfYear(Date date)
 

Return a number that is the day of the year. 1/1/2018 would return 1. 2/1/2018 would return 32.
 Usage: ${rw:getDayOfYear(date)}


int getNumberOfDays(Date date1, Date date2)
 

Return the total number of days between dates. 1/1/2018, 1/2/2018 would return 2
 Usage: ${rw:getNumberOfDays(date1, date2)}


int getNumberOfSchoolDays(Date date1, Date date2)
 

Return the total number of school days between dates.
 Usage: ${rw:getNumberOfSchoolDays(date1, date2)}


Date toDate(String value)
 

Convert the date represented in String1 to a real date. Dates should be in the pattern of m/d/yyyy
 Usage: ${rw:toDate(value)}

 

Was this article helpful?

That’s Great!

Thank you for your feedback

Sorry! We couldn't be helpful

Thank you for your feedback

Let us know how can we improve this article!

Select at least one of the reasons
CAPTCHA verification is required.

Feedback sent

We appreciate your effort and will try to fix the article