Skip to content

Commit

Permalink
Change date converters to use total days
Browse files Browse the repository at this point in the history
  • Loading branch information
plblum committed Apr 6, 2024
1 parent 48810d0 commit 65731ce
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 50 deletions.
18 changes: 5 additions & 13 deletions Jivs.code-workspace
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,6 @@
"typescript.enablePromptUseGlobalTsdk": false,
"explorerExclude.backup": {
"**/.git": true,
"**/.svn": true,
"**/.hg": true,
"**/CVS": true,
"**/.DS_Store": true,
"**/Thumbs.db": true,
".eslintignore": true,
".gitattributes": true,
Expand All @@ -35,23 +31,19 @@
".vscode": true
},
"files.exclude": {
"**/.git": false,
"**/.svn": false,
"**/.hg": false,
"**/CVS": false,
"**/.DS_Store": false,
"**/Thumbs.db": false,
".eslintignore": false,
".gitattributes": false,
".gitignore": false,
".npmignore": false,
".vscode": false,
"**/.git": false,
"**/Thumbs.db": false,
"Jivs.code-workspace": false,
"lerna.json": false,
"LICENSE": false,
"package-lock.json": false,
"typedoc_output": false,
"node_modules": false,
".vscode": false
"package-lock.json": false,
"typedoc_output": false
},
"explorerExclude.showPicker": false,
"explorer.excludeGitIgnore": false,
Expand Down
39 changes: 19 additions & 20 deletions packages/jivs-engine/src/DataTypes/DataTypeConverters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,15 @@ export class DateTimeConverter implements IDataTypeConverter
return value.getTime();
}
}

/**
* For JavaScript Date objects to convert them into a number of milliseconds
* using Date.getTime(), without the time of day part (its always set to 0:00:00).
* It assumes the Date object is in UTC and returns a UTC date.
* Date comparison doesn't work by using == and != in JavaScript.
* Officially, you compare with getTime() results.
* When this library compares Date objects, it expects this converter
* to get involved so its DefaultComparer function has two numbers
* from which to work.
* Converts a Date object into a total number of days since Jan 1, 1970 using UTC values.
* It ignores the time of day part of the Date object.
* This is used instead of Date.getTime which is a number of milliseconds
* because total days is useful in other situations like difference between
* two Date objects by date.
* DataType LookupKey: "Date".
* It assumes the Date object is setup in UTC time.
* This is automatically used when there is no dataTypeLookup key specified
* and the value is a date.
*/
Expand All @@ -74,13 +73,16 @@ export class UTCDateOnlyConverter implements IDataTypeConverter
if (isNaN(value.getTime()))
return undefined;
let dateOnly = new Date(Date.UTC(value.getUTCFullYear(), value.getUTCMonth(), value.getUTCDate()));
return dateOnly.getTime();
return Math.floor(dateOnly.getTime() / 86400000);
}
}
/**
* For JavaScript Date objects to convert them into a number of milliseconds
* using Date.getTime(), without the time of day part (its always set to 0:00:00).
* It assumes the Date object is in local time and returns a local date.
* Converts a Date object into a total number of days since Jan 1, 1970 using local date values.
* It ignores the time of day part of the Date object.
* This is used instead of Date.getTime which is a number of milliseconds
* because total days is useful in other situations like difference between
* two Date objects by date.
* It assumes the Date object is setup in local time.
* DataType Lookup Key: "LocalDate"
*/
export class LocalDateOnlyConverter implements IDataTypeConverter
Expand All @@ -93,7 +95,7 @@ export class LocalDateOnlyConverter implements IDataTypeConverter
if (isNaN(value.getTime()))
return undefined;
let dateOnly = new Date(value.getFullYear(), value.getMonth(), value.getDate());
return dateOnly.getTime();
return Math.floor(dateOnly.getTime() / 86400000);
}
}

Expand Down Expand Up @@ -152,20 +154,17 @@ export class IntegerConverter implements IDataTypeConverter

/**
* For Dates values to be compared by their total years since Jan 1, 1970
* Its actually the same conversion as UTCDateOnlyConverter, just established
* with another lookup key that is easier to understand for this purpose,
* and UTCDateOnlyConverter is selected when there is no lookup key.
* DataTypeLookupKey = "TotalDays"
* Use in Conditions that offer the ConversionLookupKey property, assigned
* to ConversionLookupKey and/or SecondValueConversionLookupKey.
*/
export class TotalDaysConverter implements IDataTypeConverter
export class TotalDaysConverter extends UTCDateOnlyConverter
{
public supportsValue(value: any, dataTypeLookupKey: string | null): boolean {
return (dataTypeLookupKey === LookupKey.TotalDays) &&
value instanceof Date;
}
public convert(value: Date, dataTypeLookupKey: string): string | number | Date | null | undefined {
if (isNaN(value.getTime()))
return undefined;
let dateOnly = new Date(Date.UTC(value.getUTCFullYear(), value.getUTCMonth(), value.getUTCDate()));
return Math.floor(dateOnly.getTime() / 86400000);
}
}
79 changes: 62 additions & 17 deletions packages/jivs-engine/tests/DataTypes/DataTypeConverters.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import {
TotalDaysConverter, IntegerConverter, TimeOfDayOnlyConverter, TimeOfDayHMSOnlyConverter
} from './../../src/DataTypes/DataTypeConverters';
import { LookupKey } from '../../src/DataTypes/LookupKeys';
import { ComparersResult } from '../../src/Interfaces/DataTypeComparerService';
import { DataTypeConverterService } from '../../src/Services/DataTypeConverterService';
import { MockValidationServices } from '../Mocks';
import { DataTypeComparerService } from '../../src/Services/DataTypeComparerService';
describe('DataTypeConverter concrete classes', () => {
Expand Down Expand Up @@ -67,11 +65,26 @@ describe('DataTypeConverter concrete classes', () => {
let testItem = new UTCDateOnlyConverter();
// convert expects to be called after supportsValue is true.
// So no illegal values as parameters tested
let test1 = new Date(Date.UTC(2000, 10, 5));
let test2 = new Date(Date.UTC(2023, 0, 1, 4, 30));
let test2dateonly = new Date(Date.UTC(2023, 0, 1));
expect(testItem.convert(test1, LookupKey.Date)).toBe(test1.getTime());
expect(testItem.convert(test2, LookupKey.Date)).toBe(test2dateonly.getTime());
let test1 = new Date(Date.UTC(1970, 0, 1));
let test2 = new Date(Date.UTC(1970, 0, 2, 4, 30));
let test3 = new Date(Date.UTC(1970, 0, 2));
let test4 = new Date(Date.UTC(1969, 11, 31));
let test5 = new Date(Date.UTC(1969, 11, 31, 23, 59, 59));
let test6 = new Date(Date.UTC(1971, 0, 1));
let test7 = new Date(Date.UTC(1970, 11, 31));
let test8 = new Date(Date.UTC(1972, 2, 1)); // leap year, one day after leap day
let test9 = new Date(Date.UTC(1972, 1, 28)); // leap year, one day before leap day
let test10 = new Date(Date.UTC(1972, 1, 29)); // leap year, leap day
expect(testItem.convert(test1, LookupKey.Date)).toBe(0);
expect(testItem.convert(test2, LookupKey.Date)).toBe(1);
expect(testItem.convert(test3, LookupKey.Date)).toBe(1);
expect(testItem.convert(test4, LookupKey.Date)).toBe(-1);
expect(testItem.convert(test5, LookupKey.Date)).toBe(-1);
expect(testItem.convert(test7, LookupKey.Date)).toBe(364);
expect(testItem.convert(test6, LookupKey.Date)).toBe(365);
expect(testItem.convert(test8, LookupKey.Date)).toBe(365 + 365 + 31 /* jan */ + 29 /* leap feb */);
expect(testItem.convert(test9, LookupKey.Date)).toBe(365 + 365 + 31 /* jan */ + 27);
expect(testItem.convert(test10, LookupKey.Date)).toBe(365 + 365 + 31 /* jan */ + 28);
// dates with an illegal value will convert to undefined
let illegalDate = new Date("foo");
expect(testItem.convert(illegalDate, LookupKey.Date)).toBeUndefined();
Expand All @@ -90,11 +103,28 @@ describe('DataTypeConverter concrete classes', () => {
let testItem = new LocalDateOnlyConverter();
// convert expects to be called after supportsValue is true.
// So no illegal values as parameters tested
let test1 = new Date(2000, 10, 5);
let test2 = new Date(2023, 0, 1, 4, 30);
let test2dateonly = new Date(2023, 0, 1);
expect(testItem.convert(test1, LookupKey.LocalDate)).toBe(test1.getTime());
expect(testItem.convert(test2, LookupKey.LocalDate)).toBe(test2dateonly.getTime());
// Convert returns a total number of days since Jan 1, 1970, which equals 0.
// Thus the test data.
let test1 = new Date(1970, 0, 1);
let test2 = new Date(1970, 0, 2, 4, 30);
let test3 = new Date(1970, 0, 2);
let test4 = new Date(1969, 11, 31);
let test5 = new Date(1969, 11, 31, 23, 59, 59);
let test6 = new Date(1971, 0, 1);
let test7 = new Date(1970, 11, 31);
let test8 = new Date(1972, 2, 1); // leap year, one day after leap day
let test9 = new Date(1972, 1, 28); // leap year, one day before leap day
let test10 = new Date(1972, 1, 29); // leap year, leap day
expect(testItem.convert(test1, LookupKey.LocalDate)).toBe(0);
expect(testItem.convert(test2, LookupKey.LocalDate)).toBe(1);
expect(testItem.convert(test3, LookupKey.LocalDate)).toBe(1);
expect(testItem.convert(test4, LookupKey.LocalDate)).toBe(-1);
expect(testItem.convert(test5, LookupKey.LocalDate)).toBe(-1);
expect(testItem.convert(test7, LookupKey.LocalDate)).toBe(364);
expect(testItem.convert(test6, LookupKey.LocalDate)).toBe(365);
expect(testItem.convert(test8, LookupKey.LocalDate)).toBe(365 + 365 + 31 /* jan */ + 29 /* leap feb */);
expect(testItem.convert(test9, LookupKey.LocalDate)).toBe(365 + 365 + 31 /* jan */ + 27);
expect(testItem.convert(test10, LookupKey.LocalDate)).toBe(365 + 365 + 31 /* jan */ + 28);
// dates with an illegal value will convert to undefined
let illegalDate = new Date("foo");
expect(testItem.convert(illegalDate, LookupKey.LocalDate)).toBeUndefined();
Expand Down Expand Up @@ -182,11 +212,26 @@ describe('DataTypeConverter concrete classes', () => {
let testItem = new TotalDaysConverter();
// convert expects to be called after supportsValue is true.
// So no illegal values as parameters tested
let date1 = new Date(Date.UTC(2000, 10, 2));
let date2 = new Date(Date.UTC(2000, 10, 2, 5, 4, 3));
let expected = Math.floor(date1.getTime() / 86400000);
expect(testItem.convert(date1, LookupKey.TotalDays)).toBe(expected);
expect(testItem.convert(date2, LookupKey.TotalDays)).toBe(expected);
let test1 = new Date(Date.UTC(1970, 0, 1));
let test2 = new Date(Date.UTC(1970, 0, 2, 4, 30));
let test3 = new Date(Date.UTC(1970, 0, 2));
let test4 = new Date(Date.UTC(1969, 11, 31));
let test5 = new Date(Date.UTC(1969, 11, 31, 23, 59, 59));
let test6 = new Date(Date.UTC(1971, 0, 1));
let test7 = new Date(Date.UTC(1970, 11, 31));
let test8 = new Date(Date.UTC(1972, 2, 1)); // leap year, one day after leap day
let test9 = new Date(Date.UTC(1972, 1, 28)); // leap year, one day before leap day
let test10 = new Date(Date.UTC(1972, 1, 29)); // leap year, leap day
expect(testItem.convert(test1, LookupKey.TotalDays)).toBe(0);
expect(testItem.convert(test2, LookupKey.TotalDays)).toBe(1);
expect(testItem.convert(test3, LookupKey.TotalDays)).toBe(1);
expect(testItem.convert(test4, LookupKey.TotalDays)).toBe(-1);
expect(testItem.convert(test5, LookupKey.TotalDays)).toBe(-1);
expect(testItem.convert(test7, LookupKey.TotalDays)).toBe(364);
expect(testItem.convert(test6, LookupKey.TotalDays)).toBe(365);
expect(testItem.convert(test8, LookupKey.TotalDays)).toBe(365 + 365 + 31 /* jan */ + 29 /* leap feb */);
expect(testItem.convert(test9, LookupKey.TotalDays)).toBe(365 + 365 + 31 /* jan */ + 27);
expect(testItem.convert(test10, LookupKey.TotalDays)).toBe(365 + 365 + 31 /* jan */ + 28);
});
});
});

0 comments on commit 65731ce

Please sign in to comment.