Skip to content

How to Create Day & Night Time-of-Day Creatives

A time-of-day billboard creative automatically changes its messaging based on the time of day — showing a morning breakfast promotion in the AM, a lunch deal at midday, and an evening entertainment message at night. The most sophisticated version uses actual sunrise and sunset times for the screen's location, creating a natural environmental alignment rather than fixed hour cutoffs.


Prerequisites

  • A Lucit account with access to the Template Designer
  • Familiarity with the Template Designer canvas and JavaScript tab
  • For sunrise/sunset approach: the screen's latitude and longitude (automatically available from screen location)

What You'll Build

This guide covers three patterns:

  1. Fixed Hour Splits — Simple AM/PM or morning/afternoon/evening splits based on clock time
  2. Sunrise/Sunset Aware — Creative switches based on actual astronomical sunrise and sunset for the screen's location
  3. Multi-Daypart with Product Rotation — Different products or messages per daypart, fully automated

Pattern 1: Fixed Hour Splits (Simplest)

This approach divides the day into time windows based on clock hour and serves different creative content per window.

JavaScript

registerDesignerFunction('getDaypartMessage', function(params, data) {
  // =====================================================
  // CONFIGURATION
  // =====================================================

  // Define time windows and messages
  // Hours in 24-hour format (0 = midnight, 12 = noon, 23 = 11 PM)
  var DAYPARTS = [
    { startHour: 5,  endHour: 10, message: 'Start your morning with [Brand]' },
    { startHour: 10, endHour: 14, message: 'Lunch time — [Brand] has you covered' },
    { startHour: 14, endHour: 18, message: 'Afternoon pick-me-up — [Brand]' },
    { startHour: 18, endHour: 22, message: 'End your day the right way — [Brand]' },
    { startHour: 22, endHour: 24, message: '[Brand] — Late night, great choice' },
    { startHour: 0,  endHour: 5,  message: '[Brand] — Always open' }
  ];

  // =====================================================

  var now = new Date();
  var currentHour = now.getHours();

  for (var i = 0; i < DAYPARTS.length; i++) {
    var part = DAYPARTS[i];
    if (currentHour >= part.startHour && currentHour < part.endHour) {
      return part.message;
    }
  }

  return '[Brand]';  // fallback
});

How to Use

  1. Open the JS tab in your template's Code Editor
  2. Paste the function above, editing the messages and hours to fit your brand
  3. Select the Text element where the message should appear
  4. In the Custom Field selector, choose getDaypartMessage

Pattern 2: Sunrise/Sunset Aware Creative

This approach computes the actual sunrise and sunset time for the screen's latitude/longitude using astronomical formulas — no external API required.

Rather than switching at a fixed hour (e.g., always at 7 AM), this switches at the actual sunrise time for each day and location. A screen in Phoenix in summer sees a 5:30 AM sunrise; the same screen in winter sees 7:20 AM. The creative adapts automatically.

Why Use This Instead of Fixed Hours

  • Daylight changes by 2+ hours between winter and summer across the US
  • "Morning" and "evening" are experiential and environmental — fixed hours create mismatches
  • Advertising a hot coffee at sunset feels right; advertising it after dark feels wrong
  • Environmental alignment makes the creative feel more considered and contextual

JavaScript

registerDesignerFunction('getDayNightMessage', function(params, data) {
  // =====================================================
  // CONFIGURATION
  // =====================================================
  var DAY_MESSAGE = 'Enjoy the sunshine with [Brand]';
  var NIGHT_MESSAGE = '[Brand] — Perfect for tonight';
  var DAWN_MESSAGE = 'Good morning — [Brand] starts your day';
  var DUSK_MESSAGE = 'Golden hour and [Brand] go together';

  // Twilight buffer in minutes before sunrise and after sunset
  var DAWN_BUFFER_MINUTES = 45;
  var DUSK_BUFFER_MINUTES = 45;

  // Screen coordinates (auto-populated from Lucit screen data)
  var lat = parseFloat(data['digital_board.location.lat']);
  var lng = parseFloat(data['digital_board.location.lng']);
  // =====================================================

  if (isNaN(lat) || isNaN(lng)) {
    // Fallback if location unavailable — use simple AM/PM split
    var hour = new Date().getHours();
    return hour >= 6 && hour < 19 ? DAY_MESSAGE : NIGHT_MESSAGE;
  }

  var times = getSunriseSunset(lat, lng, new Date());
  var now = new Date();
  var nowMin = now.getHours() * 60 + now.getMinutes();

  var sunriseMin = times.sunrise;
  var sunsetMin = times.sunset;

  // Dawn window: DAWN_BUFFER_MINUTES before sunrise
  if (nowMin >= (sunriseMin - DAWN_BUFFER_MINUTES) && nowMin < sunriseMin) {
    return DAWN_MESSAGE;
  }

  // Day window: after sunrise, before sunset
  if (nowMin >= sunriseMin && nowMin < sunsetMin) {
    return DAY_MESSAGE;
  }

  // Dusk window: DUSK_BUFFER_MINUTES after sunset
  if (nowMin >= sunsetMin && nowMin < (sunsetMin + DUSK_BUFFER_MINUTES)) {
    return DUSK_MESSAGE;
  }

  // Night: after dusk window
  return NIGHT_MESSAGE;
});

// =====================================================
// Sunrise/Sunset calculation (Julian Day / NOAA formula)
// Returns { sunrise: minutesSinceMidnight, sunset: minutesSinceMidnight }
// =====================================================
function getSunriseSunset(lat, lng, date) {
  var RAD = Math.PI / 180;
  var DEG = 180 / Math.PI;

  var dayOfYear = getDayOfYear(date);
  var b = (360 / 365) * (dayOfYear - 81) * RAD;
  var eqTime = 9.87 * Math.sin(2 * b) - 7.53 * Math.cos(b) - 1.5 * Math.sin(b);
  var decl = 23.45 * Math.sin(b) * RAD;

  var latRad = lat * RAD;
  var cosCosHourAngle = -Math.tan(latRad) * Math.tan(decl);

  // Clamp to [-1, 1] to handle polar extremes
  cosCosHourAngle = Math.max(-1, Math.min(1, cosCosHourAngle));

  var hourAngle = Math.acos(cosCosHourAngle) * DEG;

  var solarNoon = 720 - 4 * lng - eqTime;
  var sunriseMin = solarNoon - 4 * hourAngle;
  var sunsetMin = solarNoon + 4 * hourAngle;

  // Adjust for timezone offset
  var tzOffset = -date.getTimezoneOffset();
  sunriseMin += tzOffset;
  sunsetMin += tzOffset;

  return {
    sunrise: Math.round(sunriseMin),
    sunset: Math.round(sunsetMin)
  };
}

function getDayOfYear(date) {
  var start = new Date(date.getFullYear(), 0, 0);
  var diff = date - start;
  return Math.floor(diff / 86400000);
}

Pattern 3: Multi-Daypart Product Rotation

For brands with different products at different times of day (coffee, QSR, spirits), this pattern maps a product image and message to each time window.

registerDesignerFunction('getDaypartProduct', function(params, data) {
  // =====================================================
  // CONFIGURATION — Map dayparts to product keys
  // The key becomes the data-value — connect it to a
  // Custom Field or use it to select from a data source
  // =====================================================
  var DAYPARTS = [
    { startHour: 5,  endHour: 10, product: 'morning-coffee',    label: 'Start your day' },
    { startHour: 10, endHour: 14, product: 'lunch-sandwich',     label: 'Lunch is ready' },
    { startHour: 14, endHour: 17, product: 'afternoon-snack',    label: 'Afternoon snack' },
    { startHour: 17, endHour: 21, product: 'dinner-special',     label: 'Dinner\'s on us' },
    { startHour: 21, endHour: 24, product: 'evening-dessert',    label: 'End it sweet' },
    { startHour: 0,  endHour: 5,  product: 'late-night-special', label: 'Night owl special' }
  ];
  // =====================================================

  // params[0] = 'product' or 'label' — which value to return
  var returnType = params[0] || 'label';

  var now = new Date();
  var currentHour = now.getHours();

  for (var i = 0; i < DAYPARTS.length; i++) {
    var part = DAYPARTS[i];
    if (currentHour >= part.startHour && currentHour < part.endHour) {
      return returnType === 'product' ? part.product : part.label;
    }
  }

  return returnType === 'product' ? 'default-product' : '[Brand]';
});

How to use params[0]: - Create one Custom Field calling getDaypartProduct with param product → use as image selector - Create another calling getDaypartProduct with param label → display as text


Combining Day/Night with a Countdown

For the most sophisticated approach, combine a time-of-day split with a countdown — for example:

  • Morning: "Christmas is 12 Days Away — Start shopping with [Brand]"
  • Evening: "12 Days Until Christmas — Treat them tonight at [Brand]"
registerDesignerFunction('getDaypartCountdown', function(params, data) {
  var TARGET_DATE_STR = '2025-12-25T00:00:00';

  var now = new Date();
  var target = new Date(TARGET_DATE_STR);
  var diff = target - now;
  var days = diff > 0 ? Math.floor(diff / 86400000) : 0;
  var countdownStr = days > 0 ? days + ' days until Christmas' : 'Merry Christmas!';

  var hour = now.getHours();
  var isDay = hour >= 7 && hour < 19;

  if (diff <= 0) {
    return 'Merry Christmas from [Brand]!';
  }

  if (isDay) {
    return countdownStr + ' — Time to shop [Brand]';
  } else {
    return countdownStr + ' — Celebrate tonight with [Brand]';
  }
});