diff --git a/date_utils/date_utils.go b/date_utils/date_utils.go
index edace1f239e17a5e2dbc175886dd3d56f843d201..3003c28c057ee773bda3cbdf02657b147f667a82 100644
--- a/date_utils/date_utils.go
+++ b/date_utils/date_utils.go
@@ -3,6 +3,7 @@ package date_utils
 import (
 	"reflect"
 	"strconv"
+	"strings"
 	"time"
 
 	"github.com/araddon/dateparse"
@@ -273,7 +274,139 @@ func formatTimestampsWithTimeZoneInSlice(fieldValue reflect.Value, location *tim
 	return nil
 }
 
-type TradingHours struct {
-	Days  string `json:"days"`
-	Times string `json:"times"`
+// TradingHours represents an array of (StartTime,EndTime) pairs, one for each day of the week.
+// The array is 0 indexed, with 0 being Monday and 6 being Sunday.
+type TradingHours [7]struct {
+	StartTime string `json:"start_time"`
+	EndTime   string `json:"end_time"`
+}
+
+func (t *TradingHours) Validate() bool {
+	if t == nil {
+		return false
+	}
+
+	for _, day := range t {
+		if !TimeBefore(day.StartTime, day.EndTime) {
+			return false
+		}
+
+		if len(day.StartTime) != 5 || len(day.EndTime) != 5 {
+			return false
+		}
+
+		startHourMinSlice := strings.Split(day.StartTime, ":")
+		startHour, startMin := startHourMinSlice[0], startHourMinSlice[1]
+		startHourInt, err := strconv.Atoi(startHour)
+		if err != nil || startHourInt < 0 || startHourInt > 23 {
+			return false
+		}
+		startMinInt, err := strconv.Atoi(startMin)
+		if err != nil || !(startMinInt == 0 || startMinInt == 30) {
+			return false
+		}
+
+		endHourMinSlice := strings.Split(day.EndTime, ":")
+		endHour, endMin := endHourMinSlice[0], endHourMinSlice[1]
+		endHourInt, err := strconv.Atoi(endHour)
+		if err != nil || endHourInt < 0 || endHourInt > 23 {
+			return false
+		}
+		endMinInt, err := strconv.Atoi(endMin)
+		if err != nil || !(endMinInt == 0 || endMinInt == 30 || endMinInt == 59) {
+			return false
+		}
+	}
+
+	return true
+}
+
+func (t *TradingHours) String() string {
+	var dayMap = map[int]string{
+		0: "Mon",
+		1: "Tue",
+		2: "Wed",
+		3: "Thu",
+		4: "Fri",
+		5: "Sat",
+		6: "Sun",
+	}
+
+	var timeMap = map[string]string{
+		"00:00": "12am",
+		"00:30": "12:30am",
+		"01:00": "1am",
+		"01:30": "1:30am",
+		"02:00": "2am",
+		"02:30": "2:30am",
+		"03:00": "3am",
+		"03:30": "3:30am",
+		"04:00": "4am",
+		"04:30": "4:30am",
+		"05:00": "5am",
+		"05:30": "5:30am",
+		"06:00": "6am",
+		"06:30": "6:30am",
+		"07:00": "7am",
+		"07:30": "7:30am",
+		"08:00": "8am",
+		"08:30": "8:30am",
+		"09:00": "9am",
+		"09:30": "9:30am",
+		"10:00": "10am",
+		"10:30": "10:30am",
+		"11:00": "11am",
+		"11:30": "11:30am",
+		"12:00": "12pm",
+		"12:30": "12:30pm",
+		"13:00": "1pm",
+		"13:30": "1:30pm",
+		"14:00": "2pm",
+		"14:30": "2:30pm",
+		"15:00": "3pm",
+		"15:30": "3:30pm",
+		"16:00": "4pm",
+		"16:30": "4:30pm",
+		"17:00": "5pm",
+		"17:30": "5:30pm",
+		"18:00": "6pm",
+		"18:30": "6:30pm",
+		"19:00": "7pm",
+		"19:30": "7:30pm",
+		"20:00": "8pm",
+		"20:30": "8:30pm",
+		"21:00": "9pm",
+		"21:30": "9:30pm",
+		"22:00": "10pm",
+		"22:30": "10:30pm",
+		"23:00": "11pm",
+		"23:30": "11:30pm",
+		"23:59": "11:59pm",
+	}
+
+	result := ""
+	rangeStartIndex := 0
+	for i := 0; i < len(t); i++ {
+		times := timeMap[t[i].StartTime] + "-" + timeMap[t[i].EndTime]
+		if t[i].StartTime == "00:00" && t[i].EndTime == "23:59" {
+			times = "All day"
+		}
+
+		// If we're at the last element or the next day doesn't have the same times, we end the current range
+		if i == len(t)-1 || t[i].StartTime != t[i+1].StartTime || t[i].EndTime != t[i+1].EndTime {
+			if rangeStartIndex == i {
+				result += dayMap[i] + ": " + times
+			} else {
+				result += dayMap[rangeStartIndex] + "-" + dayMap[i] + ": " + times
+			}
+
+			if i < len(t)-1 {
+				result += ", "
+			}
+
+			rangeStartIndex++
+		}
+	}
+
+	return result
 }