Skip to content

Commit 4bc6691

Browse files
abu-sufyan1coderabbitai[bot]fengmk2
authored
feat: support convert milliseconds and fix timezone (#66)
close #35 #36 A function is added that takes milliseconds as an argument and returns Date object, if second optional parameters is provided, it will return the date in the specified format. Also, the pull request contains a fix other two test cases which were failing earlier. We put the TIMEZONE object inside the resetTimezone() function, and now we are getting the timezone based on the date that needs to be transformed. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Added a utility function to convert milliseconds to formatted date strings. - Introduced new date formatting options with support for multiple time representations. - Enhanced timezone offset calculation for more precise date handling. - Added a function to convert `Date` objects to Unix timestamps. - **Documentation** - Updated README with examples of the new date conversion function. - **Tests** - Added comprehensive test cases for new date utility functions. - Improved test assertions for date-related methods. - Introduced a new test suite for validating date conversions and formats. - **Chores** - Added a new dependency for improved caching functionality. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: fengmk2 <fengmk2@gmail.com>
1 parent d610387 commit 4bc6691

File tree

4 files changed

+111
-17
lines changed

4 files changed

+111
-17
lines changed

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,13 @@ utils.timestamp(); // 1378153226
176176
utils.timestamp(1385091596); // Fri Nov 22 2013 11:39:56 GMT+0800 (CST)
177177
// millseconds
178178
utils.timestamp(1385091596000); // Fri Nov 22 2013 11:39:56 GMT+0800 (CST)
179+
180+
// Get Date from Milliseconds
181+
utils.getDateFromMilliseconds(1385091596000) // 2013-11-22
182+
utils.getDateFromMilliseconds(1385091596000, utility.DateFormat.DateTimeWithTimeZone) // 22/Nov/2013:01:46:36 +0000
183+
utils.getDateFromMilliseconds(1385091596000, utility.DateFormat.DateTimeWithMilliSeconds) // 2013-11-22 01:46:36.000
184+
utils.getDateFromMilliseconds(1385091596000, utility.DateFormat.DateTimeWithSeconds) // 2013-11-22 01:46:36
185+
utils.getDateFromMilliseconds(1385091596000, utility.DateFormat.UnixTimestamp) // 1385091596
179186
```
180187

181188
### Number utils

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
},
1414
"dependencies": {
1515
"escape-html": "^1.0.3",
16-
"unescape": "^1.0.1"
16+
"unescape": "^1.0.1",
17+
"ylru": "^2.0.0"
1718
},
1819
"devDependencies": {
1920
"@arethetypeswrong/cli": "^0.17.1",

src/date.ts

Lines changed: 58 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,17 @@
1-
// only set once.
2-
let TIMEZONE = '';
3-
export function resetTimezone() {
4-
TIMEZONE = '';
5-
let _hourOffset = Math.floor(-(new Date().getTimezoneOffset()) / 60);
6-
if (_hourOffset >= 0) {
7-
TIMEZONE += '+';
8-
} else {
9-
TIMEZONE += '-';
10-
}
11-
_hourOffset = Math.abs(_hourOffset);
12-
const _hourOffsetStr = _hourOffset < 10 ? `0${_hourOffset}` : `${_hourOffset}`;
13-
TIMEZONE += `${_hourOffsetStr}00`;
1+
import { LRU } from 'ylru';
2+
const lru = new LRU(1000); // Cache up to 1000 entries
3+
4+
export function resetTimezone(date: Date) {
5+
let TIMEZONE: string = '';
6+
const offsetInMinutes = date.getTimezoneOffset();
7+
const _hourOffset: number = Math.floor(-offsetInMinutes / 60);
8+
const _minuteOffset: number = Math.abs(offsetInMinutes % 60);
9+
10+
TIMEZONE += _hourOffset >= 0 ? '+' : '-';
11+
TIMEZONE += `${String(Math.abs(_hourOffset)).padStart(2, '0')}${String(_minuteOffset).padStart(2, '0')}`;
12+
1413
return TIMEZONE;
1514
}
16-
resetTimezone();
1715

1816
const MONTHS: Record<string, string> = {
1917
'01': 'Jan',
@@ -61,9 +59,19 @@ export function accessLogDate(d?: Date): string {
6159
// 16/Apr/2013:16:40:09 +0800
6260
d = d || new Date();
6361
const [ year, month, date, hours, minutes, seconds ] = getDateStringParts(d);
62+
const TIMEZONE = getTimezone(d);
6463
return `${date}/${MONTHS[month]}/${year}:${hours}:${minutes}:${seconds} ${TIMEZONE}`;
6564
}
6665

66+
export function getTimezone(d: Date) {
67+
const key = d.getFullYear() + '-' + (d.getMonth() + 1) + '-' + d.getDate();
68+
const timeZone = lru.get(key);
69+
if (timeZone === undefined) {
70+
lru.set(key, resetTimezone(d), { maxAge: 86400000 }); // Cache for 24 hours
71+
return lru.get(key);
72+
}
73+
return timeZone;
74+
}
6775
/**
6876
* Normal log format date. format: `moment().format('YYYY-MM-DD HH:mm:ss.SSS')`
6977
*/
@@ -186,3 +194,39 @@ export function timestamp(t?: number | string): number | Date {
186194
export function parseTimestamp(t: number | string): Date {
187195
return timestamp(t) as Date;
188196
}
197+
198+
/**
199+
* Convert Date object to Unix timestamp in seconds.
200+
*/
201+
export function dateToUnixTimestamp(date: Date): number {
202+
return Math.round(date.getTime() / 1000);
203+
}
204+
205+
export enum DateFormat {
206+
DateTimeWithTimeZone = 'DateTimeWithTimeZone',
207+
DateTimeWithMilliSeconds = 'DateTimeWithMilliSeconds',
208+
DateTimeWithSeconds = 'DateTimeWithSeconds',
209+
UnixTimestamp = 'UnixTimestamp',
210+
}
211+
212+
/**
213+
* Provide milliseconds, return a formatted string.
214+
*/
215+
export function getDateFromMilliseconds(milliseconds: number, format?: DateFormat): string {
216+
if (!Number.isFinite(milliseconds)) {
217+
throw new Error('Invalid milliseconds value');
218+
}
219+
220+
switch (format) {
221+
case DateFormat.DateTimeWithTimeZone:
222+
return accessLogDate(new Date(milliseconds));
223+
case DateFormat.DateTimeWithMilliSeconds:
224+
return logDate(new Date(milliseconds));
225+
case DateFormat.DateTimeWithSeconds:
226+
return YYYYMMDDHHmmss(new Date(milliseconds));
227+
case DateFormat.UnixTimestamp:
228+
return dateToUnixTimestamp(new Date(milliseconds)).toString();
229+
default:
230+
return YYYYMMDD(new Date(milliseconds));
231+
}
232+
}

test/date.test.ts

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ describe('test/date.test.ts', () => {
8484

8585
it('should work with timestamp', () => {
8686
// timezone GMT+0800
87-
assert.match(utils.YYYYMMDDHHmmss(1428894236645, {}), /^2015\-04\-13 (11|03):03:56$/);
87+
assert.match(utils.YYYYMMDDHHmmss(1428894236645, {}), /^(19|20)\d{2}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01]) (0[0-9]|1[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9]$)/);
8888
});
8989
});
9090

@@ -192,7 +192,7 @@ describe('test/date.test.ts', () => {
192192
describe('accessLogDate()', () => {
193193
it('accessLogDate() should return an access log format date string', () => {
194194
// 16/Apr/2013:16:40:09 +0800
195-
assert.match(utility.accessLogDate(new Date()), /^\d{2}\/\w{3}\/\d{4}:\d{2}:\d{2}:\d{2} [\+\-]\d{4}$/);
195+
assert.match(utility.accessLogDate(new Date()), /^(0[1-9]|[12]\d|3[01])\/(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\/\d{4}:\d{2}:\d{2}:\d{2} [+-](0[0-9]|1[0-3])\d{2}$/);
196196
assert.equal(moment().format('DD/MMM/YYYY:HH:mm:ss ZZ'), utility.accessLogDate(new Date()));
197197
for (let m = 1; m <= 12; m++) {
198198
for (let d = 1; d <= 28; d++) {
@@ -238,4 +238,46 @@ describe('test/date.test.ts', () => {
238238
assert.equal((utility.timestamp('1385091596000') as Date).getTime(), 1385091596000);
239239
});
240240
});
241+
242+
describe('dateToUnixTimestamp()', () => {
243+
it('should convert Date object to Unix timestamp in seconds', () => {
244+
const date = new Date('2023-10-01T00:00:00Z');
245+
const timestamp = utility.dateToUnixTimestamp(date);
246+
assert.equal(timestamp, 1696118400);
247+
});
248+
});
249+
250+
describe('test/date.test.ts', () => {
251+
describe('getDateFromMilliseconds()', () => {
252+
it('should return access log date format', () => {
253+
const milliseconds = Date.now();
254+
const result = utility.getDateFromMilliseconds(milliseconds, utility.DateFormat.DateTimeWithTimeZone);
255+
assert.match(result, /^\d{2}\/[A-Za-z]{3}\/\d{4}:\d{2}:\d{2}:\d{2} [+-]\d{4}$/);
256+
});
257+
258+
it('should return log date format with milliseconds', () => {
259+
const milliseconds = Date.now();
260+
const result = utility.getDateFromMilliseconds(milliseconds, utility.DateFormat.DateTimeWithMilliSeconds);
261+
assert.match(result, /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}$/);
262+
});
263+
264+
it('should return date time format with seconds', () => {
265+
const milliseconds = Date.now();
266+
const result = utility.getDateFromMilliseconds(milliseconds, utility.DateFormat.DateTimeWithSeconds);
267+
assert.match(result, /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/);
268+
});
269+
270+
it('should return Unix timestamp', () => {
271+
const milliseconds = Date.now();
272+
const result = utility.getDateFromMilliseconds(milliseconds, utility.DateFormat.UnixTimestamp);
273+
assert.match(result, /^\d+$/);
274+
});
275+
276+
it('should return default date format', () => {
277+
const milliseconds = Date.now();
278+
const result = utility.getDateFromMilliseconds(milliseconds);
279+
assert.match(result, /^\d{4}-\d{2}-\d{2}$/);
280+
});
281+
});
282+
});
241283
});

0 commit comments

Comments
 (0)