This commit is contained in:
2018-11-30 23:48:05 +00:00
parent 460d50109f
commit aeeaf0bf30
3 changed files with 856 additions and 3 deletions

View File

@@ -27,7 +27,7 @@ Filters are saved to the database:
- op=one of the values specified in the FilterComparisonOperator class in Biz namespace
- value= straight up direct comparison value
- If string then a string fragment, case is sensitive
- If date then iso style date
- If date then iso style date //RAVEN NOTE: it is my intention that dates come in iso8601 UTC format from the client
- could be whole number or decimal number
- Could be a special "macro" filter value like "[THIS_MONTH]" (always surrounded by square brackets, no need to disambiguate with a string because only applies to non string values)
- Could be a series of id values like this "[23,45,56,123]" as in tag id's or something related to that case.
@@ -59,10 +59,12 @@ NOTES ABOUT WHY I DID THE FILTEROPTIONS LIKE I DID:
LIST FILTERING TODO
- DONE test for fetching widget filter options (localized, so have two users test each for expected response)
- Add test for excercising all of DataFilterController route including rights to non personal alternative owner etc
Add test for correctly validated Widget datafilter when saved or updated via datafiltercontroller (sanity check of the filter settings and options IFilterableObject implemented)
- Add test for correctly validated Widget datafilter when saved or updated via datafiltercontroller (sanity check of the filter settings and options IFilterableObject implemented)
Add test for providing saved filter id to widgetlist and recieving correct filtered / paged / sorted results (test all those)
- Requires filter to sql code to be written and changes to the widgetlist route
- This is where it gets real! Happy monday!! :)
- Copy as much from v7 as possible
- Client side
- Implement filter editor dialog and test

View File

@@ -5,7 +5,7 @@ Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOiIxNTQyNjY5Njc3IiwiZXhwIjoi
## IMMEDIATE ITEMS
filtering test see core-list-graph-datatable-filtering-paging.txt doc
filter to SQL / Widget list filtered with tests - see core-list-graph-datatable-filtering-paging.txt doc
SERVER SCHEMA
- Add unique constraint to all name columns in all tables in ayschema and run tests (how did I miss that before??)

View File

@@ -0,0 +1,851 @@
using System.Collections.Generic;
using System;
using System.Globalization;
using System.Text;
namespace AyaNova.Biz
{
public static class FilterSqlCriteriaBuilder
{
/// <summary>
/// Used internally by AyaNova UI to translate Infragistics grid filter settings to AyaNova friendly SQL critiera
/// </summary>
private static string GridToSqlCriteria(string sColumn, string sDataType, string sOperator, string sValue, bool IsCompound)
{
//if(log.IsDebugEnabled)
////case 1039 //log.Debug("GridToSqlCriteria(Column=" + sColumn +", DataType=" + sDataType + ", Operator=" + sOperator + ", Value=" + sValue+")");
StringBuilder sb = new StringBuilder();
//Column name
//sb.Append(" ");
sb.Append(sColumn);
sb.Append(" ");
//Added: 13-July-2006 prior fix on the 6th either broke due to other changes or
//was not enough in the first place, oddly it was working then, but this is also needed
//now to make it work:
//Handle bools with null values
//this comes about from a user selecting blanks or nonblanks to filter a bool column
if (sValue == "" && sDataType == "System.Boolean")
{
sValue = "False";
}
//handle null values separately
if (sValue == "")
{
//strings in grids are rarely null, almost always just an empty string
//so filter on that instead
switch (sDataType)
{
case "System.String":
{
if (sOperator == "Equals")
{
//Changed: 19-July-2006 was missing null values, "almost always' above not good enough!
sb.Append("Is Null");
sb.Append(" OR ");
sb.Append(sColumn);
sb.Append(" = ''");
}
else
sb.Append(" <> ''");
}
break;
default:
{
if (sOperator == "Equals")
sb.Append("Is Null");
else
sb.Append("Is Not Null");
}
break;
}
}
else
{//non null value
//Changed 21-March-2006:
//But wait! Both mssql and firebird won't include a null result
//on the filter field so in some cases we need to include them
//i.e. if a value is supposed to be not equal to a specific non-null value
//then null is a valid value to return but won't be normally
//so....
//Special addition to handle nulls
if (!IsCompound)
{
switch (sOperator)
{
case "Equals":
//no change on equals for nulls
break;
case "GreaterThan":
//no change on greater than for nulls
//(nulls are going to be assumed to be always at the
//less than end of the scale)
break;
case "GreaterThanOrEqualTo":
//no change on greater than for nulls
//(nulls are going to be assumed to be always at the
//less than end of the scale)
break;
case "LessThan":
sb.Append("Is Null OR ");
sb.Append(sColumn);
sb.Append(" ");
break;
case "LessThanOrEqualTo":
sb.Append("Is Null OR ");
sb.Append(sColumn);
sb.Append(" ");
break;
case "Like":
//No change on like
break;
case "NotEquals":
//This is the big one:
sb.Append("Is Null OR ");
sb.Append(sColumn);
sb.Append(" ");
break;
}
}
#region Build for specific type
switch (sDataType)
{
case "System.String":
//escape any pre-existing apostrophes
//i.e. "O'Flaherty's pub" would cause fits
//if this wasn't done
//MS-sql and firebird use double apostrophes so
//any future db added should consider this
sValue = sValue.Replace("'", "''");
//case 1951 - unescape ampersands
sValue = sValue.Replace("&amp;", "&");
switch (sOperator)
{
case "Equals":
sb.Append("='");
sb.Append(sValue);
sb.Append("'");
break;
case "GreaterThan":
sb.Append(">'");
sb.Append(sValue);
sb.Append("'");
break;
case "GreaterThanOrEqualTo":
sb.Append(">='");
sb.Append(sValue);
sb.Append("'");
break;
case "LessThan":
sb.Append("<'");
sb.Append(sValue);
sb.Append("'");
break;
case "LessThanOrEqualTo":
sb.Append("<='");
sb.Append(sValue);
sb.Append("'");
break;
case "Like":
sb.Append("Like '");
sb.Append(sValue);
sb.Append("%'");
break;
case "NotEquals":
sb.Append("<>'");
sb.Append(sValue);
sb.Append("'");
break;
//Following 7 operators added 14-June-2006
case "DoesNotContain":
sb.Append("Not Like '%");
sb.Append(sValue);
sb.Append("%'");
break;
case "Contains":
sb.Append("Like '%");
sb.Append(sValue);
sb.Append("%'");
break;
case "StartsWith":
sb.Append("Like '");
sb.Append(sValue);
sb.Append("%'");
break;
case "EndsWith":
sb.Append("Like '%");
sb.Append(sValue);
sb.Append("'");
break;
case "DoesNotStartWith":
sb.Append("Not Like '");
sb.Append(sValue);
sb.Append("%'");
break;
case "DoesNotEndWith":
sb.Append("Not Like '%");
sb.Append(sValue);
sb.Append("'");
break;
case "NotLike":
sb.Append("Not Like '");
sb.Append(sValue);
sb.Append("%'");
break;
default:
throw new System.ArgumentOutOfRangeException("OPERATOR_TYPE", sOperator, "GridToSqlCriteria unhandled operator type [" + sOperator + "] IN STRING");
}
break;
case "System.Boolean":
{
switch (sOperator)
{
case "Equals":
sb.Append("= ");
if (sValue == "True")
sb.Append("1");
else
sb.Append("0");
break;
case "NotEquals":
sb.Append("<> ");
if (sValue == "True")
sb.Append("1");
else
sb.Append("0");
break;
default:
throw new System.ArgumentOutOfRangeException("OPERATOR_TYPE", sOperator, "GridToSqlCriteria unhandled operator type [" + sOperator + "] in BOOL");
}
}
break;
case "System.Guid":
{
switch (sOperator)
{
case "Equals":
sb.Append("= ");
sb.Append("'");
sb.Append(sValue);
sb.Append("'");
break;
case "NotEquals":
sb.Append("<> ");
sb.Append("'");
sb.Append(sValue);
sb.Append("'");
break;
default:
throw new System.ArgumentOutOfRangeException("OPERATOR_TYPE", sOperator, "GridToSqlCriteria unhandled operator type [" + sOperator + "] in BOOL");
}
}
break;
case "System.DateTime":
{
if (sValue.StartsWith("["))
{
#region Build criteria for date RANGE specified
//Used as the basis point
System.DateTime dtAfter;
System.DateTime dtBefore;
switch (sValue)
{
//Case 402
case "[YESTERDAY]":
//Between Day before yesterday at midnight and yesterday at midnight
dtAfter = System.DateTime.Today.AddDays(-1);
dtAfter = dtAfter.AddSeconds(-1);
dtBefore = System.DateTime.Today;//.AddDays(-1);
sb.Append(">'");
sb.Append(PostgresDateFormat(dtAfter));
sb.Append("') AND (");
sb.Append(sColumn);
sb.Append(" ");
sb.Append("<'");
sb.Append(PostgresDateFormat(dtBefore));
sb.Append("'");
break;
case "[TODAY]":
//Between yesterday at midnight and tommorow at midnight
dtAfter = System.DateTime.Today.AddSeconds(-1);
dtBefore = System.DateTime.Today.AddDays(1);
//dtBefore=dtBefore.AddSeconds(1);
sb.Append(">'");
sb.Append(PostgresDateFormat(dtAfter));
sb.Append("') AND (");
//sb.Append(" ");
sb.Append(sColumn);
sb.Append(" ");
sb.Append("<'");
sb.Append(PostgresDateFormat(dtBefore));
sb.Append("'");
break;
case "[TOMORROW]":
//Between Tonight at midnight and day after tommorow at midnight
dtAfter = System.DateTime.Today.AddDays(1);
dtAfter = dtAfter.AddSeconds(-1);
dtBefore = System.DateTime.Today.AddDays(2);
//dtBefore=dtBefore.AddSeconds(1);
sb.Append(">'");
sb.Append(PostgresDateFormat(dtAfter));
sb.Append("') AND (");
//sb.Append(" ");
sb.Append(sColumn);
sb.Append(" ");
sb.Append("<'");
sb.Append(PostgresDateFormat(dtBefore));
sb.Append("'");
break;
//Case 402
case "[LAST WEEK]":
//Between two Sundays ago at midnight and last sunday at midnight
dtAfter = System.DateTime.Today;
//go back a week
dtAfter = dtAfter.AddDays(-7);
//go backwards to Sunday
while (dtAfter.DayOfWeek != DayOfWeek.Sunday)
dtAfter = dtAfter.AddDays(-1);
//go to very start of eighth dayahead
dtBefore = dtAfter.AddDays(8);
dtAfter = dtAfter.AddSeconds(-1);
sb.Append(">'");
sb.Append(PostgresDateFormat(dtAfter));
sb.Append("') AND (");
//sb.Append(" ");
sb.Append(sColumn);
sb.Append(" ");
sb.Append("<'");
sb.Append(PostgresDateFormat(dtBefore));
sb.Append("'");
break;
case "[THIS WEEK]":
//Between Sunday at midnight and Next sunday at midnight
dtAfter = System.DateTime.Today;
//go backwards to monday
while (dtAfter.DayOfWeek != DayOfWeek.Monday)
dtAfter = dtAfter.AddDays(-1);
//Now go back to sunday last second
dtAfter = dtAfter.AddSeconds(-1);
dtBefore = System.DateTime.Today;
//go forwards to monday
if (System.DateTime.Today.DayOfWeek == DayOfWeek.Monday)
{
//Monday today? then go to next monday
dtBefore = dtBefore.AddDays(7);
}
else
{
while (dtBefore.DayOfWeek != DayOfWeek.Monday)
dtBefore = dtBefore.AddDays(1);
}
sb.Append(">'");
sb.Append(PostgresDateFormat(dtAfter));
sb.Append("') AND (");
//sb.Append(" ");
sb.Append(sColumn);
sb.Append(" ");
sb.Append("<'");
sb.Append(PostgresDateFormat(dtBefore));
sb.Append("'");
break;
case "[NEXT WEEK]":
//Between Next Sunday at midnight and Next Next sunday at midnight
dtAfter = System.DateTime.Today;
//If today is monday skip over it first
if (dtAfter.DayOfWeek == DayOfWeek.Monday)
dtAfter = dtAfter.AddDays(1);
//go forwards to next monday
while (dtAfter.DayOfWeek != DayOfWeek.Monday)
dtAfter = dtAfter.AddDays(1);
//Now go back to sunday last second
dtAfter = dtAfter.AddDays(-1);
//go seven days ahead
dtBefore = dtAfter.AddDays(7);
//case 1155
dtAfter = dtAfter.AddSeconds(-1);
sb.Append(">'");
sb.Append(PostgresDateFormat(dtAfter));
sb.Append("') AND (");
//sb.Append(" ");
sb.Append(sColumn);
sb.Append(" ");
sb.Append("<'");
sb.Append(PostgresDateFormat(dtBefore));
sb.Append("'");
break;
case "[LAST MONTH]":
//start with the first day of this month
dtAfter = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1, 00, 00, 00);
//subtract a Month
dtAfter = dtAfter.AddMonths(-1);
//Add one month to dtAfter to get end date
dtBefore = dtAfter.AddMonths(1);
//case 1155
dtAfter = dtAfter.AddSeconds(-1);
// 'yyyy-mm-ddTHH:MM:SS'
sb.Append(">'");
sb.Append(PostgresDateFormat(dtAfter));
sb.Append("') AND (");
//sb.Append(" ");
sb.Append(sColumn);
sb.Append(" ");
sb.Append("<'");
sb.Append(PostgresDateFormat(dtBefore));
sb.Append("'");
break;
case "[THIS MONTH]":
//start with the first day of this month
dtAfter = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1, 00, 00, 00);
//Add one month to dtAfter to get end date
dtBefore = dtAfter.AddMonths(1);
//case 1155
dtAfter = dtAfter.AddSeconds(-1);
sb.Append(">'");
sb.Append(PostgresDateFormat(dtAfter));
sb.Append("') AND (");
//sb.Append(" ");
sb.Append(sColumn);
sb.Append(" ");
sb.Append("<'");
sb.Append(PostgresDateFormat(dtBefore));
sb.Append("'");
break;
case "[NEXT MONTH]":
//start with the first day of this month
dtAfter = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1, 00, 00, 00);
//Add a Month
dtAfter = dtAfter.AddMonths(1);
//Add one month to dtAfter to get end date
dtBefore = dtAfter.AddMonths(1);
//case 1155
dtAfter = dtAfter.AddSeconds(-1);
sb.Append(">'");
sb.Append(PostgresDateFormat(dtAfter));
sb.Append("') AND (");
//sb.Append(" ");
sb.Append(sColumn);
sb.Append(" ");
sb.Append("<'");
sb.Append(PostgresDateFormat(dtBefore));
sb.Append("'");
break;
case "[14DAYWINDOW]":
//start with today zero hour
dtAfter = new DateTime(DateTime.Today.Year, DateTime.Today.Month, DateTime.Today.Day, 00, 00, 00);
dtAfter = dtAfter.AddDays(-7);
//Add 15 days to get end date (zero hour so not really 15 full days)
dtBefore = dtAfter.AddDays(15);
//case 1155
dtAfter = dtAfter.AddSeconds(-1);
sb.Append(">'");
sb.Append(PostgresDateFormat(dtAfter));
sb.Append("') AND (");
//sb.Append(" ");
sb.Append(sColumn);
sb.Append(" ");
sb.Append("<'");
sb.Append(PostgresDateFormat(dtBefore));
sb.Append("'");
break;
//case 2067 ADDITIONAL DATE RANGES ************
case "[PAST]":
//Forever up to Now
dtAfter = new DateTime(1753, 1, 2, 00, 00, 00);
dtBefore = System.DateTime.Now;
sb.Append(">'");
sb.Append(PostgresDateFormat(dtAfter));
sb.Append("') AND (");
sb.Append(sColumn);
sb.Append(" ");
sb.Append("<'");
sb.Append(PostgresDateFormat(dtBefore));
sb.Append("'");
break;
case "[FUTURE]":
//From Now to forever (999 years from now)
dtAfter = System.DateTime.Now;
dtBefore = System.DateTime.Now.AddYears(999);
sb.Append(">'");
sb.Append(PostgresDateFormat(dtAfter));
sb.Append("') AND (");
sb.Append(sColumn);
sb.Append(" ");
sb.Append("<'");
sb.Append(PostgresDateFormat(dtBefore));
sb.Append("'");
break;
case "[LASTYEAR]":
//From zero hour january 1 a year ago
dtAfter = new DateTime(DateTime.Now.AddYears(-1).Year, 1, 1, 00, 00, 00);
//To zero hour January 1 this year
dtBefore = new DateTime(DateTime.Now.Year, 1, 1, 00, 00, 00);
sb.Append(">'");
sb.Append(PostgresDateFormat(dtAfter));
sb.Append("') AND (");
sb.Append(sColumn);
sb.Append(" ");
sb.Append("<'");
sb.Append(PostgresDateFormat(dtBefore));
sb.Append("'");
break;
case "[THISYEAR]":
//From zero hour january 1 this year
dtAfter = new DateTime(DateTime.Now.Year, 1, 1, 00, 00, 00);
//To zero hour Jan 1 next year
dtBefore = new DateTime(DateTime.Now.AddYears(1).Year, 1, 1, 00, 00, 00);
sb.Append(">'");
sb.Append(PostgresDateFormat(dtAfter));
sb.Append("') AND (");
sb.Append(sColumn);
sb.Append(" ");
sb.Append("<'");
sb.Append(PostgresDateFormat(dtBefore));
sb.Append("'");
break;
case "[INTHELAST3MONTHS]":
//From Now minus 3 months
dtAfter = DateTime.Now.AddMonths(-3);
//To Now
dtBefore = DateTime.Now;
sb.Append(">'");
sb.Append(PostgresDateFormat(dtAfter));
sb.Append("') AND (");
sb.Append(sColumn);
sb.Append(" ");
sb.Append("<'");
sb.Append(PostgresDateFormat(dtBefore));
sb.Append("'");
break;
case "[INTHELAST6MONTHS]":
//From Now minus 6 months
dtAfter = DateTime.Now.AddMonths(-6);
//To Now
dtBefore = DateTime.Now;
sb.Append(">'");
sb.Append(PostgresDateFormat(dtAfter));
sb.Append("') AND (");
sb.Append(sColumn);
sb.Append(" ");
sb.Append("<'");
sb.Append(PostgresDateFormat(dtBefore));
sb.Append("'");
break;
case "[INTHELASTYEAR]":
//From Now minus 365 days
dtAfter = DateTime.Now.AddDays(-365);
//To Now
dtBefore = DateTime.Now;
sb.Append(">'");
sb.Append(PostgresDateFormat(dtAfter));
sb.Append("') AND (");
sb.Append(sColumn);
sb.Append(" ");
sb.Append("<'");
sb.Append(PostgresDateFormat(dtBefore));
sb.Append("'");
break;
}
#endregion
}
else
{
#region Build criteria for date specified
//RAVEN NOTE: it is my intention that dates come in iso8601 UTC format from the client
//so a simple parse should be sufficient
//https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-date-and-time-format-strings#Roundtrip
System.DateTime dtData = DateTime.Parse(sValue);
//RAVEN NOTE: there is some old code kept commented out for now as I'm not certain I need the high low stuff anymore
// sValue = dtData.ToString(SqlDateFormatHighLow(false));
// string sHighEnd = dtData.ToString(SqlDateFormatHighLow(true));
// string sLowEnd = dtData.ToString(SqlDateFormatHighLow(false));
// string sGreaterThanValue = dtData.AddSeconds(1).ToString(SqlDateFormatHighLow(false));
// string sLessThanValue = dtData.AddSeconds(-1).ToString(SqlDateFormatHighLow(true));
sValue = PostgresDateFormat(ZeroMilliseconds(dtData));
string sHighEnd = PostgresDateFormat(MaxMilliseconds(dtData));
string sLowEnd = PostgresDateFormat(ZeroMilliseconds(dtData));
string sGreaterThanValue = PostgresDateFormat(ZeroMilliseconds(dtData.AddSeconds(1)));
string sLessThanValue = PostgresDateFormat(MaxMilliseconds(dtData.AddSeconds(-1)));
switch (sOperator)
{
//case "Equals":
// sb.Append("='");
// sb.Append(sValue);
// sb.Append("'");
// break;
case "Equals":
sb.Append(">='");
sb.Append(sLowEnd);
sb.Append("') AND (");
sb.Append(sColumn);
sb.Append(" ");
sb.Append("<='");
sb.Append(sHighEnd);
sb.Append("'");
break;
case "GreaterThan":
sb.Append(">'");
sb.Append(sGreaterThanValue);
sb.Append("'");
break;
case "GreaterThanOrEqualTo":
sb.Append(">='");
sb.Append(sLowEnd);
sb.Append("'");
break;
case "LessThan":
sb.Append("<'");
sb.Append(sLessThanValue);
sb.Append("'");
break;
case "LessThanOrEqualTo":
sb.Append("<='");
sb.Append(sHighEnd);
sb.Append("'");
break;
//case "NotEquals":
// sb.Append("<>'");
// sb.Append(sValue);
// sb.Append("'");
// break;
case "NotEquals":
sb.Append("<'");
sb.Append(sLowEnd);
sb.Append("') OR (");
sb.Append(sColumn);
sb.Append(" ");
sb.Append(">'");
sb.Append(sHighEnd);
sb.Append("'");
break;
default:
throw new System.ArgumentOutOfRangeException("OPERATOR_TYPE", sOperator, "GridToSqlCriteria unhandled operator type [" + sOperator + "] IN DATE_TIME");
}
#endregion
}
}
break;
case "System.Decimal":
case "System.Int32":
case "System.Int64"://case 808
{
//case 1795 - it's numeric, convert to locale independant format
NumberFormatInfo nfi = System.Globalization.CultureInfo.CurrentCulture.NumberFormat;
switch (sDataType)
{
case "System.Decimal":
{
if (nfi.CurrencyDecimalSeparator != ".")
{
sValue = sValue.Replace(nfi.CurrencyGroupSeparator, "");
sValue = sValue.Replace(nfi.CurrencyDecimalSeparator, ".");
}
}
break;
case "System.Int32":
{
if (nfi.NumberDecimalSeparator != ".")
{
sValue = sValue.Replace(nfi.NumberGroupSeparator, "");
sValue = sValue.Replace(nfi.NumberDecimalSeparator, ".");
}
}
break;
case "System.Int64":
{
if (nfi.NumberDecimalSeparator != ".")
{
sValue = sValue.Replace(nfi.NumberGroupSeparator, "");
sValue = sValue.Replace(nfi.NumberDecimalSeparator, ".");
}
}
break;
}
switch (sOperator)
{
case "Equals":
sb.Append("=");
sb.Append(sValue);
break;
case "GreaterThan":
sb.Append(">");
sb.Append(sValue);
break;
case "GreaterThanOrEqualTo":
sb.Append(">=");
sb.Append(sValue);
break;
case "LessThan":
sb.Append("<");
sb.Append(sValue);
break;
case "LessThanOrEqualTo":
sb.Append("<=");
sb.Append(sValue);
break;
// case "Like":
// sb.Append("Like N'");
// sb.Append(sValue);
// sb.Append("%'");
// break;
case "NotEquals":
sb.Append("<>");
sb.Append(sValue);
break;
default:
throw new System.ArgumentOutOfRangeException("OPERATOR_TYPE", sOperator, "GridToSqlCriteria unhandled operator type [" + sOperator + "] IN DECIMAL");
}
break;
}
default:
throw new System.ArgumentOutOfRangeException("DATA_TYPE", sDataType, "GridToSqlCriteria unhandled data type[" + sDataType + "]");
}
#endregion
}
//
//if(log.IsDebugEnabled)
// //case 1039 //log.Debug("GridToSqlCriteria: returning[" + sb.ToString() + "]");
return sb.ToString();
}
// public static string SqlDateFormatHighLow(bool bhigh)
// {
// //new test version
// if (bhigh)
// return SqlDateFormat() + ".999";
// else
// return SqlDateFormat() + ".000";
// }
public static DateTime ZeroMilliseconds(DateTime d)
{
if (d.Millisecond == 0) return d;
return new DateTime(d.Year, d.Month, d.Day, d.Hour, d.Minute, d.Second, DateTimeKind.Utc);
}
public static DateTime MaxMilliseconds(DateTime d)
{
if (d.Millisecond == 0) return d;
return new DateTime(d.Year, d.Month, d.Day, d.Hour, d.Minute, d.Second, 999, DateTimeKind.Utc);
}
/// <summary>
/// Postgres compatible date format
/// https://www.postgresql.org/docs/current/datatype-datetime.html#DATATYPE-DATETIME-DATE-TABLE
/// </summary>
/// <returns></returns>
public static string PostgresDateFormat(DateTime theDate)
{
//If this was used it should be like this for a UTC date to iso8601
// ISO8601 with 7 decimal places
return theDate.ToString("o", CultureInfo.InvariantCulture);
// if (DBUtil.DB.DBType == DataBaseType.MSSQL)
// return "yyyy-MM-ddTHH:mm:ss";
// else
// return "yyyy-MM-dd HH:mm:ss";
}
}//eoc
}//ens