Ampscript Countdown

I wanted to include a countdown in my Ampscript Wordle clone which would display the remaining time in of the following ways:

  • 8 hours and 44 minutes
  • 1 hour
  • 1 minute
  • less than a minute

Seemingly simple this one piece of information required a lot more code than I expected at first as we need to:

  • calculate when tomorrow starts
  • subtract the current time from that end date
  • conditionally display the different date parts and apply their correct singular or plural form
I'll admit this normally should be done with client-side JavaScript displaying a dynamically changing countdown, but for my project I wanted to use pure Ampscript and knew that the user would refresh the CloudPage quite often making this less of a problem.

Calculate when tomorrow begins

We can’t just do a simple DateAdd(Now(), 1, 'D') as this would give us tomorrow’s date with our current time, so I had to come up with a few new ways of getting the clear date with the start set to the very beginning of the calendar date (00:00 or 12:00 AM )

The Complex Way

I’ll admit this was the original way I was calculating the start of the day and now feel that this might have been influenced heavily by my experience with other scripting languages where you encounter strong demands on the types of data that is being processed:

set @now = Now()
set @tomorrow = DateAdd(
                            DatePart(@now, 'year'), '-',
                            DatePart(@now, 'month'), '-',
                            DatePart(@now, 'day')
                1, 'D'

Let’s break down what’s going on here:

  • Let’s imagine that today is the 12th September 2020 – we store this date in the @now variable
  • First we are using the DatePart function and get the basic parts of the the date: the year (2020), the month (9) and the day of the month (12)
  • With Concat we stitch this all together into a string: 2020-09-12
  • We have a string representing the date DateParse function to convert it to have a date data type
  • Once that’s done, we simply add 1 day (D) to the date of today to get the tomorrow’s date in our @tomorrow variable

The Smarter Way

This was all OK until I learned that the DateAdd function does accept strings as dates and does the parsing itself() and reminded myself that FormatDate() is a thing. There’s a special sort of satisfaction when you reduce a convoluted something that overly complicated to something small and readable:

set @now = Now()
set @tomorrow = DateAdd(FormatDate(@now, 'yyyy-MM-dd'), 1, 'D')

BTW. Format(@now, 's') would also work, but I find the yyyy-MM-dd string is more understandable.

You would think there would also be a different way:
- Add 1 day to the current date
- Subtract the hour, minutes and second values 

In practice this is impossible as the DateAdd function does not support adding (and substracting by adding negative amounts of) seconds - the smallest time unit you could use here is mi representing minutes. 

Basic calculations

With the cut-off date available, we can proceed with the further steps

set @leftTime = DateDiff(@now, @tomorrow, 'MI')
set @leftMinutes = Mod(@leftTime, 60)
set @leftHours = Divide(Subtract(@leftTime, @leftMinutes), 60)

Here I’ve made a decision to make the minutes (MI) the smallest unit of time I woud have the code display in the interface.

Building the text string

We know how many hours and minutes are left, so we can easily start building the string:

  • starting with the amount of full hours left and conditionally assigning the plural form:
/* Build the text string with hours and minutes (if they are bigger than 0) */
set @leftString = 'Expires in '

/* Hours */
    @leftHours >= 2
            set @leftString = Concat(@leftString, @leftHours, ' hours ')
    @leftHours == 1
            set @leftString = Concat(@leftString, @leftHours, ' hour ')
  • a conditional and separating hours from minutes if both should be displayed:
/* If both numbers of hours and minuter are mentioned place an 'and' string between them */
    @leftHours >= 1
    @leftMinutes >= 1
            set @leftString = Concat(@leftString, ' and ')
  • and finally with the amount minutes left:
/* Minutes */
    @leftMinutes >= 2
            set @leftString = Concat(@leftString, @leftMinutes, ' minutes ')
    @leftMinutes == 1
            set @leftString = Concat(@leftString, @leftMinutes, ' minute ')
    @leftHours == 0
    @leftMinutes == 0
            set @leftString = Concat(@leftString, 'less than a minute ')

As you can see here, if the amount of time left will be smaller than one minute, we simply display less than a minute.