Merge 3ef7e50b5b into b47d132839
				
					
				
			This commit is contained in:
		
						commit
						e31aae4408
					
				| @ -36,6 +36,7 @@ | |||||||
|     "release": "node ./scripts/release.mjs" |     "release": "node ./scripts/release.mjs" | ||||||
|   }, |   }, | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|  |     "@date-fns/utc": "^1.2.0", | ||||||
|     "@it-tools/bip39": "^0.0.4", |     "@it-tools/bip39": "^0.0.4", | ||||||
|     "@it-tools/oggen": "^1.3.0", |     "@it-tools/oggen": "^1.3.0", | ||||||
|     "@regexper/render": "^1.0.0", |     "@regexper/render": "^1.0.0", | ||||||
|  | |||||||
							
								
								
									
										7
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										7
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							| @ -5,6 +5,9 @@ settings: | |||||||
|   excludeLinksFromLockfile: false |   excludeLinksFromLockfile: false | ||||||
| 
 | 
 | ||||||
| dependencies: | dependencies: | ||||||
|  |   '@date-fns/utc': | ||||||
|  |     specifier: ^1.2.0 | ||||||
|  |     version: 1.2.0 | ||||||
|   '@it-tools/bip39': |   '@it-tools/bip39': | ||||||
|     specifier: ^0.0.4 |     specifier: ^0.0.4 | ||||||
|     version: 0.0.4 |     version: 0.0.4 | ||||||
| @ -1941,6 +1944,10 @@ packages: | |||||||
|       vue: 3.3.4 |       vue: 3.3.4 | ||||||
|     dev: false |     dev: false | ||||||
| 
 | 
 | ||||||
|  |   /@date-fns/utc@1.2.0: | ||||||
|  |     resolution: {integrity: sha512-YLq+crMPJiBmIdkRmv9nZuZy1mVtMlDcUKlg4mvI0UsC/dZeIaGoGB5p/C4FrpeOhZ7zBTK03T58S0DFkRNMnw==} | ||||||
|  |     dev: false | ||||||
|  | 
 | ||||||
|   /@emotion/hash@0.8.0: |   /@emotion/hash@0.8.0: | ||||||
|     resolution: {integrity: sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==} |     resolution: {integrity: sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==} | ||||||
|     dev: false |     dev: false | ||||||
|  | |||||||
| @ -11,7 +11,7 @@ test.describe('Date time converter - json to yaml', () => { | |||||||
| 
 | 
 | ||||||
|   test('Format is auto detected from a date and the date is correctly converted', async ({ page }) => { |   test('Format is auto detected from a date and the date is correctly converted', async ({ page }) => { | ||||||
|     const initialFormat = await page.getByTestId('date-time-converter-format-select').innerText(); |     const initialFormat = await page.getByTestId('date-time-converter-format-select').innerText(); | ||||||
|     expect(initialFormat.trim()).toEqual('Timestamp'); |     expect(initialFormat.trim()).toEqual('Unix timestamp'); | ||||||
| 
 | 
 | ||||||
|     await page.getByTestId('date-time-converter-input').fill('2023-04-12T23:10:24+02:00'); |     await page.getByTestId('date-time-converter-input').fill('2023-04-12T23:10:24+02:00'); | ||||||
| 
 | 
 | ||||||
| @ -22,6 +22,7 @@ test.describe('Date time converter - json to yaml', () => { | |||||||
|       'Wed Apr 12 2023 23:10:24 GMT+0200 (Central European Summer Time)', |       'Wed Apr 12 2023 23:10:24 GMT+0200 (Central European Summer Time)', | ||||||
|     ); |     ); | ||||||
|     expect((await page.getByTestId('ISO 8601').inputValue()).trim()).toEqual('2023-04-12T23:10:24+02:00'); |     expect((await page.getByTestId('ISO 8601').inputValue()).trim()).toEqual('2023-04-12T23:10:24+02:00'); | ||||||
|  |     expect((await page.getByTestId('ISO 8601 UTC').inputValue()).trim()).toEqual('2023-04-12T21:10:24.000Z'); | ||||||
|     expect((await page.getByTestId('ISO 9075').inputValue()).trim()).toEqual('2023-04-12 23:10:24'); |     expect((await page.getByTestId('ISO 9075').inputValue()).trim()).toEqual('2023-04-12 23:10:24'); | ||||||
|     expect((await page.getByTestId('Unix timestamp').inputValue()).trim()).toEqual('1681333824'); |     expect((await page.getByTestId('Unix timestamp').inputValue()).trim()).toEqual('1681333824'); | ||||||
|     expect((await page.getByTestId('RFC 7231').inputValue()).trim()).toEqual('Wed, 12 Apr 2023 21:10:24 GMT'); |     expect((await page.getByTestId('RFC 7231').inputValue()).trim()).toEqual('Wed, 12 Apr 2023 21:10:24 GMT'); | ||||||
|  | |||||||
| @ -2,15 +2,20 @@ import { describe, expect, test } from 'vitest'; | |||||||
| import { | import { | ||||||
|   dateToExcelFormat, |   dateToExcelFormat, | ||||||
|   excelFormatToDate, |   excelFormatToDate, | ||||||
|  |   fromJSDate, | ||||||
|  |   fromTimestamp, | ||||||
|   isExcelFormat, |   isExcelFormat, | ||||||
|   isISO8601DateTimeString, |   isISO8601DateTimeString, | ||||||
|   isISO9075DateString, |   isISO9075DateString, | ||||||
|  |   isJSDate, | ||||||
|   isMongoObjectId, |   isMongoObjectId, | ||||||
|   isRFC3339DateString, |   isRFC3339DateString, | ||||||
|   isRFC7231DateString, |   isRFC7231DateString, | ||||||
|   isTimestamp, |   isTimestamp, | ||||||
|  |   isTimestampMicroSeconds, | ||||||
|   isUTCDateString, |   isUTCDateString, | ||||||
|   isUnixTimestamp, |   isUnixTimestamp, | ||||||
|  |   toJSDate, | ||||||
| } from './date-time-converter.models'; | } from './date-time-converter.models'; | ||||||
| 
 | 
 | ||||||
| describe('date-time-converter models', () => { | describe('date-time-converter models', () => { | ||||||
| @ -113,6 +118,45 @@ describe('date-time-converter models', () => { | |||||||
|       expect(isTimestamp('foo')).toBe(false); |       expect(isTimestamp('foo')).toBe(false); | ||||||
|       expect(isTimestamp('')).toBe(false); |       expect(isTimestamp('')).toBe(false); | ||||||
|     }); |     }); | ||||||
|  | 
 | ||||||
|  |     test('should return true for valid Unix timestamps in microseconds', () => { | ||||||
|  |       expect(isTimestamp('1701227351995845')).toBe(true); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     test('should return false for invalid Unix timestamps in microseconds', () => { | ||||||
|  |       expect(isTimestamp('170122735199584')).toBe(false); | ||||||
|  |       expect(isTimestamp('17012273519958')).toBe(false); | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   describe('isTimestampMicroSeconds', () => { | ||||||
|  |     test('should return true for valid Unix timestamps in microseconds', () => { | ||||||
|  |       expect(isTimestampMicroSeconds('1649792026123123')).toBe(true); | ||||||
|  |       expect(isTimestampMicroSeconds('1701227351995845')).toBe(true); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     test('should return false for invalid Unix timestamps in microseconds', () => { | ||||||
|  |       expect(isTimestampMicroSeconds('foo')).toBe(false); | ||||||
|  |       expect(isTimestampMicroSeconds('')).toBe(false); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     test('should return false for invalid Unix timestamps not in microseconds', () => { | ||||||
|  |       expect(isTimestampMicroSeconds('170122735199584')).toBe(false); | ||||||
|  |       expect(isTimestampMicroSeconds('17012273519958')).toBe(false); | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   describe('fromTimestamp', () => { | ||||||
|  |     test('should return valid Date for valid Unix timestamps in microseconds', () => { | ||||||
|  |       expect(fromTimestamp('1649792026123123').toString()).toBe(new Date(1649792026123).toString()); | ||||||
|  |       expect(fromTimestamp('1701227351995845').toString()).toBe(new Date(1701227351995).toString()); | ||||||
|  |       expect(fromTimestamp('0').toString()).toBe(new Date(0).toString()); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     test('should return Date(0) for invalid Unix timestamps not in microseconds', () => { | ||||||
|  |       expect(fromTimestamp('170122735199584').toString()).toBe(new Date(0).toString()); | ||||||
|  |       expect(fromTimestamp('17012273519958').toString()).toBe(new Date(0).toString()); | ||||||
|  |     }); | ||||||
|   }); |   }); | ||||||
| 
 | 
 | ||||||
|   describe('isUTCDateString', () => { |   describe('isUTCDateString', () => { | ||||||
| @ -177,4 +221,36 @@ describe('date-time-converter models', () => { | |||||||
|       expect(excelFormatToDate('-1000')).toEqual(new Date('1897-04-04T00:00:00.000Z')); |       expect(excelFormatToDate('-1000')).toEqual(new Date('1897-04-04T00:00:00.000Z')); | ||||||
|     }); |     }); | ||||||
|   }); |   }); | ||||||
|  | 
 | ||||||
|  |   describe('isJSDate', () => { | ||||||
|  |     test('a JS date is a new Date()', () => { | ||||||
|  |       expect(isJSDate('new Date(2000, 0)')).toBe(true); | ||||||
|  |       expect(isJSDate('new Date(2000, 0, 1, 12, 12)')).toBe(true); | ||||||
|  |       expect(isJSDate('new Date(2000, 0, 1, 12, 12, 12)')).toBe(true); | ||||||
|  |       expect(isJSDate('new Date(2000, 0, 1, 12, 12, 12, 1)')).toBe(true); | ||||||
|  | 
 | ||||||
|  |       expect(isJSDate('new Date(2000)')).toBe(false); | ||||||
|  |       expect(isJSDate('')).toBe(false); | ||||||
|  |       expect(isJSDate('foo')).toBe(false); | ||||||
|  |       expect(isJSDate('1.1.1')).toBe(false); | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   describe('fromJSDate', () => { | ||||||
|  |     test('convert a JS new Date() to date', () => { | ||||||
|  |       expect(fromJSDate('new Date(2000, 0)')).toEqual(new Date(2000, 0)); | ||||||
|  |       expect(fromJSDate('new Date(2000, 0, 1, 12, 12)')).toEqual(new Date(2000, 0, 1, 12, 12)); | ||||||
|  |       expect(fromJSDate('new Date(2000, 0, 1, 12, 12, 12)')).toEqual(new Date(2000, 0, 1, 12, 12, 12)); | ||||||
|  |       expect(fromJSDate('new Date(2000, 0, 1, 12, 12, 12, 1)')).toEqual(new Date(2000, 0, 1, 12, 12, 12, 1)); | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   describe('toJSDate', () => { | ||||||
|  |     test('convert a date to JS new Date()', () => { | ||||||
|  |       expect(toJSDate(new Date(2000, 0))).toEqual('new Date(2000, 0, 1, 0, 0, 0, 0);'); | ||||||
|  |       expect(toJSDate(new Date(2000, 0, 1, 12, 12))).toEqual('new Date(2000, 0, 1, 12, 12, 0, 0);'); | ||||||
|  |       expect(toJSDate(new Date(2000, 0, 1, 12, 12, 12))).toEqual('new Date(2000, 0, 1, 12, 12, 12, 0);'); | ||||||
|  |       expect(toJSDate(new Date(2000, 0, 1, 12, 12, 12, 1))).toEqual('new Date(2000, 0, 1, 12, 12, 12, 1);'); | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
| }); | }); | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| import _ from 'lodash'; | import _ from 'lodash'; | ||||||
|  | import { addMilliseconds } from 'date-fns'; | ||||||
| 
 | 
 | ||||||
| export { | export { | ||||||
|   isISO8601DateTimeString, |   isISO8601DateTimeString, | ||||||
| @ -12,6 +13,11 @@ export { | |||||||
|   dateToExcelFormat, |   dateToExcelFormat, | ||||||
|   excelFormatToDate, |   excelFormatToDate, | ||||||
|   isExcelFormat, |   isExcelFormat, | ||||||
|  |   fromTimestamp, | ||||||
|  |   isTimestampMicroSeconds, | ||||||
|  |   isJSDate, | ||||||
|  |   fromJSDate, | ||||||
|  |   toJSDate, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const ISO8601_REGEX | const ISO8601_REGEX | ||||||
| @ -26,6 +32,8 @@ const RFC7231_REGEX = /^[A-Za-z]{3},\s[0-9]{2}\s[A-Za-z]{3}\s[0-9]{4}\s[0-9]{2}: | |||||||
| 
 | 
 | ||||||
| const EXCEL_FORMAT_REGEX = /^-?\d+(\.\d+)?$/; | const EXCEL_FORMAT_REGEX = /^-?\d+(\.\d+)?$/; | ||||||
| 
 | 
 | ||||||
|  | const JS_DATE_REGEX = /^new\s+Date\(\s*(?:(\d+)\s*,\s*)(?:(\d|11)\s*,\s*(?:(\d+)\s*,\s*(?:(\d+)\s*,\s*(?:(\d+)\s*,\s*(?:(\d+)\s*,\s*)?)?)?)?)?(\d+)\)\s*;?$/; | ||||||
|  | 
 | ||||||
| function createRegexMatcher(regex: RegExp) { | function createRegexMatcher(regex: RegExp) { | ||||||
|   return (date?: string) => !_.isNil(date) && regex.test(date); |   return (date?: string) => !_.isNil(date) && regex.test(date); | ||||||
| } | } | ||||||
| @ -35,9 +43,19 @@ const isISO9075DateString = createRegexMatcher(ISO9075_REGEX); | |||||||
| const isRFC3339DateString = createRegexMatcher(RFC3339_REGEX); | const isRFC3339DateString = createRegexMatcher(RFC3339_REGEX); | ||||||
| const isRFC7231DateString = createRegexMatcher(RFC7231_REGEX); | const isRFC7231DateString = createRegexMatcher(RFC7231_REGEX); | ||||||
| const isUnixTimestamp = createRegexMatcher(/^[0-9]{1,10}$/); | const isUnixTimestamp = createRegexMatcher(/^[0-9]{1,10}$/); | ||||||
| const isTimestamp = createRegexMatcher(/^[0-9]{1,13}$/); | const isTimestamp = createRegexMatcher(/^([0-9]{1,13}|[0-9]{16})$/); | ||||||
|  | const isTimestampMilliSeconds = createRegexMatcher(/^[0-9]{1,13}$/); | ||||||
|  | const isTimestampMicroSeconds = createRegexMatcher(/^[0-9]{16}$/); | ||||||
| const isMongoObjectId = createRegexMatcher(/^[0-9a-fA-F]{24}$/); | const isMongoObjectId = createRegexMatcher(/^[0-9a-fA-F]{24}$/); | ||||||
| 
 | 
 | ||||||
|  | const isJSDate = createRegexMatcher(JS_DATE_REGEX); | ||||||
|  | function fromJSDate(date: string): Date { | ||||||
|  |   const res = JS_DATE_REGEX.exec(date); | ||||||
|  |   const parts = (res || []).filter(p => p !== undefined).map(p => Number.parseInt(p, 10)).slice(1); | ||||||
|  |   return new (Function.prototype.bind.apply(Date, [null, ...parts]))(); | ||||||
|  | } | ||||||
|  | const toJSDate = (date: Date) => `new Date(${date.getFullYear()}, ${date.getMonth()}, ${date.getDate()}, ${date.getHours()}, ${date.getMinutes()}, ${date.getSeconds()}, ${date.getMilliseconds()});`; | ||||||
|  | 
 | ||||||
| const isExcelFormat = createRegexMatcher(EXCEL_FORMAT_REGEX); | const isExcelFormat = createRegexMatcher(EXCEL_FORMAT_REGEX); | ||||||
| 
 | 
 | ||||||
| function isUTCDateString(date?: string) { | function isUTCDateString(date?: string) { | ||||||
| @ -60,3 +78,14 @@ function dateToExcelFormat(date: Date) { | |||||||
| function excelFormatToDate(excelFormat: string | number) { | function excelFormatToDate(excelFormat: string | number) { | ||||||
|   return new Date((Number(excelFormat) - 25569) * 86400 * 1000); |   return new Date((Number(excelFormat) - 25569) * 86400 * 1000); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | function fromTimestamp(timestamp: string, type: 'auto' | 'milliseconds' | 'microseconds' = 'auto') { | ||||||
|  |   let milliSeconds = 0; | ||||||
|  |   if (type === 'microseconds' || isTimestampMicroSeconds(timestamp)) { | ||||||
|  |     milliSeconds = Number(timestamp) / 1000; | ||||||
|  |   } | ||||||
|  |   else if (type === 'milliseconds' || isTimestampMilliSeconds(timestamp)) { | ||||||
|  |     milliSeconds = Number(timestamp); | ||||||
|  |   } | ||||||
|  |   return addMilliseconds(new Date(0), milliSeconds); | ||||||
|  | } | ||||||
|  | |||||||
| @ -10,21 +10,25 @@ import { | |||||||
|   isDate, |   isDate, | ||||||
|   isValid, |   isValid, | ||||||
|   parseISO, |   parseISO, | ||||||
|   parseJSON, |  | ||||||
| } from 'date-fns'; | } from 'date-fns'; | ||||||
|  | import { UTCDate } from '@date-fns/utc'; | ||||||
| import type { DateFormat, ToDateMapper } from './date-time-converter.types'; | import type { DateFormat, ToDateMapper } from './date-time-converter.types'; | ||||||
| import { | import { | ||||||
|   dateToExcelFormat, |   dateToExcelFormat, | ||||||
|   excelFormatToDate, |   excelFormatToDate, | ||||||
|  |   fromJSDate, | ||||||
|  |   fromTimestamp, | ||||||
|   isExcelFormat, |   isExcelFormat, | ||||||
|   isISO8601DateTimeString, |   isISO8601DateTimeString, | ||||||
|   isISO9075DateString, |   isISO9075DateString, | ||||||
|  |   isJSDate, | ||||||
|   isMongoObjectId, |   isMongoObjectId, | ||||||
|   isRFC3339DateString, |   isRFC3339DateString, | ||||||
|   isRFC7231DateString, |   isRFC7231DateString, | ||||||
|   isTimestamp, |   isTimestamp, | ||||||
|   isUTCDateString, |   isUTCDateString, | ||||||
|   isUnixTimestamp, |   isUnixTimestamp, | ||||||
|  |   toJSDate, | ||||||
| } from './date-time-converter.models'; | } from './date-time-converter.models'; | ||||||
| import { withDefaultOnError } from '@/utils/defaults'; | import { withDefaultOnError } from '@/utils/defaults'; | ||||||
| import { useValidation } from '@/composable/validation'; | import { useValidation } from '@/composable/validation'; | ||||||
| @ -46,6 +50,12 @@ const formats: DateFormat[] = [ | |||||||
|     toDate: parseISO, |     toDate: parseISO, | ||||||
|     formatMatcher: date => isISO8601DateTimeString(date), |     formatMatcher: date => isISO8601DateTimeString(date), | ||||||
|   }, |   }, | ||||||
|  |   { | ||||||
|  |     name: 'ISO 8601 UTC', | ||||||
|  |     fromDate: date => (new UTCDate(date)).toISOString(), | ||||||
|  |     toDate: parseISO, | ||||||
|  |     formatMatcher: date => isISO8601DateTimeString(date), | ||||||
|  |   }, | ||||||
|   { |   { | ||||||
|     name: 'ISO 9075', |     name: 'ISO 9075', | ||||||
|     fromDate: formatISO9075, |     fromDate: formatISO9075, | ||||||
| @ -73,7 +83,7 @@ const formats: DateFormat[] = [ | |||||||
|   { |   { | ||||||
|     name: 'Timestamp', |     name: 'Timestamp', | ||||||
|     fromDate: date => String(getTime(date)), |     fromDate: date => String(getTime(date)), | ||||||
|     toDate: ms => parseJSON(+ms), |     toDate: ms => fromTimestamp(ms), | ||||||
|     formatMatcher: date => isTimestamp(date), |     formatMatcher: date => isTimestamp(date), | ||||||
|   }, |   }, | ||||||
|   { |   { | ||||||
| @ -94,6 +104,12 @@ const formats: DateFormat[] = [ | |||||||
|     toDate: excelFormatToDate, |     toDate: excelFormatToDate, | ||||||
|     formatMatcher: isExcelFormat, |     formatMatcher: isExcelFormat, | ||||||
|   }, |   }, | ||||||
|  |   { | ||||||
|  |     name: 'JS Date', | ||||||
|  |     fromDate: date => toJSDate(date), | ||||||
|  |     toDate: date => fromJSDate(date), | ||||||
|  |     formatMatcher: isJSDate, | ||||||
|  |   }, | ||||||
| ]; | ]; | ||||||
| 
 | 
 | ||||||
| const formatIndex = ref(6); | const formatIndex = ref(6); | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user