diff --git a/package.json b/package.json index 968035f..e870183 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,6 @@ "discord.js": "^12.5.1", "dotenv": "^8.2.0", "googleapis": "^39.2.0", - "luxon": "^1.27.0", "mongoose": "^5.11.8", "node-cron": "^2.0.3" }, diff --git a/src/constants/studySession.js b/src/constants/studySession.js index 338d30d..589c799 100644 --- a/src/constants/studySession.js +++ b/src/constants/studySession.js @@ -1,4 +1,4 @@ -const { getUTCFullDate, getUTCFullTime } = require("../utils/date"); +const { getDynamicDateTime } = require("../utils/date"); // Study session's related messages const STUDY_SESSION = { @@ -6,7 +6,7 @@ const STUDY_SESSION = { SUCCESS: (session) => ({ title: "STUDY SESSION", content: "Study session has been registered successfully!", - description: `šŸ“† ${getUTCFullDate(session.startDate, "date")} at ${getUTCFullDate(session.startDate, "time")} *(UTC)*\nšŸ•‘ Estimated length: ${session.estimatedLength} minutes.\n\n${getStudySessionText(session.message)}\n\n*If anybody wants to join the session, subscribe using the ā­ button\nIf you want to cancel the session, delete the message used to create it*`, + description: `šŸ“† ${getDynamicDateTime(session.startDate, 'long date time')}\nšŸ•‘ Estimated length: ${session.estimatedLength} minutes.\n\n${getStudySessionText(session.message)}\n\n*If anybody wants to join the session, subscribe using the ā­ button\nIf you want to cancel the session, delete the message used to create it*`, withAuthor: true, }), ERROR: (error) => ({ @@ -45,7 +45,7 @@ const STUDY_SESSION = { content: "Here are the upcoming study sessions:\n*Make sure to check the time zones!*", fields: sessions.map((session) => ({ name: `${session.author.username}'s study session`, - value: `*${getUTCFullDate(session.startDate)} UTC (${session.estimatedLength} min)*\n${getUpcomingStudySessionSummary(session.message)} - Subscribe [here](${session.message?.link})`, + value: `*${getDynamicDateTime(session.startDate, 'short date time')} (${session.estimatedLength} min)*\n${getUpcomingStudySessionSummary(session.message)} - Subscribe [here](${session.message?.link})`, })), }), ERROR: (error) => ({ @@ -62,7 +62,7 @@ const STUDY_SESSION = { content: `šŸ‘‹ Hey ${subscriber.username}, you successfully registered to <@${author.id}> study session! See you soon!`, description: messageContent.substr(6).trim(), }), - REMINDER: (studySession, subscriber) => ({ content: `šŸ‘‹ How is your day going, ${subscriber.username}? Thank you for waiting, <@${studySession.author.id}>'s study session is starting in an hour! See you on the Korean Study Group server at **${getUTCFullTime(studySession.startDate)} UTC**!\n*Make sure to check the time zone!*` }), + REMINDER: (studySession, subscriber) => ({ content: `šŸ‘‹ How is your day going, ${subscriber.username}? Thank you for waiting, <@${studySession.author.id}>'s study session is starting ${getDynamicDateTime(studySession.startDate, 'relative')}! See you on the Korean Study Group server at **${getDynamicDateTime(studySession.startDate, 'short time')}**!\n` }), ERROR: (author, error) => ({ content: `${author.username}, you just tried to subscribe to a study session. Thanks for your participation! However, an error as occurred during the process. Please try again! (and don't hesitate to notify <@202787014502776832> about this error)`, title: "āŒ Subscription error", @@ -138,7 +138,7 @@ function getStudySessionCancellationInformation(studySession) { cancellationMessage = title; } - return `${cancellationMessage} on ${getUTCFullDate(startDate, "date")} at ${getUTCFullDate(startDate, "time")} *(UTC)* has been cancelled`; + return `${cancellationMessage} on ${getDynamicDateTime(startDate, 'long date time')} has been cancelled`; } function getTitle(message) { @@ -161,7 +161,7 @@ function getStudySessionCancellationSubscriberNotification(studySession) { cancellationMessage = title; } - return `${cancellationMessage} on ${getUTCFullDate(startDate, "date")} at ${getUTCFullDate(startDate, "time")} *(UTC)*`; + return `${cancellationMessage} on ${getDynamicDateTime(startDate, 'long date time')}`; } module.exports = { STUDY_SESSION }; diff --git a/src/index.js b/src/index.js index bd97784..a1ea7a8 100644 --- a/src/index.js +++ b/src/index.js @@ -21,7 +21,7 @@ const { addBookmark, removeBookmark } = require("./scripts/users/dm/bookmarks"); const { unPin50thMsg, getAllChannels, ping, handleHelpCommand } = require("./scripts/utilities"); const { typingGame, typingGameListener, endTypingGame, gameExplanation } = require("./scripts/activities/games"); const { createStudySession, getUpcomingStudySessions, cancelStudySessionFromCommand, cancelStudySessionFromDeletion, subscribeStudySession, unsubscribeStudySession, updateStudySessionDetails } = require("./scripts/activities/study-session"); -const { convertBetweenTimezones } = require("./scripts/utility-commands/time-and-date"); +const { createDynamicTime } = require("./scripts/utility-commands/time-and-date"); const { loadMessageReaction } = require("./utils/cache"); const runScheduler = require("./scheduler").default; /* ------------------------------------------------------ */ @@ -151,8 +151,8 @@ client.on("message", (message) => { return; } - if (text.startsWith("!timezone")) { - convertBetweenTimezones(message); + if (text.startsWith("!time")) { + createDynamicTime(message); return; } }); diff --git a/src/scripts/utilities.js b/src/scripts/utilities.js index e08d157..ab25332 100644 --- a/src/scripts/utilities.js +++ b/src/scripts/utilities.js @@ -88,8 +88,8 @@ function logMessageDate() { } function handleHelpCommand(message) { - if (message.content.startsWith('!help timezone')) { - handleHelpTimezoneCommand(message); + if (message.content.startsWith('!help time')) { + handleHelpTimeCommand(message); return; } if (message.content.startsWith('!help cancel study')) { @@ -119,11 +119,11 @@ You can cancel a study session either by deleting the message used to create the ` }, { - name: 'Timezones', + name: 'Time', value: ` -Use \`!timezone\` to convert a date-time to equivalent date-times in different regions +Use \`!time\` to generate a dynamic date-time which shows the correct time to each user based on their local timezone -Use \`!help timezone\` for more information +Use \`!help time\` for more information ` }, { name: 'Bookmarks', @@ -143,36 +143,40 @@ Any message the bot sends via DM can be deleted by applying an 'x' (āŒ) reactio }); } -function handleHelpTimezoneCommand(message) { +function handleHelpTimeCommand(message) { + const currentTime = Math.round(new Date().getTime() / 1000); message.channel.send(null, { embed: { - title: "The !timezone command", + title: "The !time command", fields: [ { name: 'Description', - value: 'The `!timezone` command can be used to convert a date-time into date-times around the world' + value: 'The `!time` command can be used to generate a dynamic date-time' }, { name: 'Format', value: ` -This requires a date in the format YYYY/MM/DD and a UTC time in HH:mm followed by any number of [TZ database names](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List) +This command optionally takes a UTC date-time in the format YYYY/MM/DD HH:mm and an output type + +If a date is not supplied it will use the current date and time +If an output type is not supplied it will use the default output type ("short date time") ` }, { - name: 'Example', + name: 'Examples', value: ` -If you've created a study session with these details -\`\`\` -!study 2022/03/05 at 13:30 ... -\`\`\` -You can get the equivalent date-times in Toronto, London and Seoul using -\`\`\` -!timezone 2022/03/05 13:30 America/Toronto Europe/London Asia/Seoul -\`\`\` -Which creates this response: -\`\`\` -Sat, 5 Mar at 08:30 (Eastern Standard Time) -Sat, 5 Mar at 13:30 (Greenwich Mean Time) -Sat, 5 Mar at 22:30 (Korean Standard Time) -\`\`\` +\`!time\` on its own will generate +\`!time short time\` will generate +\`!time 2021/07/29 22:00 relative\` will generate + ` + }, { + name: 'Output types', + value: ` +short date: +long date: +short time: +long time: +short date time: +long date time: +relative: ` } ] diff --git a/src/scripts/utility-commands/time-and-date.js b/src/scripts/utility-commands/time-and-date.js index 6069422..f8cfb72 100644 --- a/src/scripts/utility-commands/time-and-date.js +++ b/src/scripts/utility-commands/time-and-date.js @@ -1,35 +1,18 @@ -const { DateTime } = require("luxon"); +const { getDynamicDateTime, DATE_FORMAT } = require("../../utils/date"); -function convertBetweenTimezones(message) { - let text = message.content ?? ""; - if (text.length < 10) { - return; - } - text = text.substring(9).trim(); +const COMMAND = "!time"; - const dateTime = getDateTimeFromMessage(text); - if (dateTime === null) { - message.reply("please provide a valid datetime in the format YYYY/MM/DD HH:mm"); - return; - } - - const timezones = getTimeZonesFromMessage(text); - if (timezones === null || timezones.length === 0) { - message.reply("please provide at least one valid timezone to convert to. \n\nFor more information use `!help timezone`"); +function createDynamicTime(message) { + let text = message.content ?? ""; + if (text.length < COMMAND.length) { return; } - let convertedTimes = []; - timezones.forEach(timezone => { - const convertedTime = dateTime.setZone(timezone); - if (convertedTime.invalid === null) { - const timeZoneAbbreviation = convertedTime.offsetNameLong; - const dateTimeString = `${convertedTime.weekdayShort}, ${convertedTime.day} ${convertedTime.monthShort} at ${convertedTime.toFormat('HH:mm')} *(${timeZoneAbbreviation})*`; - convertedTimes.push(dateTimeString); - } - }); + text = text.substring(5).trim(); + const dateTime = getDateTimeFromMessage(text) ?? new Date(); - message.channel.send(convertedTimes.join('\n')); + const dynamicDateTimeString = getDynamicDateTime(dateTime, getFormat(text)); + message.channel.send(`${dynamicDateTimeString}\n\nAdd this dynamic time to your messages using \`${dynamicDateTimeString}\`\nUse \`!help time\` for more information.`); } function getDateTimeFromMessage(text) { @@ -41,12 +24,14 @@ function getDateTimeFromMessage(text) { if (isNaN(jsDate.getTime())) { return null; } - return DateTime.fromISO(jsDate.toISOString()); + return jsDate; } -function getTimeZonesFromMessage(text) { - const timezoneRegex = /([A-Za-z]+[\/][A-Za-z0-9_\-+]*)/g; - return text.match(timezoneRegex); +function getFormat(text) { + const keys = Object.keys(DATE_FORMAT); + const formatPattern = new RegExp(`(${keys.join('|').replaceAll('_', ' ')})`); + const maybeFormat = text.toUpperCase().match(formatPattern); + return maybeFormat ? maybeFormat[0] : null; } -module.exports = { convertBetweenTimezones }; +module.exports = { createDynamicTime }; diff --git a/src/tasks/studySession/channelReminder.js b/src/tasks/studySession/channelReminder.js index 53dfe7a..fe5ae00 100644 --- a/src/tasks/studySession/channelReminder.js +++ b/src/tasks/studySession/channelReminder.js @@ -1,5 +1,5 @@ const { getUpcomingStudySessionsForScheduler } = require('../../scripts/activities/study-session'); -const { getUTCFullDate } = require("../../utils/date"); +const { getDynamicDateTime } = require("../../utils/date"); const upcomingStudySessionMessageContent = "Here are the upcoming study sessions:\n*Make sure to check the time zones!*"; const oneHour = 60 * 60 * 1000; @@ -69,7 +69,7 @@ function makeStudySessionMessage() { title: "UPCOMING STUDY SESSIONS", fields: upcomingStudySessions.map((session) => ({ name: `${session.author.username}'s study session`, - value: `*${getUTCFullDate(session.startDate)} UTC (${session.estimatedLength} min)*\n${getUpcomingStudySessionSummary(session.message)} - Subscribe [here](${session.message?.link})`, + value: `*${getDynamicDateTime(session.startDate, 'short date time')} (${session.estimatedLength} min)*\n${getUpcomingStudySessionSummary(session.message)} - Subscribe [here](${session.message?.link})`, })), color: "GREEN" } diff --git a/src/utils/date.js b/src/utils/date.js index b145cbf..53f4261 100644 --- a/src/utils/date.js +++ b/src/utils/date.js @@ -1,31 +1,23 @@ -function getUTCFullDate(date, separateIntoGroups = "") { - if (!date) return ""; - const dateUTC = date.toUTCString(); +const DATE_FORMAT = Object.freeze({ + SHORT_DATE_TIME: 'f', + LONG_DATE_TIME: 'F', + SHORT_DATE: 'd', + LONG_DATE: 'D', + SHORT_TIME: 't', + LONG_TIME: 'T', + RELATIVE: 'R' +}); - // Optionally separate date, year, time, and timezone into groups - const separateRegEx = /(?\w{3},\s\d+\s\w{3})\s(?\d{4})\s(?