1- import { describe , it , expect } from 'vitest' ;
1+ import { describe , it , expect , test } from 'vitest' ;
22import {
33 formatDate ,
44 getMonthDaysByWeek ,
@@ -12,6 +12,15 @@ import {
1212 hasDayOfWeek ,
1313 replaceDayOfWeek ,
1414 isStringDate ,
15+ timeInterval ,
16+ startOfInterval ,
17+ endOfInterval ,
18+ parseDate ,
19+ intervalOffset ,
20+ isSameInterval ,
21+ intervalDifference ,
22+ isLeapYear ,
23+ isDateWithin ,
1524} from './date.js' ;
1625import { createLocaleSettings , defaultLocale , LocaleSettings } from './locale.js' ;
1726import {
@@ -21,12 +30,23 @@ import {
2130 type CustomIntlDateTimeFormatOptions ,
2231 DateToken ,
2332 PeriodTypeCode ,
33+ TimeIntervalType ,
2434} from './date_types.js' ;
2535import { getWeekStartsOnFromIntl } from './dateInternal.js' ;
26- import { parseISO } from 'date-fns' ;
36+ import {
37+ timeDay ,
38+ timeHour ,
39+ timeMillisecond ,
40+ timeMinute ,
41+ timeMonth ,
42+ timeYear ,
43+ timeSecond ,
44+ timeWeek ,
45+ } from 'd3-time' ;
2746
2847export const testDateStr = '2023-11-21' ; // "good" default date as the day (21) is bigger than 12 (number of months). And november is a good month1 (because why not?)
29- export const testDate = parseISO ( '2023-11-21' ) ; // "good" default date as the day (21) is bigger than 12 (number of months). And november is a good month1 (because why not?)
48+ export const testDate = parseDate ( '2023-11-21' ) ; // "good" default date as the day (21) is bigger than 12 (number of months). And november is a good month1 (because why not?)
49+
3050const dt_2M_2d = new Date ( 2023 , 10 , 21 ) ;
3151const dt_2M_1d = new Date ( 2023 , 10 , 7 ) ;
3252const dt_1M_1d = new Date ( 2023 , 2 , 7 ) ;
@@ -1236,3 +1256,192 @@ describe('isStringDate()', () => {
12361256 expect ( isStringDate ( '1982-03-30T11:25:59.1234567Z' ) ) . true ;
12371257 } ) ;
12381258} ) ;
1259+
1260+ describe ( 'parseDate()' , ( ) => {
1261+ it ( 'date only as locale date' , ( ) => {
1262+ expect ( parseDate ( '1982-03-30' ) ) . toEqual ( new Date ( '1982-03-30T04:00:00.000Z' ) ) ;
1263+ } ) ;
1264+
1265+ it ( 'date and time only (hour/minute) as locale date' , ( ) => {
1266+ expect ( parseDate ( '1982-03-30T04:00' ) ) . toEqual ( new Date ( '1982-03-30T08:00:00.000Z' ) ) ;
1267+ } ) ;
1268+
1269+ it ( 'date and time only (hour/minute/second) as locale date' , ( ) => {
1270+ expect ( parseDate ( '1982-03-30T04:00:00' ) ) . toEqual ( new Date ( '1982-03-30T08:00:00.000Z' ) ) ;
1271+ } ) ;
1272+
1273+ it ( 'should not equal UTC date' , ( ) => {
1274+ // Just an extra check
1275+ expect ( parseDate ( '1982-03-30' ) ) . not . toEqual ( new Date ( '1982-03-30' ) ) ;
1276+ } ) ;
1277+
1278+ it ( 'date with timezome (UTC)' , ( ) => {
1279+ expect ( parseDate ( '1982-03-30T11:25:59Z' ) ) . toEqual ( new Date ( '1982-03-30T11:25:59Z' ) ) ;
1280+ } ) ;
1281+
1282+ it ( 'date with time (offset)' , ( ) => {
1283+ expect ( parseDate ( '1982-03-30T00:00:00-01:00' ) ) . toEqual ( new Date ( '1982-03-30T00:00:00-01:00' ) ) ;
1284+ } ) ;
1285+
1286+ it ( 'date with time and 3 digit milliseconds (UTC)' , ( ) => {
1287+ expect ( parseDate ( '1982-03-30T11:25:59.123Z' ) ) . toEqual ( new Date ( '1982-03-30T11:25:59.123Z' ) ) ;
1288+ } ) ;
1289+
1290+ it ( 'date with time with 7 digit milliseconds (UTC)' , ( ) => {
1291+ expect ( parseDate ( '1982-03-30T11:25:59.1234567Z' ) ) . toEqual (
1292+ new Date ( '1982-03-30T11:25:59.1234567Z' )
1293+ ) ;
1294+ } ) ;
1295+
1296+ it ( 'invalid date string' , ( ) => {
1297+ expect ( parseDate ( 'some_string' ) ) . toEqual ( new Date ( 'Invalid Date' ) ) ;
1298+ } ) ;
1299+ } ) ;
1300+
1301+ describe ( 'timeInterval()' , ( ) => {
1302+ test . each ( [
1303+ [ 'millisecond' , timeMillisecond ] ,
1304+ [ 'second' , timeSecond ] ,
1305+ [ 'minute' , timeMinute ] ,
1306+ [ 'hour' , timeHour ] ,
1307+ [ 'day' , timeDay ] ,
1308+ [ 'week' , timeWeek ] ,
1309+ [ 'month' , timeMonth ] ,
1310+ // ['quarter', timeMonth.every(3)], // TODO: how to verify this?
1311+ [ 'year' , timeYear ] ,
1312+ ] ) ( 'timeInterval(%s) => %s' , ( interval , expected ) => {
1313+ expect ( timeInterval ( interval as TimeIntervalType ) ) . toEqual ( expected ) ;
1314+ } ) ;
1315+ } ) ;
1316+
1317+ describe ( 'startOfInterval()' , ( ) => {
1318+ test . each ( [
1319+ [ 'millisecond' , '2023-03-07T14:02:03.004' ] ,
1320+ [ 'second' , '2023-03-07T14:02:03' ] ,
1321+ [ 'minute' , '2023-03-07T14:02' ] ,
1322+ [ 'hour' , '2023-03-07T14:00:00.000' ] ,
1323+ [ 'day' , '2023-03-07' ] ,
1324+ [ 'week' , '2023-03-05' ] ,
1325+ [ 'month' , '2023-03-01' ] ,
1326+ [ 'quarter' , '2023-01-01' ] ,
1327+ [ 'year' , '2023-01-01' ] ,
1328+ ] ) ( 'startOfInterval(%s, %s) => %s' , ( interval , expected ) => {
1329+ expect ( startOfInterval ( interval as TimeIntervalType , dt_1M_1d_time_pm ) ) . toEqual (
1330+ parseDate ( expected )
1331+ ) ;
1332+ } ) ;
1333+ } ) ;
1334+
1335+ describe ( 'endOfInterval()' , ( ) => {
1336+ test . each ( [
1337+ [ 'millisecond' , '2023-03-07T14:02:03.004' ] ,
1338+ [ 'second' , '2023-03-07T14:02:03.999' ] ,
1339+ [ 'minute' , '2023-03-07T14:02:59.999' ] ,
1340+ [ 'hour' , '2023-03-07T14:59:59.999' ] ,
1341+ [ 'day' , '2023-03-07T23:59:59.999' ] ,
1342+ [ 'week' , '2023-03-11T23:59:59.999' ] ,
1343+ [ 'month' , '2023-03-31T23:59:59.999' ] ,
1344+ [ 'quarter' , '2023-03-31T23:59:59.999' ] ,
1345+ [ 'year' , '2023-12-31T23:59:59.999' ] ,
1346+ ] ) ( 'endOfInterval(%s, %s) => %s' , ( interval , expected ) => {
1347+ expect ( endOfInterval ( interval as TimeIntervalType , dt_1M_1d_time_pm ) ) . toEqual (
1348+ parseDate ( expected )
1349+ ) ;
1350+ } ) ;
1351+ } ) ;
1352+
1353+ describe ( 'intervalOffset()' , ( ) => {
1354+ test . each ( [
1355+ [ 'millisecond' , 1 , '2023-11-21T04:00:00.001Z' ] ,
1356+ [ 'millisecond' , - 1 , '2023-11-21T03:59:59.999Z' ] ,
1357+ [ 'second' , 1 , '2023-11-21T04:00:01Z' ] ,
1358+ [ 'second' , - 1 , '2023-11-21T03:59:59Z' ] ,
1359+ [ 'minute' , 1 , '2023-11-21T04:01:00Z' ] ,
1360+ [ 'minute' , - 1 , '2023-11-21T03:59:00Z' ] ,
1361+ [ 'hour' , 1 , '2023-11-21T05:00:00Z' ] ,
1362+ [ 'hour' , - 1 , '2023-11-21T03:00:00Z' ] ,
1363+ [ 'day' , 1 , '2023-11-22' ] ,
1364+ [ 'day' , - 1 , '2023-11-20' ] ,
1365+ [ 'week' , 1 , '2023-11-28' ] ,
1366+ [ 'week' , - 1 , '2023-11-14' ] ,
1367+ [ 'month' , 1 , '2023-12-21' ] ,
1368+ [ 'month' , - 1 , '2023-10-21' ] ,
1369+ [ 'quarter' , 1 , '2024-02-01' ] ,
1370+ [ 'quarter' , - 1 , '2023-08-01' ] ,
1371+ [ 'year' , 1 , '2024-11-21' ] ,
1372+ [ 'year' , - 1 , '2022-11-21' ] ,
1373+ ] ) ( 'intervalOffset(%s, %s, %s) => %s' , ( interval , offset , expected ) => {
1374+ expect ( intervalOffset ( interval as TimeIntervalType , testDate , offset ) ) . toEqual (
1375+ parseDate ( expected )
1376+ ) ;
1377+ } ) ;
1378+ } ) ;
1379+
1380+ describe ( 'isSameInterval()' , ( ) => {
1381+ test . each ( [
1382+ [ 'day' , '2023-03-07T00:00' , '2023-03-07T23:59' , true ] ,
1383+ [ 'day' , '2023-03-07T11:00' , '2023-03-08T12:00' , false ] ,
1384+ [ 'week' , '2023-03-07' , '2023-03-08' , true ] ,
1385+ [ 'week' , '2023-03-07' , '2023-03-14' , false ] ,
1386+ [ 'month' , '2023-03-07' , '2023-03-30' , true ] ,
1387+ [ 'month' , '2023-03-07' , '2023-04-07' , false ] ,
1388+ [ 'quarter' , '2023-03-07' , '2023-01-07' , true ] ,
1389+ [ 'quarter' , '2023-03-07' , '2023-04-07' , false ] ,
1390+ [ 'year' , '2023-03-07' , '2023-11-21' , true ] ,
1391+ [ 'year' , '2023-03-07' , '2024-03-07' , false ] ,
1392+ ] ) ( 'isSameInterval(%s, %s, %s) => %s' , ( interval , date1 , date2 , expected ) => {
1393+ expect ( isSameInterval ( interval as TimeIntervalType , parseDate ( date1 ) , parseDate ( date2 ) ) ) . toBe (
1394+ expected
1395+ ) ;
1396+ } ) ;
1397+ } ) ;
1398+
1399+ describe ( 'intervalDifference()' , ( ) => {
1400+ test . each ( [
1401+ [ 'day' , '2023-03-07T00:00' , '2023-03-07T23:59' , 0 ] , // Same day
1402+ [ 'day' , '2023-03-07' , '2023-03-08' , 1 ] , // Next day
1403+ [ 'day' , '2023-01-01' , '2023-12-31' , 364 ] , // Full year
1404+ [ 'day' , '2023-01-01' , '2024-01-01' , 365 ] , // Next year
1405+ [ 'week' , '2023-03-05' , '2023-03-11' , 0 ] , // Same week
1406+ [ 'week' , '2023-03-07' , '2023-03-14' , 1 ] , // Next week
1407+ [ 'month' , '2023-01-01' , '2023-01-31' , 0 ] , // Same month
1408+ [ 'month' , '2023-01-01' , '2023-02-01' , 1 ] , // Next month
1409+ [ 'quarter' , '2023-01-01' , '2023-03-31' , 0 ] , // Same quarter
1410+ [ 'quarter' , '2023-01-01' , '2023-04-01' , 1 ] , // Next quarter
1411+ [ 'year' , '2023-01-01' , '2023-12-31' , 0 ] , // Same year
1412+ [ 'year' , '2023-01-01' , '2024-01-01' , 1 ] , // Next year
1413+ ] ) ( 'intervalDifference(%s, %s, %s) => %s' , ( interval , date1 , date2 , expected ) => {
1414+ expect (
1415+ intervalDifference ( interval as TimeIntervalType , parseDate ( date1 ) , parseDate ( date2 ) )
1416+ ) . toEqual ( expected ) ;
1417+ } ) ;
1418+ } ) ;
1419+
1420+ describe ( 'isLeapYear()' , ( ) => {
1421+ test . each ( [
1422+ [ '2020-01-01' , true ] ,
1423+ [ '2021-01-01' , false ] ,
1424+ [ '2022-01-01' , false ] ,
1425+ [ '2023-01-01' , false ] ,
1426+ [ '2024-01-01' , true ] ,
1427+ ] ) ( 'isLeapYear(%s) => %s' , ( date , expected ) => {
1428+ expect ( isLeapYear ( parseDate ( date ) ) ) . toBe ( expected ) ;
1429+ } ) ;
1430+ } ) ;
1431+
1432+ describe ( 'isDateWithin()' , ( ) => {
1433+ test . each ( [
1434+ [ '2023-03-07' , '2023-03-06' , '2023-03-08' , true ] , // between
1435+ [ '2023-03-07' , '2023-03-07' , '2023-03-08' , true ] , // match start
1436+ [ '2023-03-07' , '2023-03-06' , '2023-03-07' , true ] , // match end
1437+ [ '2023-03-07' , '2023-03-08' , '2023-03-09' , false ] , // outside start
1438+ [ '2023-03-07' , '2023-03-05' , '2023-03-06' , false ] , // outside end
1439+ ] ) ( 'isDateWithin(%s, %s) => %s' , ( date , start , end , expected ) => {
1440+ expect (
1441+ isDateWithin ( parseDate ( date ) , {
1442+ start : parseDate ( start ) ,
1443+ end : parseDate ( end ) ,
1444+ } )
1445+ ) . toBe ( expected ) ;
1446+ } ) ;
1447+ } ) ;
0 commit comments