Format dates with moment

This commit is contained in:
Daniel Odendahl Jr
2018-09-20 16:38:05 +00:00
parent 553abdb6fa
commit 42bd597db7
26 changed files with 81 additions and 51 deletions
+5 -3
View File
@@ -1,4 +1,6 @@
const Command = require('../../structures/Command');
const moment = require('moment');
require('moment-duration-format');
module.exports = class DaysUntilCommand extends Command {
constructor(client) {
@@ -29,8 +31,8 @@ module.exports = class DaysUntilCommand extends Command {
let year = now.getMonth() + 1 <= month ? now.getFullYear() : now.getFullYear() + 1;
if (month === now.getMonth() + 1 && now.getDate() >= day) ++year;
const future = new Date(`${month}/${day}/${year}`);
const time = Math.round((future - now) / (1000 * 60 * 60 * 24)) + 1;
if (!time) return msg.reply('Invalid date.');
return msg.say(`There are ${time} days until ${future.toDateString()}!`);
const time = moment.duration(future - now).format('M [months and] d [days]');
if (time === 'Invalid date') return msg.reply('Invalid date.');
return msg.say(`There are ${time} until ${moment.utc(future).format('dddd, MMMM Do, YYYY')}!`);
}
};
+2 -1
View File
@@ -1,5 +1,6 @@
const Command = require('../../structures/Command');
const request = require('node-superfetch');
const moment = require('moment');
module.exports = class GoogleDoodleCommand extends Command {
constructor(client) {
@@ -35,7 +36,7 @@ module.exports = class GoogleDoodleCommand extends Command {
const { body } = await request.get(`https://www.google.com/doodles/json/${year}/${month}`);
if (!body.length) return msg.say('Could not find any results.');
const data = body[latest ? 0 : Math.floor(Math.random() * body.length)];
const runDate = new Date(data.run_date_array.join('-')).toDateString();
const runDate = moment.utc(new Date(data.run_date_array.join('-'))).format('MMMM Do, YYYY');
return msg.say(`${runDate}: ${data.share_text}`, { files: [`https:${data.url}`] });
} catch (err) {
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
+4 -2
View File
@@ -1,7 +1,9 @@
const Command = require('../../structures/Command');
const request = require('node-superfetch');
const { stripIndents } = require('common-tags');
const { list, duration, tomorrow } = require('../../util/Util');
const moment = require('moment');
require('moment-duration-format');
const { list, tomorrow } = require('../../util/Util');
const { GOLD_FISH_EMOJI_ID, SILVER_FISH_EMOJI_ID } = process.env;
const locales = ['en', 'jp'];
@@ -31,7 +33,7 @@ module.exports = class NekoAtsumePasswordCommand extends Command {
const data = await this.fetchPassword(locale);
return msg.say(stripIndents`
The current Neko Atsume password is **${data.password}**.
It will expire in **${duration(data.expires - data.date)}**.
It will expire in **${moment.duration(data.expires - data.date).format('hh:mm:ss')}**.
${data.gold} ${this.goldFish} ${data.silver} ${this.silverFish}
`);
+2 -1
View File
@@ -1,4 +1,5 @@
const Command = require('../../structures/Command');
const moment = require('moment-timezone');
const { firstUpperCase } = require('../../util/Util');
module.exports = class TimeCommand extends Command {
@@ -29,7 +30,7 @@ module.exports = class TimeCommand extends Command {
neopia = true;
}
try {
const time = new Date().toLocaleTimeString('en-US', { timeZone });
const time = moment().tz(timeZone).format('hh:mm:ss A');
const location = neopia ? ['neopia'] : timeZone.split('/');
const main = firstUpperCase(location[0], /[_ ]/);
const sub = location[1] ? firstUpperCase(location[1], /[_ ]/) : null;
+2 -1
View File
@@ -1,4 +1,5 @@
const Command = require('../../structures/Command');
const moment = require('moment');
const { MessageEmbed } = require('discord.js');
const types = {
dm: 'DM',
@@ -37,7 +38,7 @@ module.exports = class ChannelInfoCommand extends Command {
.addField(' NSFW', channel.nsfw ? 'Yes' : 'No', true)
.addField(' Category', channel.parent ? channel.parent.name : 'None', true)
.addField(' Type', types[channel.type], true)
.addField(' Creation Date', channel.createdAt.toDateString(), true)
.addField(' Creation Date', moment.utc(channel.createdAt).format('MMM Do, YYYY [at] hh:mm:ss A'), true)
.addField(' Topic', channel.topic || 'None');
return msg.embed(embed);
}
+2 -1
View File
@@ -1,4 +1,5 @@
const Command = require('../../structures/Command');
const moment = require('moment');
const { MessageEmbed } = require('discord.js');
module.exports = class EmojiInfoCommand extends Command {
@@ -27,7 +28,7 @@ module.exports = class EmojiInfoCommand extends Command {
.setThumbnail(emoji.url)
.addField(' Name', emoji.name, true)
.addField(' ID', emoji.id, true)
.addField(' Creation Date', emoji.createdAt.toDateString(), true)
.addField(' Creation Date', moment.utc(emoji.createdAt).format('MMM Do, YYYY [at] hh:mm:ss A'), true)
.addField(' Animated?', emoji.animated ? 'Yes' : 'No', true);
return msg.embed(embed);
}
+2 -1
View File
@@ -1,4 +1,5 @@
const Command = require('../../structures/Command');
const moment = require('moment');
const { MessageEmbed } = require('discord.js');
const { util: { permissions } } = require('discord.js-commando');
@@ -30,7 +31,7 @@ module.exports = class RoleInfoCommand extends Command {
.addField(' Name', role.name, true)
.addField(' ID', role.id, true)
.addField(' Color', role.hexColor.toUpperCase(), true)
.addField(' Creation Date', role.createdAt.toDateString(), true)
.addField(' Creation Date', moment.utc(role.createdAt).format('MMM Do, YYYY [at] hh:mm:ss A'), true)
.addField(' Hoisted?', role.hoist ? 'Yes' : 'No', true)
.addField(' Mentionable?', role.mentionable ? 'Yes' : 'No', true)
.addField(' Permissions', perms.map(perm => permissions[perm]).join(', ') || 'None');
+2 -1
View File
@@ -1,4 +1,5 @@
const Command = require('../../structures/Command');
const moment = require('moment');
const { MessageEmbed } = require('discord.js');
const filterLevels = ['Off', 'No Role', 'Everyone'];
const verificationLevels = ['None', 'Low', 'Medium', '(╯°□°)╯︵ ┻━┻', '┻━┻ ミヽ(ಠ益ಠ)ノ彡┻━┻'];
@@ -24,7 +25,7 @@ module.exports = class ServerInfoCommand extends Command {
.addField(' Name', msg.guild.name, true)
.addField(' ID', msg.guild.id, true)
.addField(' Region', msg.guild.region.toUpperCase(), true)
.addField(' Creation Date', msg.guild.createdAt.toDateString(), true)
.addField(' Creation Date', moment.utc(msg.guild.createdAt).format('MMM Do, YYYY [at] hh:mm:ss A'), true)
.addField(' Explicit Filter', filterLevels[msg.guild.explicitContentFilter], true)
.addField(' Verification Level', verificationLevels[msg.guild.verificationLevel], true)
.addField(' Owner', msg.guild.owner.user.tag, true)
+3 -2
View File
@@ -1,4 +1,5 @@
const Command = require('../../structures/Command');
const moment = require('moment');
const { MessageEmbed } = require('discord.js');
const { trimArray } = require('../../util/Util');
const activities = {
@@ -33,7 +34,7 @@ module.exports = class UserInfoCommand extends Command {
.setThumbnail(user.displayAvatarURL())
.addField(' Name', user.tag, true)
.addField(' ID', user.id, true)
.addField(' Discord Join Date', user.createdAt.toDateString(), true)
.addField(' Discord Join Date', moment.utc(user.createdAt).format('MMM Do, YYYY [at] hh:mm:ss A'), true)
.addField(' Bot?', user.bot ? 'Yes' : 'No', true);
if (msg.channel.type === 'text') {
try {
@@ -47,7 +48,7 @@ module.exports = class UserInfoCommand extends Command {
.setDescription(member.presence.activity
? `${activities[member.presence.activity.type]} **${member.presence.activity.name}**`
: '')
.addField(' Server Join Date', member.joinedAt.toDateString(), true)
.addField(' Server Join Date', moment.utc(member.joinedAt).format('MMM Do, YYYY [at] hh:mm:ss A'), true)
.addField(' Nickname', member.nickname || 'None', true)
.addField(' Highest Role',
member.roles.highest.id === msg.guild.defaultRole.id ? 'None' : member.roles.highest.name, true)
+3 -1
View File
@@ -1,4 +1,5 @@
const Command = require('../../structures/Command');
const moment = require('moment');
const { MessageEmbed } = require('discord.js');
const request = require('node-superfetch');
const { list } = require('../../util/Util');
@@ -51,7 +52,8 @@ module.exports = class EshopCommand extends Command {
.addField(' Category', data.game_category_ref
? data.game_category_ref.length ? data.game_category_ref[0].title : data.game_category_ref.title
: '???', true)
.addField(' Release Date', data.release_date ? new Date(data.release_date).toDateString() : '???', true)
.addField(' Release Date',
data.release_date ? moment.utc(data.release_date).format('MMM Do, YYYY [at] hh:mm:ss A') : '???', true)
.addField(' Player Count', data.number_of_players || '???', true)
.addField(' DLC?', data.dlc === 'true' ? 'Yes' : 'No', true)
.addField(' Demo?', data.demo === 'true' ? 'Yes' : 'No', true)
+3 -2
View File
@@ -1,4 +1,5 @@
const Command = require('../../structures/Command');
const moment = require('moment');
const { MessageEmbed } = require('discord.js');
const request = require('node-superfetch');
const { shorten, base64 } = require('../../util/Util');
@@ -46,8 +47,8 @@ module.exports = class GithubCommand extends Command {
.addField(' Forks', body.forks, true)
.addField(' Issues', body.open_issues, true)
.addField(' Language', body.language || '???', true)
.addField(' Creation Date', new Date(body.created_at).toDateString(), true)
.addField(' Modification Date', new Date(body.updated_at).toDateString(), true);
.addField(' Creation Date', moment.utc(body.created_at).format('MMM Do, YYYY [at] hh:mm:ss A'), true)
.addField(' Modification Date', moment.utc(body.updated_at).format('MMM Do, YYYY [at] hh:mm:ss A'), true);
return msg.embed(embed);
} catch (err) {
if (err.status === 404) return msg.say('Could not find any results.');
+2 -1
View File
@@ -1,4 +1,5 @@
const Command = require('../../structures/Command');
const moment = require('moment');
const { MessageEmbed } = require('discord.js');
const request = require('node-superfetch');
@@ -51,7 +52,7 @@ module.exports = class ItunesCommand extends Command {
.setTitle(data.trackName)
.addField(' Artist', data.artistName, true)
.addField(' Album', data.collectionName, true)
.addField(' Release Date', new Date(data.releaseDate).toDateString(), true)
.addField(' Release Date', moment.utc(data.releaseDate).format('MMM Do, YYYY [at] hh:mm:ss A'), true)
.addField(' Genre', data.primaryGenreName, true);
return msg.embed(embed);
} catch (err) {
+3 -2
View File
@@ -1,4 +1,5 @@
const Command = require('../../structures/Command');
const moment = require('moment');
const { MessageEmbed } = require('discord.js');
const request = require('node-superfetch');
const { shorten } = require('../../util/Util');
@@ -43,8 +44,8 @@ module.exports = class KickstarterCommand extends Command {
.addField(' Pledged', `$${data.pledged}`, true)
.addField(' Backers', data.backers_count, true)
.addField(' Creator', data.creator.name, true)
.addField(' Creation Date', new Date(data.created_at * 1000).toDateString(), true)
.addField(' Deadline', new Date(data.deadline * 1000).toDateString(), true);
.addField(' Creation Date', moment.utc(data.created_at * 1000).format('MMM Do, YYYY [at] hh:mm:ss A'), true)
.addField(' Deadline', moment.utc(data.deadline * 1000).format('MMM Do, YYYY [at] hh:mm:ss A'), true);
return msg.embed(embed);
} catch (err) {
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
+5 -2
View File
@@ -1,4 +1,5 @@
const Command = require('../../structures/Command');
const moment = require('moment');
const { MessageEmbed } = require('discord.js');
const request = require('node-superfetch');
const { shorten } = require('../../util/Util');
@@ -39,8 +40,10 @@ module.exports = class KitsuAnimeCommand extends Command {
.setDescription(shorten(data.synopsis))
.addField(' Type', `${data.showType} - ${data.status}`, true)
.addField(' Episodes', data.episodeCount || '???', true)
.addField(' Start Date', data.startDate ? new Date(data.startDate).toDateString() : '???', true)
.addField(' End Date', data.endDate ? new Date(data.endDate).toDateString() : '???', true);
.addField(' Start Date',
data.startDate ? moment.utc(data.startDate).format('MMM Do, YYYY [at] hh:mm:ss A') : '???', true)
.addField(' End Date',
data.endDate ? moment.utc(data.endDate).format('MMM Do, YYYY [at] hh:mm:ss A') : '???', true);
return msg.embed(embed);
} catch (err) {
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
+5 -2
View File
@@ -1,4 +1,5 @@
const Command = require('../../structures/Command');
const moment = require('moment');
const { MessageEmbed } = require('discord.js');
const request = require('node-superfetch');
const { shorten } = require('../../util/Util');
@@ -39,8 +40,10 @@ module.exports = class KitsuMangaCommand extends Command {
.setDescription(shorten(data.synopsis))
.addField(' Type', `${data.subtype} - ${data.status}`, true)
.addField(' Volumes / Chapters', `${data.volumeCount || '???'} / ${data.chapterCount || '???'}`, true)
.addField(' Start Date', data.startDate ? new Date(data.startDate).toDateString() : '???', true)
.addField(' End Date', data.endDate ? new Date(data.endDate).toDateString() : '???', true);
.addField(' Start Date',
data.startDate ? moment.utc(data.startDate).format('MMM Do, YYYY [at] hh:mm:ss A') : '???', true)
.addField(' End Date',
data.endDate ? moment.utc(data.endDate).format('MMM Do, YYYY [at] hh:mm:ss A') : '???', true);
return msg.embed(embed);
} catch (err) {
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
+3 -2
View File
@@ -1,4 +1,5 @@
const Command = require('../../structures/Command');
const moment = require('moment');
const { MessageEmbed } = require('discord.js');
const request = require('node-superfetch');
const { trimArray } = require('../../util/Util');
@@ -40,8 +41,8 @@ module.exports = class NPMCommand extends Command {
.addField(' Version', body['dist-tags'].latest, true)
.addField(' License', body.license || 'None', true)
.addField(' Author', body.author ? body.author.name : '???', true)
.addField(' Creation Date', new Date(body.time.created).toDateString(), true)
.addField(' Modification Date', new Date(body.time.modified).toDateString(), true)
.addField(' Creation Date', moment.utc(body.time.created).format('MMM Do, YYYY [at] hh:mm:ss A'), true)
.addField(' Modification Date', moment.utc(body.time.modified).format('MMM Do, YYYY [at] hh:mm:ss A'), true)
.addField(' Main File', version.main || 'index.js', true)
.addField(' Dependencies', dependencies && dependencies.length ? dependencies.join(', ') : 'None')
.addField(' Maintainers', maintainers.join(', '));
+4 -2
View File
@@ -1,4 +1,5 @@
const Command = require('../../structures/Command');
const moment = require('moment');
const { MessageEmbed } = require('discord.js');
const request = require('node-superfetch');
const { STACKOVERFLOW_KEY } = process.env;
@@ -47,8 +48,9 @@ module.exports = class StackOverflowCommand extends Command {
.addField(' Asker', `[${data.owner.display_name}](${data.owner.link})`, true)
.addField(' Views', data.view_count, true)
.addField(' Score', data.score, true)
.addField(' Creation Date', new Date(data.creation_date * 1000).toDateString(), true)
.addField(' Last Activity', new Date(data.last_activity_date * 1000).toDateString(), true);
.addField(' Creation Date', moment.utc(data.creation_date * 1000).format('MMM Do, YYYY [at] hh:mm:ss A'), true)
.addField(' Last Activity',
moment.utc(data.last_activity_date * 1000).format('MMM Do, YYYY [at] hh:mm:ss A'), true);
return msg.embed(embed);
} catch (err) {
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
+3 -1
View File
@@ -1,4 +1,5 @@
const Command = require('../../structures/Command');
const moment = require('moment');
const { MessageEmbed } = require('discord.js');
const request = require('node-superfetch');
const { ALPHA_VANTAGE_KEY } = process.env;
@@ -42,7 +43,8 @@ module.exports = class StocksCommand extends Command {
.addField(' Volume', data['5. volume'], true)
.addField(' High', `$${data['2. high']}`, true)
.addField(' Low', `$${data['3. low']}`, true)
.addField(' Last Updated', new Date(body['Meta Data']['3. Last Refreshed']).toDateString(), true);
.addField(' Last Updated',
moment.utc(body['Meta Data']['3. Last Refreshed']).format('MMM Do, YYYY [at] hh:mm:ss A'), true);
return msg.embed(embed);
} catch (err) {
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
+2 -1
View File
@@ -1,4 +1,5 @@
const Command = require('../../structures/Command');
const moment = require('moment');
const { MessageEmbed } = require('discord.js');
const request = require('node-superfetch');
const { base64 } = require('../../util/Util');
@@ -53,7 +54,7 @@ module.exports = class TwitterCommand extends Command {
.addField(' Following', body.friends_count, true)
.addField(' Protected?', body.protected ? 'Yes' : 'No', true)
.addField(' Verified?', body.verified ? 'Yes' : 'No', true)
.addField(' Creation Date', new Date(body.created_at).toDateString(), true)
.addField(' Creation Date', moment.utc(body.created_at).format('MMM Do, YYYY [at] hh:mm:ss A'), true)
.addField(' Latest Tweet', latest);
return msg.embed(embed);
} catch (err) {
+2 -1
View File
@@ -1,4 +1,5 @@
const Command = require('../../structures/Command');
const moment = require('moment');
const { MessageEmbed } = require('discord.js');
const request = require('node-superfetch');
const { shorten } = require('../../util/Util');
@@ -44,7 +45,7 @@ module.exports = class VocaDBCommand extends Command {
.setDescription(data.lyrics.length ? shorten(data.lyrics[0].value) : 'No lyrics available.')
.setThumbnail(data.thumbUrl)
.addField(' Artist', data.artistString)
.addField(' Publish Date', new Date(data.publishDate).toDateString(), true);
.addField(' Publish Date', moment.utc(data.publishDate).format('MMM Do, YYYY [at] hh:mm:ss A'), true);
return msg.embed(embed);
} catch (err) {
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
+2 -1
View File
@@ -1,4 +1,5 @@
const Command = require('../../structures/Command');
const moment = require('moment');
const { MessageEmbed } = require('discord.js');
const request = require('node-superfetch');
const { shorten } = require('../../util/Util');
@@ -41,7 +42,7 @@ module.exports = class WattpadCommand extends Command {
.setTitle(data.title)
.setDescription(shorten(data.description))
.setThumbnail(data.cover)
.addField(' Creation Date', new Date(data.createDate).toDateString(), true)
.addField(' Creation Date', moment.utc(data.createDate).format('MMM Do, YYYY [at] hh:mm:ss A'), true)
.addField(' Author', data.user.name, true)
.addField(' Chapters', data.numParts, true)
.addField(' Reads', data.readCount, true)
+2 -1
View File
@@ -1,4 +1,5 @@
const Command = require('../../structures/Command');
const moment = require('moment');
const { MessageEmbed } = require('discord.js');
const request = require('node-superfetch');
const { GOOGLE_KEY } = process.env;
@@ -43,7 +44,7 @@ module.exports = class YoutubeCommand extends Command {
.setURL(`https://www.youtube.com/watch?v=${data.id.videoId}`)
.setThumbnail(data.snippet.thumbnails.default ? data.snippet.thumbnails.default.url : null)
.addField(' ID', data.id.videoId, true)
.addField(' Publish Date', new Date(data.snippet.publishedAt).toDateString(), true)
.addField(' Publish Date', moment.utc(data.snippet.publishedAt).format('MMM Do, YYYY [at] hh:mm:ss A'), true)
.addField(' Channel', data.snippet.channelTitle, true);
return msg.embed(embed);
} catch (err) {
+1 -1
View File
@@ -27,7 +27,7 @@ module.exports = class MockingCommand extends Command {
for (let i = 0; i < letters.length; i += Math.floor(Math.random() * 4)) {
letters[i] = letters[i].toUpperCase();
}
return msg.say(`${letters.join('')} <:mocking:${MOCKING_EMOJI_ID}>`);
return msg.say(`${letters.join('')}${MOCKING_EMOJI_ID ? ` <:mocking:${MOCKING_EMOJI_ID}>` : ''}`);
}
};
+12 -9
View File
@@ -1,7 +1,8 @@
const Command = require('../../structures/Command');
const { MessageEmbed } = require('discord.js');
const moment = require('moment');
require('moment-duration-format');
const { version, dependencies } = require('../../package');
const { duration } = require('../../util/Util');
const { XIAO_GITHUB_REPO_USERNAME, XIAO_GITHUB_REPO_NAME } = process.env;
const source = XIAO_GITHUB_REPO_NAME && XIAO_GITHUB_REPO_USERNAME;
@@ -29,18 +30,20 @@ module.exports = class InfoCommand extends Command {
.addField(' Source Code',
source ? `[Here](https://github.com/${XIAO_GITHUB_REPO_USERNAME}/${XIAO_GITHUB_REPO_NAME})` : 'N/A', true)
.addField(' Memory Usage', `${Math.round(process.memoryUsage().heapUsed / 1024 / 1024)}MB`, true)
.addField(' Uptime', duration(this.client.uptime), true)
.addField(' Uptime', moment.duration(this.client.uptime).format('hh:mm:ss'), true)
.addField(' Version', `v${version}`, true)
.addField(' Node Version', process.version, true)
.addField(' Dependencies', Object.entries(dependencies).map(dep => this.parseDependency(dep)).join(', '));
.addField(' Dependencies', this.parseDependencies());
return msg.embed(embed);
}
parseDependency(dep) {
if (dep[1].startsWith('github:')) {
const repo = dep[1].replace('github:', '').split('/');
return `[${dep[0]}](https://github.com/${repo[0]}/${repo[1].replace(/#.+/, '')})`;
}
return `[${dep[0]}](https://www.npmjs.com/package/${dep[0]})`;
parseDependencies() {
return Object.entries(dependencies).map(dep => {
if (dep[1].startsWith('github:')) {
const repo = dep[1].replace('github:', '').split('/');
return `[${dep[0]}](https://github.com/${repo[0]}/${repo[1].replace(/#.+/, '')})`;
}
return `[${dep[0]}](https://www.npmjs.com/package/${dep[0]})`;
}).join(', ');
}
};
+5 -2
View File
@@ -1,6 +1,6 @@
{
"name": "xiao",
"version": "91.8.3",
"version": "91.8.4",
"description": "Your personal server companion.",
"main": "Xiao.js",
"scripts": {
@@ -42,6 +42,9 @@
"dotenv": "^6.0.0",
"erlpack": "github:discordapp/erlpack",
"mathjs": "^5.1.2",
"moment": "^2.22.2",
"moment-duration-format": "^2.2.2",
"moment-timezone": "^0.5.21",
"neopet-image-finder": "^5.0.2",
"node-opus": "^0.3.0",
"node-superfetch": "^0.1.5",
@@ -49,7 +52,7 @@
"zlib-sync": "^0.1.4"
},
"devDependencies": {
"eslint": "^5.5.0",
"eslint": "^5.6.0",
"eslint-config-amber": "^1.1.0",
"eslint-plugin-json": "^1.2.1"
},
-7
View File
@@ -28,13 +28,6 @@ module.exports = class Util {
return text.length > maxLen ? `${text.substr(0, maxLen - 3)}...` : text;
}
static duration(ms) {
const sec = Math.floor((ms / 1000) % 60).toString();
const min = Math.floor((ms / (1000 * 60)) % 60).toString();
const hrs = Math.floor(ms / (1000 * 60 * 60)).toString();
return `${hrs.padStart(2, '0')}:${min.padStart(2, '0')}:${sec.padStart(2, '0')}`;
}
static randomRange(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}