diff --git a/bindings/java/src/org/sleuthkit/datamodel/TimelineManager.java b/bindings/java/src/org/sleuthkit/datamodel/TimelineManager.java
index 9717ba76813c3db3a317b5b21f6f9e48f5f8e51c..089a92b3396bfbbcc70e81213f664e3a997ec780 100644
--- a/bindings/java/src/org/sleuthkit/datamodel/TimelineManager.java
+++ b/bindings/java/src/org/sleuthkit/datamodel/TimelineManager.java
@@ -93,7 +93,7 @@ public String csvAggFunction(String args) {
 	}
 
 	public String csvAggFunction(String args, String seperator) {
-		return csvFunction + "(" + args + ", '" + seperator + "')";
+		return csvFunction + "(Cast (" + args + " AS VARCHAR) , '" + seperator + "')";
 	}
 
 	TimelineManager(SleuthkitCase tskCase) throws TskCoreException {
@@ -108,13 +108,13 @@ public Interval getSpanningInterval(Collection<Long> eventIDs) throws TskCoreExc
 		if (eventIDs.isEmpty()) {
 			return null;
 		}
-		final String query = "SELECT Min(time), Max(time) FROM events WHERE event_id IN (" + StringUtils.joinAsStrings(eventIDs, ", ") + ")";
+		final String query = "SELECT Min(time) as minTime, Max(time) as maxTime FROM events WHERE event_id IN (" + StringUtils.joinAsStrings(eventIDs, ", ") + ")";
 		sleuthkitCase.acquireSingleUserCaseReadLock();
 		try (CaseDbConnection con = sleuthkitCase.getConnection();
 				Statement stmt = con.createStatement();
 				ResultSet rs = stmt.executeQuery(query);) {
 			while (rs.next()) {
-				return new Interval(rs.getLong("Min(time)") * 1000, (rs.getLong("Max(time)") + 1) * 1000, DateTimeZone.UTC); // NON-NLS
+				return new Interval(rs.getLong("minTime") * 1000, (rs.getLong("maxTime") + 1) * 1000, DateTimeZone.UTC); // NON-NLS
 			}
 
 		} catch (SQLException ex) {
@@ -1136,18 +1136,17 @@ public List<EventStripe> getEventStripes(ZoomParams params, DateTimeZone tz) thr
 		RangeDivisionInfo rangeInfo = RangeDivisionInfo.getRangeDivisionInfo(timeRange, tz);
 
 		//build dynamic parts of query
-		String strfTimeFormat = getStrfTimeFormat(rangeInfo.getPeriodSize());
 		String descriptionColumn = getDescriptionColumn(descriptionLOD);
 		final boolean useSubTypes = typeZoomLevel.equals(EventTypeZoomLevel.SUB_TYPE);
 		String timeZone = tz.equals(DateTimeZone.getDefault()) ? ", 'localtime'" : "";  // NON-NLS
 		String typeColumn = typeColumnHelper(useSubTypes);
 
 		//compose query string, the new-lines are only for nicer formatting if printing the entire query
-		String query = "SELECT strftime('" + strfTimeFormat + "',time , 'unixepoch'" + timeZone + ") AS interval, " // NON-NLS
-				+ csvFunction + "(events.event_id) as event_ids, " //NON-NLS
-				+ csvFunction + "(CASE WHEN hash_hit = 1 THEN events.event_id ELSE NULL END) as hash_hits, " //NON-NLS
-				+ csvFunction + "(CASE WHEN tagged = 1 THEN events.event_id ELSE NULL END) as taggeds, " //NON-NLS
-				+ " min(time), max(time),  " + typeColumn + ", " + descriptionColumn // NON-NLS
+		String query = "SELECT " + formatTimeFunction(rangeInfo.getPeriodSize(), tz) + " AS interval, " // NON-NLS
+				+ csvAggFunction("events.event_id") + " as event_ids, " //NON-NLS
+				+ csvAggFunction("CASE WHEN hash_hit = 1 THEN events.event_id ELSE NULL END") + " as hash_hits, " //NON-NLS
+				+ csvAggFunction("CASE WHEN tagged = 1 THEN events.event_id ELSE NULL END") + " as taggeds, " //NON-NLS
+				+ " min(time) AS minTime, max(time) AS maxTime,  " + typeColumn + ", " + descriptionColumn // NON-NLS
 				+ " FROM events" + useHashHitTablesHelper(filter) + useTagTablesHelper(filter) // NON-NLS
 				+ " WHERE time >= " + start + " AND time < " + end + " AND " + getSQLWhere(filter) // NON-NLS
 				+ " GROUP BY interval, " + typeColumn + " , " + descriptionColumn // NON-NLS
@@ -1172,6 +1171,21 @@ public List<EventStripe> getEventStripes(ZoomParams params, DateTimeZone tz) thr
 		return mergeClustersToStripes(rangeInfo.getPeriodSize().getPeriod(), events);
 	}
 
+	String formatTimeFunction(TimeUnits periodSize, DateTimeZone tz) {
+
+		switch (sleuthkitCase.getDatabaseType()) {
+			case SQLITE:
+				String strfTimeFormat = getStrfTimeFormat(periodSize);
+				String timeZone = tz.equals(DateTimeZone.getDefault()) ? ", 'localtime'" : ""; // NON-NLS
+				return "strftime('" + strfTimeFormat + "', time , 'unixepoch'" + timeZone + ")";
+			case POSTGRESQL:
+				String formatString = getPostgresTimeFormat(periodSize);
+				return "to_char(to_timestamp(time) AT TIME ZONE '" + tz.getID() + "', '" + formatString + "')";
+			default:
+				throw new UnsupportedOperationException("DbType " + sleuthkitCase.getDatabaseType() + " is not supported.");
+		}
+	}
+
 	/**
 	 * map a single row in a ResultSet to an EventCluster
 	 *
@@ -1187,7 +1201,7 @@ public List<EventStripe> getEventStripes(ZoomParams params, DateTimeZone tz) thr
 	 * @throws SQLException
 	 */
 	private EventCluster eventClusterHelper(ResultSet rs, boolean useSubTypes, DescriptionLoD descriptionLOD, TagsFilter filter, DateTimeZone tz) throws SQLException {
-		Interval interval = new Interval(rs.getLong("min(time)") * 1000, rs.getLong("max(time)") * 1000, tz);// NON-NLS
+		Interval interval = new Interval(rs.getLong("minTime") * 1000, rs.getLong("maxTime") * 1000, tz);// NON-NLS
 		String eventIDsString = rs.getString("event_ids");// NON-NLS
 		List<Long> eventIDs = unGroupConcat(eventIDsString, Long::valueOf);
 		String description = rs.getString(getDescriptionColumn(descriptionLOD));
@@ -1289,7 +1303,8 @@ String useTagTablesHelper(RootFilter filter) {
 
 	/**
 	 * take the result of a group_concat SQLite operation and split it into a
-	 * set of X using the mapper to to convert from string to X
+	 * set of X using the mapper to to convert from string to X If groupConcat
+	 * is empty, null, or all whitespace, returns an empty list.
 	 *
 	 * @param <X>         the type of elements to return
 	 * @param groupConcat a string containing the group_concat result ( a comma
@@ -1300,7 +1315,11 @@ String useTagTablesHelper(RootFilter filter) {
 	 *         comma delimited string
 	 */
 	<X> List<X> unGroupConcat(String groupConcat, Function<String, X> mapper) {
-		List<X> result = new ArrayList<X>();
+		if (org.apache.commons.lang3.StringUtils.isBlank(groupConcat)) {
+			return Collections.emptyList();
+		}
+
+		List<X> result = new ArrayList<>();
 		String[] split = groupConcat.split(",");
 		for (String s : split) {
 			result.add(mapper.apply(s));
@@ -1529,6 +1548,24 @@ String getStrfTimeFormat(TimeUnits timeUnit) {
 			}
 	}
 
+	String getPostgresTimeFormat(TimeUnits timeUnit) {
+		switch (timeUnit) {
+			case YEARS:
+				return "YYYY-01-01T00:00:00"; // NON-NLS
+			case MONTHS:
+				return "YYYY-MM-01T00:00:00"; // NON-NLS
+			case DAYS:
+				return "YYYY-MM-DDT00:00:00"; // NON-NLS
+			case HOURS:
+				return "YYYY-MM-DDTHH24:00:00"; // NON-NLS
+			case MINUTES:
+				return "YYYY-MM-DDTHH24:MI:00"; // NON-NLS
+			case SECONDS:
+			default:    //seconds - should never happen
+				return "YYYY-MM-DDTHH24:MI:SS"; // NON-NLS  
+			}
+	}
+
 	String getDescriptionColumn(DescriptionLoD lod) {
 		switch (lod) {
 			case FULL: