Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,13 @@ utils.timestamp(); // 1378153226
utils.timestamp(1385091596); // Fri Nov 22 2013 11:39:56 GMT+0800 (CST)
// millseconds
utils.timestamp(1385091596000); // Fri Nov 22 2013 11:39:56 GMT+0800 (CST)

// Get Date from Milliseconds
utils.getDateFromMilliseconds(1385091596000) // 2013-11-22
utils.getDateFromMilliseconds(1385091596000, utility.DateFormat.DateTimeWithTimeZone) // 22/Nov/2013:01:46:36 +0000
utils.getDateFromMilliseconds(1385091596000, utility.DateFormat.DateTimeWithMilliSeconds) // 2013-11-22 01:46:36.000
utils.getDateFromMilliseconds(1385091596000, utility.DateFormat.DateTimeWithSeconds) // 2013-11-22 01:46:36
utils.getDateFromMilliseconds(1385091596000, utility.DateFormat.UnixTimestamp) // 1385091596
```

### Number utils
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
},
"dependencies": {
"escape-html": "^1.0.3",
"unescape": "^1.0.1"
"unescape": "^1.0.1",
"ylru": "^2.0.0"
},
"devDependencies": {
"@arethetypeswrong/cli": "^0.17.1",
Expand Down
72 changes: 58 additions & 14 deletions src/date.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
// only set once.
let TIMEZONE = '';
export function resetTimezone() {
TIMEZONE = '';
let _hourOffset = Math.floor(-(new Date().getTimezoneOffset()) / 60);
if (_hourOffset >= 0) {
TIMEZONE += '+';
} else {
TIMEZONE += '-';
}
_hourOffset = Math.abs(_hourOffset);
const _hourOffsetStr = _hourOffset < 10 ? `0${_hourOffset}` : `${_hourOffset}`;
TIMEZONE += `${_hourOffsetStr}00`;
import { LRU } from 'ylru';
const lru = new LRU(1000); // Cache up to 1000 entries

export function resetTimezone(date: Date) {
let TIMEZONE: string = '';
const offsetInMinutes = date.getTimezoneOffset();
const _hourOffset: number = Math.floor(-offsetInMinutes / 60);
const _minuteOffset: number = Math.abs(offsetInMinutes % 60);

TIMEZONE += _hourOffset >= 0 ? '+' : '-';
TIMEZONE += `${String(Math.abs(_hourOffset)).padStart(2, '0')}${String(_minuteOffset).padStart(2, '0')}`;

return TIMEZONE;
}
resetTimezone();

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

export function getTimezone(d: Date) {
const key = d.getFullYear() + '-' + (d.getMonth() + 1) + '-' + d.getDate();
const timeZone = lru.get(key);
if (timeZone === undefined) {
lru.set(key, resetTimezone(d), { maxAge: 86400000 }); // Cache for 24 hours
return lru.get(key);
}
return timeZone;
}
/**
* Normal log format date. format: `moment().format('YYYY-MM-DD HH:mm:ss.SSS')`
*/
Expand Down Expand Up @@ -186,3 +194,39 @@ export function timestamp(t?: number | string): number | Date {
export function parseTimestamp(t: number | string): Date {
return timestamp(t) as Date;
}

/**
* Convert Date object to Unix timestamp in seconds.
*/
export function dateToUnixTimestamp(date: Date): number {
return Math.round(date.getTime() / 1000);
}

export enum DateFormat {
DateTimeWithTimeZone,
DateTimeWithMilliSeconds,
DateTimeWithSeconds,
UnixTimestamp
}

/**
* Provide milliseconds, return a formatted string.
*/
export function getDateFromMilliseconds(milliseconds: number, format?: DateFormat): string {
if (!Number.isFinite(milliseconds)) {
throw new Error('Invalid milliseconds value');
}

switch (format) {
case DateFormat.DateTimeWithTimeZone:
return accessLogDate(new Date(milliseconds));
case DateFormat.DateTimeWithMilliSeconds:
return logDate(new Date(milliseconds));
case DateFormat.DateTimeWithSeconds:
return YYYYMMDDHHmmss(new Date(milliseconds));
case DateFormat.UnixTimestamp:
return dateToUnixTimestamp(new Date(milliseconds)).toString();
default:
return YYYYMMDD(new Date(milliseconds));
}
}
46 changes: 44 additions & 2 deletions test/date.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ describe('test/date.test.ts', () => {

it('should work with timestamp', () => {
// timezone GMT+0800
assert.match(utils.YYYYMMDDHHmmss(1428894236645, {}), /^2015\-04\-13 (11|03):03:56$/);
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]$)/);
});
});

Expand Down Expand Up @@ -192,7 +192,7 @@ describe('test/date.test.ts', () => {
describe('accessLogDate()', () => {
it('accessLogDate() should return an access log format date string', () => {
// 16/Apr/2013:16:40:09 +0800
assert.match(utility.accessLogDate(new Date()), /^\d{2}\/\w{3}\/\d{4}:\d{2}:\d{2}:\d{2} [\+\-]\d{4}$/);
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}$/);
assert.equal(moment().format('DD/MMM/YYYY:HH:mm:ss ZZ'), utility.accessLogDate(new Date()));
for (let m = 1; m <= 12; m++) {
for (let d = 1; d <= 28; d++) {
Expand Down Expand Up @@ -238,4 +238,46 @@ describe('test/date.test.ts', () => {
assert.equal((utility.timestamp('1385091596000') as Date).getTime(), 1385091596000);
});
});

describe('dateToUnixTimestamp()', () => {
it('should convert Date object to Unix timestamp in seconds', () => {
const date = new Date('2023-10-01T00:00:00Z');
const timestamp = utility.dateToUnixTimestamp(date);
assert.equal(timestamp, 1696118400);
});
});

describe('test/date.test.ts', () => {
describe('getDateFromMilliseconds()', () => {
it('should return access log date format', () => {
const milliseconds = Date.now();
const result = utility.getDateFromMilliseconds(milliseconds, utility.DateFormat.DateTimeWithTimeZone);
assert.match(result, /^\d{2}\/[A-Za-z]{3}\/\d{4}:\d{2}:\d{2}:\d{2} [+-]\d{4}$/);
});

it('should return log date format with milliseconds', () => {
const milliseconds = Date.now();
const result = utility.getDateFromMilliseconds(milliseconds, utility.DateFormat.DateTimeWithMilliSeconds);
assert.match(result, /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}$/);
});

it('should return date time format with seconds', () => {
const milliseconds = Date.now();
const result = utility.getDateFromMilliseconds(milliseconds, utility.DateFormat.DateTimeWithSeconds);
assert.match(result, /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/);
});

it('should return Unix timestamp', () => {
const milliseconds = Date.now();
const result = utility.getDateFromMilliseconds(milliseconds, utility.DateFormat.UnixTimestamp);
assert.match(result, /^\d+$/);
});

it('should return default date format', () => {
const milliseconds = Date.now();
const result = utility.getDateFromMilliseconds(milliseconds);
assert.match(result, /^\d{4}-\d{2}-\d{2}$/);
});
});
});
});
Loading