mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 05:01:07 +00:00
Initial checkin
This commit is contained in:
@ -0,0 +1,249 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2023. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.actions.dashboard.widgets;
|
||||||
|
|
||||||
|
|
||||||
|
import java.time.DayOfWeek;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.time.temporal.ChronoField;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.time.temporal.IsoFields;
|
||||||
|
import java.time.temporal.TemporalAdjusters;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Enum to define various "levels" of group-by for on dashboards that want to
|
||||||
|
** group records by, e.g., year, or month, or week, or day, or hour.
|
||||||
|
*******************************************************************************/
|
||||||
|
public enum DateTimeGroupBy
|
||||||
|
{
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// note - double %'s on the time format strings here, because this is a java-format string, which will get //
|
||||||
|
// its '%s' replaced with a column name, and so then those %'s for the date_format need escaped as %%. //
|
||||||
|
// See https://www.w3schools.com/sql/func_mysql_date_format.asp for DATE_FORMAT args //
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
YEAR("%%Y", MillisPer.YEAR, 1, ChronoUnit.YEARS, DateTimeFormatter.ofPattern("yyyy"), DateTimeFormatter.ofPattern("yyyy")),
|
||||||
|
MONTH("%%Y-%%m", 2 * MillisPer.MONTH, 1, ChronoUnit.MONTHS, DateTimeFormatter.ofPattern("yyyy-MM"), DateTimeFormatter.ofPattern("MMM'.' yyyy")),
|
||||||
|
WEEK("%%XW%%V", 35 * MillisPer.DAY, 7, ChronoUnit.DAYS, DateTimeFormatter.ofPattern("YYYY'W'ww"), DateTimeFormatter.ofPattern("YYYY'W'w")),
|
||||||
|
DAY("%%Y-%%m-%%d", 36 * MillisPer.HOUR, 1, ChronoUnit.DAYS, DateTimeFormatter.ofPattern("yyyy-MM-dd"), DateTimeFormatter.ofPattern("EEE'.' M'/'d")),
|
||||||
|
HOUR("%%Y-%%m-%%dT%%H", 0, 1, ChronoUnit.HOURS, DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH"), DateTimeFormatter.ofPattern("h a"));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public interface MillisPer
|
||||||
|
{
|
||||||
|
long HOUR = 60 * 60 * 1000;
|
||||||
|
long DAY = 24 * HOUR;
|
||||||
|
long WEEK = 7 * DAY;
|
||||||
|
long MONTH = 30 * DAY;
|
||||||
|
long YEAR = 365 * DAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private final String sqlDateFormat;
|
||||||
|
private final long millisThreshold;
|
||||||
|
private final int noOfChronoUnitsToAdd;
|
||||||
|
private final ChronoUnit chronoUnitToAdd;
|
||||||
|
private final DateTimeFormatter selectedStringFormatter;
|
||||||
|
private final DateTimeFormatter humanStringFormatter;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Constructor
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
DateTimeGroupBy(String sqlDateFormat, long millisThreshold, int noOfChronoUnitsToAdd, ChronoUnit chronoUnitToAdd, DateTimeFormatter selectedStringFormatter, DateTimeFormatter humanStringFormatter)
|
||||||
|
{
|
||||||
|
this.sqlDateFormat = sqlDateFormat;
|
||||||
|
this.millisThreshold = millisThreshold;
|
||||||
|
this.noOfChronoUnitsToAdd = noOfChronoUnitsToAdd;
|
||||||
|
this.chronoUnitToAdd = chronoUnitToAdd;
|
||||||
|
this.selectedStringFormatter = selectedStringFormatter;
|
||||||
|
this.humanStringFormatter = humanStringFormatter;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getSqlExpression()
|
||||||
|
{
|
||||||
|
ZoneId sessionOrInstanceZoneId = ValueUtils.getSessionOrInstanceZoneId();
|
||||||
|
String targetTimezone = sessionOrInstanceZoneId.toString();
|
||||||
|
|
||||||
|
if("Z".equals(targetTimezone) || !StringUtils.hasContent(targetTimezone))
|
||||||
|
{
|
||||||
|
targetTimezone = "UTC";
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// if we only had a timezone offset (not a zone name/id), then the zoneId's toString will look like //
|
||||||
|
// UTC-05:00. MySQL doesn't want that, so, strip away the leading UTC, to just get -05:00 //
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
if((targetTimezone.startsWith("UTC-") || targetTimezone.startsWith("UTC+")) && targetTimezone.length() > 5)
|
||||||
|
{
|
||||||
|
targetTimezone = targetTimezone.substring(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
return "DATE_FORMAT(CONVERT_TZ(%s, 'UTC', '" + targetTimezone + "'), '" + sqlDateFormat + "')";
|
||||||
|
|
||||||
|
/*
|
||||||
|
if(this == WEEK)
|
||||||
|
{
|
||||||
|
return "YEARWEEK(CONVERT_TZ(%s, 'UTC', '" + targetTimezone + "'), 6)";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return "DATE_FORMAT(CONVERT_TZ(%s, 'UTC', '" + targetTimezone + "'), '" + sqlDateFormat + "')";
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** get an instance of this enum, based on start & end instants - look at the #
|
||||||
|
** of millis between them, and return the first enum value w/ a millisThreshold
|
||||||
|
** under that difference. Default to HOUR.
|
||||||
|
*******************************************************************************/
|
||||||
|
public static DateTimeGroupBy selectFromStartAndEndTimes(Instant start, Instant end)
|
||||||
|
{
|
||||||
|
long millisBetween = end.toEpochMilli() - start.toEpochMilli();
|
||||||
|
for(DateTimeGroupBy value : DateTimeGroupBy.values())
|
||||||
|
{
|
||||||
|
if(millisBetween > value.millisThreshold)
|
||||||
|
{
|
||||||
|
return (value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (HOUR);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Make an Instant into a string that will match what came out of the database's
|
||||||
|
** DATE_FORMAT() function
|
||||||
|
*******************************************************************************/
|
||||||
|
public String makeSelectedString(Instant time)
|
||||||
|
{
|
||||||
|
ZonedDateTime zoned = time.atZone(ValueUtils.getSessionOrInstanceZoneId());
|
||||||
|
|
||||||
|
if(this == WEEK)
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// so, it seems like database is returning, e.g., W00-W52, but java is doing W1-W53... //
|
||||||
|
// which, apparently we can compensate for by adding a week? not sure, but results seemed right. //
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
zoned = zoned.plusDays(7);
|
||||||
|
int weekYear = zoned.get(IsoFields.WEEK_BASED_YEAR);
|
||||||
|
int week = zoned.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR);
|
||||||
|
return (String.format("%04dW%02d", weekYear, week));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (selectedStringFormatter.format(zoned));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Make a string to show to a user
|
||||||
|
*******************************************************************************/
|
||||||
|
public String makeHumanString(Instant instant)
|
||||||
|
{
|
||||||
|
ZonedDateTime zoned = instant.atZone(ValueUtils.getSessionOrInstanceZoneId());
|
||||||
|
if(this.equals(WEEK))
|
||||||
|
{
|
||||||
|
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("M'/'d");
|
||||||
|
|
||||||
|
while(zoned.get(ChronoField.DAY_OF_WEEK) != DayOfWeek.SUNDAY.getValue())
|
||||||
|
{
|
||||||
|
////////////////////////////////////////
|
||||||
|
// go backwards until sunday is found //
|
||||||
|
////////////////////////////////////////
|
||||||
|
zoned = zoned.minus(1, ChronoUnit.DAYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (dateTimeFormatter.format(zoned) + "-" + dateTimeFormatter.format(zoned.plusDays(6)));
|
||||||
|
|
||||||
|
/*
|
||||||
|
int weekOfYear = zoned.get(ChronoField.ALIGNED_WEEK_OF_YEAR);
|
||||||
|
ZonedDateTime sunday = zoned.with(IsoFields.WEEK_OF_WEEK_BASED_YEAR, weekOfYear).with(TemporalAdjusters.previousOrSame(DayOfWeek.SUNDAY));
|
||||||
|
ZonedDateTime saturday = sunday.with(TemporalAdjusters.next(DayOfWeek.SATURDAY));
|
||||||
|
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("M'/'d");
|
||||||
|
|
||||||
|
return (dateTimeFormatter.format(sunday) + "-" + dateTimeFormatter.format(saturday));
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
return (humanStringFormatter.format(zoned));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@SuppressWarnings("checkstyle:indentation")
|
||||||
|
public Instant roundDown(Instant instant)
|
||||||
|
{
|
||||||
|
ZonedDateTime zoned = instant.atZone(ValueUtils.getSessionOrInstanceZoneId());
|
||||||
|
return switch(this)
|
||||||
|
{
|
||||||
|
case YEAR -> zoned.with(TemporalAdjusters.firstDayOfYear()).truncatedTo(ChronoUnit.DAYS).toInstant();
|
||||||
|
case MONTH -> zoned.with(TemporalAdjusters.firstDayOfMonth()).truncatedTo(ChronoUnit.DAYS).toInstant();
|
||||||
|
case WEEK ->
|
||||||
|
{
|
||||||
|
while(zoned.get(ChronoField.DAY_OF_WEEK) != DayOfWeek.SUNDAY.getValue())
|
||||||
|
{
|
||||||
|
zoned = zoned.minusDays(1);
|
||||||
|
}
|
||||||
|
yield (zoned.truncatedTo(ChronoUnit.DAYS).toInstant());
|
||||||
|
}
|
||||||
|
case DAY -> zoned.truncatedTo(ChronoUnit.DAYS).toInstant();
|
||||||
|
case HOUR -> zoned.truncatedTo(ChronoUnit.HOURS).toInstant();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Instant increment(Instant instant)
|
||||||
|
{
|
||||||
|
ZonedDateTime zoned = instant.atZone(ValueUtils.getSessionOrInstanceZoneId());
|
||||||
|
return (zoned.plus(noOfChronoUnitsToAdd, chronoUnitToAdd).toInstant());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,241 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2023. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.actions.dashboard.widgets;
|
||||||
|
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
import com.kingsrook.qqq.backend.core.BaseTest;
|
||||||
|
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.session.QSession;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Unit test for DateTimeGroupBy
|
||||||
|
*******************************************************************************/
|
||||||
|
class DateTimeGroupByTest extends BaseTest
|
||||||
|
{
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testMillisPer()
|
||||||
|
{
|
||||||
|
assertEquals(3_600_000L, DateTimeGroupBy.MillisPer.HOUR);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testRoundDown()
|
||||||
|
{
|
||||||
|
assertEquals(Instant.parse("2023-01-01T00:00:00Z"), DateTimeGroupBy.YEAR.roundDown(Instant.parse("2023-03-13T14:50:00Z")));
|
||||||
|
assertEquals(Instant.parse("2023-03-01T00:00:00Z"), DateTimeGroupBy.MONTH.roundDown(Instant.parse("2023-03-13T14:50:00Z")));
|
||||||
|
assertEquals(Instant.parse("2023-03-12T00:00:00Z"), DateTimeGroupBy.WEEK.roundDown(Instant.parse("2023-03-13T14:50:00Z")));
|
||||||
|
assertEquals(Instant.parse("2023-03-13T00:00:00Z"), DateTimeGroupBy.DAY.roundDown(Instant.parse("2023-03-13T14:50:00Z")));
|
||||||
|
assertEquals(Instant.parse("2023-03-13T14:00:00Z"), DateTimeGroupBy.HOUR.roundDown(Instant.parse("2023-03-13T14:50:00Z")));
|
||||||
|
|
||||||
|
QContext.getQInstance().setDefaultTimeZoneId("US/Eastern");
|
||||||
|
assertEquals(Instant.parse("2023-02-01T05:00:00Z"), DateTimeGroupBy.MONTH.roundDown(Instant.parse("2023-03-01T00:00:00Z")));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testIncrement()
|
||||||
|
{
|
||||||
|
assertEquals(Instant.parse("2024-03-01T00:00:00Z"), DateTimeGroupBy.YEAR.increment(Instant.parse("2023-03-01T00:00:00Z")));
|
||||||
|
assertEquals(Instant.parse("2024-01-01T00:00:00Z"), DateTimeGroupBy.MONTH.increment(Instant.parse("2023-12-01T00:00:00Z")));
|
||||||
|
assertEquals(Instant.parse("2024-01-01T00:00:00Z"), DateTimeGroupBy.MONTH.increment(Instant.parse("2023-12-01T00:00:00Z")));
|
||||||
|
assertEquals(Instant.parse("2023-03-08T00:00:00Z"), DateTimeGroupBy.WEEK.increment(Instant.parse("2023-03-01T00:00:00Z")));
|
||||||
|
assertEquals(Instant.parse("2023-03-02T00:00:00Z"), DateTimeGroupBy.DAY.increment(Instant.parse("2023-03-01T00:00:00Z")));
|
||||||
|
assertEquals(Instant.parse("2023-03-01T01:00:00Z"), DateTimeGroupBy.HOUR.increment(Instant.parse("2023-03-01T00:00:00Z")));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testSelectFromStartAndEndTimes()
|
||||||
|
{
|
||||||
|
///////////////////////////////////////////////////////////////////
|
||||||
|
// simple wrapper to call the function w/ a specified time range //
|
||||||
|
///////////////////////////////////////////////////////////////////
|
||||||
|
BiFunction<Integer, ChronoUnit, DateTimeGroupBy> f = (amountToAdd, unit) ->
|
||||||
|
{
|
||||||
|
Instant start = Instant.parse("2021-01-01T00:00:00Z");
|
||||||
|
Instant end = start.plus(amountToAdd, unit);
|
||||||
|
return (DateTimeGroupBy.selectFromStartAndEndTimes(start, end));
|
||||||
|
};
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////
|
||||||
|
// choose YEAR if the timeframe is any amount larger than a year //
|
||||||
|
///////////////////////////////////////////////////////////////////
|
||||||
|
assertEquals(DateTimeGroupBy.YEAR, f.apply(365 * 10, ChronoUnit.DAYS));
|
||||||
|
assertEquals(DateTimeGroupBy.YEAR, f.apply(365 + 1, ChronoUnit.DAYS));
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////
|
||||||
|
// choose month if equal to 1 year, or down to 60 days //
|
||||||
|
/////////////////////////////////////////////////////////
|
||||||
|
assertEquals(DateTimeGroupBy.MONTH, f.apply(365, ChronoUnit.DAYS));
|
||||||
|
assertEquals(DateTimeGroupBy.MONTH, f.apply(61, ChronoUnit.DAYS));
|
||||||
|
|
||||||
|
///////////////////////////////////////
|
||||||
|
// week between 60 days and 35 days //
|
||||||
|
///////////////////////////////////////
|
||||||
|
assertEquals(DateTimeGroupBy.WEEK, f.apply(60, ChronoUnit.DAYS));
|
||||||
|
assertEquals(DateTimeGroupBy.WEEK, f.apply(36, ChronoUnit.DAYS));
|
||||||
|
|
||||||
|
//////////////////////////////////////
|
||||||
|
// day between 35 days and 36 hours //
|
||||||
|
//////////////////////////////////////
|
||||||
|
assertEquals(DateTimeGroupBy.DAY, f.apply(35, ChronoUnit.DAYS));
|
||||||
|
assertEquals(DateTimeGroupBy.DAY, f.apply(37, ChronoUnit.HOURS));
|
||||||
|
|
||||||
|
//////////////////////////////////////////
|
||||||
|
// hour under 36 hours (even negative!) //
|
||||||
|
//////////////////////////////////////////
|
||||||
|
assertEquals(DateTimeGroupBy.HOUR, f.apply(35, ChronoUnit.HOURS));
|
||||||
|
assertEquals(DateTimeGroupBy.HOUR, f.apply(1, ChronoUnit.HOURS));
|
||||||
|
assertEquals(DateTimeGroupBy.HOUR, f.apply(0, ChronoUnit.HOURS));
|
||||||
|
assertEquals(DateTimeGroupBy.HOUR, f.apply(-1, ChronoUnit.HOURS));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testGetSqlExpression()
|
||||||
|
{
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// note - double %'s on the time format strings here, because this is a java-format string, which will get //
|
||||||
|
// its '%s' replaced with a column name, and so then those %'s for the date_format need escaped as %%. //
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
assertEquals("DATE_FORMAT(CONVERT_TZ(%s, 'UTC', 'UTC'), '%%Y')", DateTimeGroupBy.YEAR.getSqlExpression());
|
||||||
|
assertEquals("DATE_FORMAT(CONVERT_TZ(%s, 'UTC', 'UTC'), '%%Y-%%m')", DateTimeGroupBy.MONTH.getSqlExpression());
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
// if session has no zone info, but instance does, assert that it is used. //
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
QContext.getQInstance().setDefaultTimeZoneId("US/Eastern");
|
||||||
|
assertEquals("DATE_FORMAT(CONVERT_TZ(%s, 'UTC', 'US/Eastern'), '%%Y')", DateTimeGroupBy.YEAR.getSqlExpression());
|
||||||
|
|
||||||
|
QContext.getQInstance().setDefaultTimeZoneId("US/Central");
|
||||||
|
assertEquals("DATE_FORMAT(CONVERT_TZ(%s, 'UTC', 'US/Central'), '%%Y')", DateTimeGroupBy.YEAR.getSqlExpression());
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////
|
||||||
|
// put a zone offset (but not name) in session - see it be used //
|
||||||
|
//////////////////////////////////////////////////////////////////
|
||||||
|
QContext.getQSession().setValue(QSession.VALUE_KEY_USER_TIMEZONE_OFFSET_MINUTES, "-300");
|
||||||
|
assertEquals("DATE_FORMAT(CONVERT_TZ(%s, 'UTC', '-05:00'), '%%Y')", DateTimeGroupBy.YEAR.getSqlExpression());
|
||||||
|
|
||||||
|
QContext.getQSession().setValue(QSession.VALUE_KEY_USER_TIMEZONE_OFFSET_MINUTES, "-420");
|
||||||
|
assertEquals("DATE_FORMAT(CONVERT_TZ(%s, 'UTC', '-07:00'), '%%Y')", DateTimeGroupBy.YEAR.getSqlExpression());
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////
|
||||||
|
// put a zone (name) in session - see it be used //
|
||||||
|
///////////////////////////////////////////////////
|
||||||
|
QContext.getQSession().setValue(QSession.VALUE_KEY_USER_TIMEZONE_OFFSET_MINUTES, null);
|
||||||
|
QContext.getQSession().setValue(QSession.VALUE_KEY_USER_TIMEZONE, "US/Central");
|
||||||
|
assertEquals("DATE_FORMAT(CONVERT_TZ(%s, 'UTC', 'US/Central'), '%%Y')", DateTimeGroupBy.YEAR.getSqlExpression());
|
||||||
|
|
||||||
|
QContext.getQSession().setValue(QSession.VALUE_KEY_USER_TIMEZONE, "US/Eastern");
|
||||||
|
assertEquals("DATE_FORMAT(CONVERT_TZ(%s, 'UTC', 'US/Eastern'), '%%Y')", DateTimeGroupBy.YEAR.getSqlExpression());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testMakeSelectedString()
|
||||||
|
{
|
||||||
|
assertEquals("2021", DateTimeGroupBy.YEAR.makeSelectedString(Instant.parse("2021-01-01T00:00:00Z")));
|
||||||
|
assertEquals("2021", DateTimeGroupBy.YEAR.makeSelectedString(Instant.parse("2021-12-31T11:59:59Z")));
|
||||||
|
|
||||||
|
///////////////////////////////////////////////
|
||||||
|
// make sure a timezone does what's expected //
|
||||||
|
///////////////////////////////////////////////
|
||||||
|
QContext.getQInstance().setDefaultTimeZoneId("US/Central");
|
||||||
|
assertEquals("2020", DateTimeGroupBy.YEAR.makeSelectedString(Instant.parse("2021-01-01T00:00:00Z")));
|
||||||
|
assertEquals("2021", DateTimeGroupBy.YEAR.makeSelectedString(Instant.parse("2021-01-01T06:00:00Z")));
|
||||||
|
assertEquals("2021", DateTimeGroupBy.YEAR.makeSelectedString(Instant.parse("2021-12-31T11:59:59Z")));
|
||||||
|
assertEquals("2021", DateTimeGroupBy.YEAR.makeSelectedString(Instant.parse("2022-01-01T03:00:00Z")));
|
||||||
|
|
||||||
|
///////////////////////////////////////////////
|
||||||
|
// reset to UTC - test the other enum values //
|
||||||
|
///////////////////////////////////////////////
|
||||||
|
QContext.getQInstance().setDefaultTimeZoneId("UTC");
|
||||||
|
assertEquals("2021-01", DateTimeGroupBy.MONTH.makeSelectedString(Instant.parse("2021-01-01T00:00:00Z")));
|
||||||
|
assertEquals("2021W01", DateTimeGroupBy.WEEK.makeSelectedString(Instant.parse("2021-01-01T00:00:00Z")));
|
||||||
|
assertEquals("2021W01", DateTimeGroupBy.WEEK.makeSelectedString(Instant.parse("2020-12-31T00:00:00Z")));
|
||||||
|
assertEquals("2021-01-01", DateTimeGroupBy.DAY.makeSelectedString(Instant.parse("2021-01-01T00:00:00Z")));
|
||||||
|
assertEquals("2021-01-01T00", DateTimeGroupBy.HOUR.makeSelectedString(Instant.parse("2021-01-01T00:00:00Z")));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testMakeHumanString()
|
||||||
|
{
|
||||||
|
assertEquals("2021", DateTimeGroupBy.YEAR.makeHumanString(Instant.parse("2021-01-01T00:00:00Z")));
|
||||||
|
assertEquals("2021", DateTimeGroupBy.YEAR.makeHumanString(Instant.parse("2021-12-31T11:59:59Z")));
|
||||||
|
|
||||||
|
///////////////////////////////////////////////
|
||||||
|
// make sure a timezone does what's expected //
|
||||||
|
///////////////////////////////////////////////
|
||||||
|
QContext.getQInstance().setDefaultTimeZoneId("US/Central");
|
||||||
|
assertEquals("2020", DateTimeGroupBy.YEAR.makeHumanString(Instant.parse("2021-01-01T00:00:00Z")));
|
||||||
|
assertEquals("2021", DateTimeGroupBy.YEAR.makeHumanString(Instant.parse("2021-01-01T06:00:00Z")));
|
||||||
|
assertEquals("2021", DateTimeGroupBy.YEAR.makeHumanString(Instant.parse("2021-12-31T11:59:59Z")));
|
||||||
|
assertEquals("2021", DateTimeGroupBy.YEAR.makeHumanString(Instant.parse("2022-01-01T03:00:00Z")));
|
||||||
|
|
||||||
|
///////////////////////////////////////////////
|
||||||
|
// reset to UTC - test the other enum values //
|
||||||
|
///////////////////////////////////////////////
|
||||||
|
QContext.getQInstance().setDefaultTimeZoneId("UTC");
|
||||||
|
assertEquals("Jan. 2021", DateTimeGroupBy.MONTH.makeHumanString(Instant.parse("2021-01-01T00:00:00Z")));
|
||||||
|
assertEquals("12/27-1/2", DateTimeGroupBy.WEEK.makeHumanString(Instant.parse("2021-01-01T00:00:00Z")));
|
||||||
|
assertEquals("12/27-1/2", DateTimeGroupBy.WEEK.makeHumanString(Instant.parse("2020-12-31T00:00:00Z")));
|
||||||
|
assertEquals("Fri. 1/1", DateTimeGroupBy.DAY.makeHumanString(Instant.parse("2021-01-01T00:00:00Z")));
|
||||||
|
assertEquals("12 AM", DateTimeGroupBy.HOUR.makeHumanString(Instant.parse("2021-01-01T00:00:00Z")));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Reference in New Issue
Block a user