@megaorm/zone
Version:
This package is designed to convert UTC datetimes to a specific timezone and helps format and display them as you like.
142 lines • 5.8 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Zone = exports.ZoneError = void 0;
const test_1 = require("@megaorm/test");
/**
* Formats a Date object as a string in the format `YYYY-MM-DD hh:mm:ss`.
*
* @param date The Date object to format.
* @returns A string representing the date in the format `YYYY-MM-DD hh:mm:ss`.
*/
function formatDate(date) {
return date.toISOString().slice(0, 19).replace('T', ' ');
}
/**
* Custom error class for handling errors specific to the Zone class.
*/
class ZoneError extends Error {
}
exports.ZoneError = ZoneError;
/**
* Represents a date and time in a specific timezone, providing utilities
* for formatting and calculating time differences.
*/
class Zone {
/**
* Creates a new Zone instance based on a datetime and timezone.
*
* @param datetime The datetime string in `YYYY-MM-DD hh:mm:ss` fromat.
* @param timezone The timezone identifier (e.g., `America/New_York`).
* @throws `ZoneError` if the datetime or timezone is invalid.
*/
constructor(datetime, timezone) {
if (!(0, test_1.isDateTime)(datetime)) {
throw new ZoneError(`Invalid datetime: ${String(datetime)}`);
}
if (!(0, test_1.isFullStr)(timezone)) {
throw new ZoneError(`Invalid timezone: ${String(timezone)}`);
}
try {
// Create a UTC date object
const utcDate = new Date(datetime.concat('Z')); // The datetime is assumed to be in UTC
// Format the datetime in the specified timezone
const formatter = new Intl.DateTimeFormat('en-US', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false, // 24-hour format
timeZone: timezone,
});
// Get the local date in the target timezone
const parts = formatter.formatToParts(utcDate);
this.year = Number(parts.find((part) => part.type === 'year').value);
this.month = Number(parts.find((part) => part.type === 'month').value);
this.day = Number(parts.find((part) => part.type === 'day').value);
this.hour = Number(parts.find((part) => part.type === 'hour').value);
this.minute = Number(parts.find((part) => part.type === 'minute').value);
this.second = Number(parts.find((part) => part.type === 'second').value);
this.datetime = formatDate(new Date(Date.UTC(this.year, this.month - 1, this.day, this.hour, this.minute, this.second)));
this.date = utcDate;
this.timezone = timezone;
}
catch (error) {
throw new ZoneError(error.message);
}
}
/**
* Formats the datetime using a custom formatter function.
*
* @param formatter A function that formats datetime components into a string.
* @returns The formatted date-time string or the default datetime string.
*/
format(formatter) {
if (!(0, test_1.isFunc)(formatter))
return this.datetime;
const result = formatter(this.year, this.month, this.day, this.hour, this.minute, this.second);
return (0, test_1.isStr)(result) ? result : this.datetime;
}
/**
* Returns the date as a `YYYY-MM-DD` formatted string.
*
* @returns The date string.
*/
toDateString() {
return `${this.year}-${String(this.month).padStart(2, '0')}-${String(this.day).padStart(2, '0')}`;
}
/**
* Returns the time as a `hh:mm:ss` formatted string.
*
* @returns The time string.
*/
toTimestring() {
return `${String(this.hour).padStart(2, '0')}:${String(this.minute).padStart(2, '0')}:${String(this.second).padStart(2, '0')}`;
}
/**
* Returns the time in 12-hour AM/PM format.
*
* @returns The formatted time (e.g., `1:30 PM`).
*/
ampm() {
let hour = this.hour % 12 || 12; // Converts 0 (midnight) to 12.
const ampm = this.hour < 12 || this.hour === 24 ? 'AM' : 'PM';
return `${hour}:${String(this.minute).padStart(2, '0')} ${ampm}`;
}
/**
* Calculates the time difference between now and the Zone's date.
*
* @returns A human-readable description of the time difference (e.g., `5 minutes ago`).
*/
diff() {
const now = new Date();
const diff = now.getTime() - this.date.getTime();
if (diff < 0)
return 'Just now'; // Case where the date is in the future
const seconds = Math.floor(diff / 1000);
const minutes = Math.floor(seconds / 60);
const hours = Math.floor(minutes / 60);
const days = Math.floor(hours / 24);
const years = Math.floor(days / 365);
let months = Math.floor(now.getMonth() - this.date.getMonth());
// If the current day is earlier than the target day, subtract 1 month
if (now.getDate() < this.date.getDate())
months--;
if (years > 0)
return `${years} year${years > 1 ? 's' : ''} ago`;
if (months > 0)
return `${months} month${months > 1 ? 's' : ''} ago`;
if (days > 0)
return `${days} day${days > 1 ? 's' : ''} ago`;
if (hours > 0)
return `${hours} hour${hours > 1 ? 's' : ''} ago`;
if (minutes > 0)
return `${minutes} minute${minutes > 1 ? 's' : ''} ago`;
if (seconds > 0)
return `${seconds} second${seconds > 1 ? 's' : ''} ago`;
return 'Just now'; // Fallback when the time difference is too small
}
}
exports.Zone = Zone;
//# sourceMappingURL=index.js.map