diff --git a/BackgroundServices/BirthdayRoleUpdate.cs b/BackgroundServices/BirthdayRoleUpdate.cs
index e9bfcf1..9e2d889 100644
--- a/BackgroundServices/BirthdayRoleUpdate.cs
+++ b/BackgroundServices/BirthdayRoleUpdate.cs
@@ -19,8 +19,7 @@ namespace BirthdayBot.BackgroundServices
public BirthdayRoleUpdate(ShardInstance instance) : base(instance) { }
///
- /// Processes birthday updates for all available guilds synchronously
- /// (to avoid database connection pool bottlenecks and rate limiting).
+ /// Processes birthday updates for all available guilds synchronously.
///
public override async Task OnTick(CancellationToken token)
{
@@ -41,25 +40,24 @@ namespace BirthdayBot.BackgroundServices
}
catch (Exception ex)
{
- // Catch all exceptions per-guild but continue processing, throw at end
+ // Catch all exceptions per-guild but continue processing, throw at end.
exs.Add(ex);
}
}
if (exs.Count != 0) throw new AggregateException(exs);
-
- // TODO metrics for role sets, unsets, announcements - and how to do that for singles too?
}
///
/// Access to for the testing command.
///
/// Diagnostic data in string form.
- public async Task SingleProcessGuildAsync(SocketGuild guild) => (await ProcessGuildAsync(guild).ConfigureAwait(false)).Export();
+ public static async Task SingleProcessGuildAsync(SocketGuild guild)
+ => (await ProcessGuildAsync(guild).ConfigureAwait(false)).Export();
///
/// Main method where actual guild processing occurs.
///
- private async Task ProcessGuildAsync(SocketGuild guild)
+ private static async Task ProcessGuildAsync(SocketGuild guild)
{
var diag = new PGDiagnostic();
@@ -100,7 +98,7 @@ namespace BirthdayBot.BackgroundServices
var announceping = gc.AnnouncePing;
SocketTextChannel channel = null;
if (gc.AnnounceChannelId.HasValue) channel = guild.GetTextChannel(gc.AnnounceChannelId.Value);
- if (announcementList.Count() != 0)
+ if (announcementList.Any())
{
var announceResult =
await AnnounceBirthdaysAsync(announce, announceping, channel, announcementList).ConfigureAwait(false);
@@ -117,7 +115,7 @@ namespace BirthdayBot.BackgroundServices
///
/// Checks if the bot may be allowed to alter roles.
///
- private string CheckCorrectRoleSettings(SocketGuild guild, SocketRole role)
+ private static string CheckCorrectRoleSettings(SocketGuild guild, SocketRole role)
{
if (role == null) return "Designated role is not set, or target role cannot be found.";
@@ -139,7 +137,7 @@ namespace BirthdayBot.BackgroundServices
/// Gets all known users from the given guild and returns a list including only those who are
/// currently experiencing a birthday in the respective time zone.
///
- private HashSet GetGuildCurrentBirthdays(IEnumerable guildUsers, string defaultTzStr)
+ private static HashSet GetGuildCurrentBirthdays(IEnumerable guildUsers, string defaultTzStr)
{
var birthdayUsers = new HashSet();
@@ -184,7 +182,7 @@ namespace BirthdayBot.BackgroundServices
/// First item: List of users who had the birthday role applied, used to announce.
/// Second item: Counts of users who have had roles added/removed, used for operation reporting.
///
- private async Task<(IEnumerable, (int, int))> UpdateGuildBirthdayRoles(
+ private static async Task<(IEnumerable, (int, int))> UpdateGuildBirthdayRoles(
SocketGuild g, SocketRole r, HashSet names)
{
// Check members currently with the role. Figure out which users to remove it from.
@@ -224,7 +222,7 @@ namespace BirthdayBot.BackgroundServices
/// who have just had their birthday role added.
///
/// The message to place into operation status log.
- private async Task AnnounceBirthdaysAsync(
+ private static async Task AnnounceBirthdaysAsync(
(string, string) announce, bool announcePing, SocketTextChannel c, IEnumerable names)
{
if (c == null) return "Announcement channel is not set, or previous announcement channel has been deleted.";
diff --git a/BackgroundServices/DataRetention.cs b/BackgroundServices/DataRetention.cs
index 6807f04..92f13f9 100644
--- a/BackgroundServices/DataRetention.cs
+++ b/BackgroundServices/DataRetention.cs
@@ -15,7 +15,7 @@ namespace BirthdayBot.BackgroundServices
///
class DataRetention : BackgroundService
{
- private static readonly SemaphoreSlim _updateLock = new SemaphoreSlim(ShardManager.MaxConcurrentOperations);
+ private static readonly SemaphoreSlim _updateLock = new(ShardManager.MaxConcurrentOperations);
const int ProcessInterval = 3600 / ShardBackgroundWorker.Interval; // Process about once per hour
private int _tickCount = -1;
@@ -33,10 +33,11 @@ namespace BirthdayBot.BackgroundServices
try
{
// A semaphore is used to restrict this work being done concurrently on other shards
- // to avoid putting pressure on the SQL connection pool. Updating this is a low priority.
+ // to avoid putting pressure on the SQL connection pool. Clearing old database information
+ // ultimately is a low priority among other tasks.
await _updateLock.WaitAsync(token).ConfigureAwait(false);
}
- catch (Exception ex) when (ex is OperationCanceledException || ex is ObjectDisposedException)
+ catch (Exception ex) when (ex is OperationCanceledException or ObjectDisposedException)
{
// Calling thread does not expect the exception that SemaphoreSlim throws...
throw new TaskCanceledException();
@@ -81,13 +82,13 @@ namespace BirthdayBot.BackgroundServices
var userlist = item.Value;
pUpdateG.Value = (long)guild;
- updatedGuilds += await cUpdateGuild.ExecuteNonQueryAsync().ConfigureAwait(false);
+ updatedGuilds += await cUpdateGuild.ExecuteNonQueryAsync(CancellationToken.None).ConfigureAwait(false);
pUpdateGU_g.Value = (long)guild;
foreach (var userid in userlist)
{
pUpdateGU_u.Value = (long)userid;
- updatedUsers += await cUpdateGuildUser.ExecuteNonQueryAsync().ConfigureAwait(false);
+ updatedUsers += await cUpdateGuildUser.ExecuteNonQueryAsync(CancellationToken.None).ConfigureAwait(false);
}
}
var resultText = new StringBuilder();
@@ -100,13 +101,13 @@ namespace BirthdayBot.BackgroundServices
{
// Delete data for guilds not seen in 4 weeks
c.CommandText = $"delete from {GuildConfiguration.BackingTable} where (now() - interval '28 days') > last_seen";
- staleGuilds = await c.ExecuteNonQueryAsync().ConfigureAwait(false);
+ staleGuilds = await c.ExecuteNonQueryAsync(CancellationToken.None).ConfigureAwait(false);
}
using (var c = db.CreateCommand())
{
// Delete data for users not seen in 8 weeks
c.CommandText = $"delete from {GuildUserConfiguration.BackingTable} where (now() - interval '56 days') > last_seen";
- staleUsers = await c.ExecuteNonQueryAsync().ConfigureAwait(false);
+ staleUsers = await c.ExecuteNonQueryAsync(CancellationToken.None).ConfigureAwait(false);
}
if (staleGuilds != 0 || staleUsers != 0)
{
diff --git a/BackgroundServices/ExternalStatisticsReporting.cs b/BackgroundServices/ExternalStatisticsReporting.cs
index 6e2fc0c..2c9007b 100644
--- a/BackgroundServices/ExternalStatisticsReporting.cs
+++ b/BackgroundServices/ExternalStatisticsReporting.cs
@@ -14,7 +14,7 @@ namespace BirthdayBot.BackgroundServices
const int ProcessInterval = 600 / ShardBackgroundWorker.Interval; // Process every ~5 minutes
private int _tickCount = 0;
- private static readonly HttpClient _httpClient = new HttpClient();
+ private static readonly HttpClient _httpClient = new();
public ExternalStatisticsReporting(ShardInstance instance) : base(instance) { }
diff --git a/BackgroundServices/SelectiveAutoUserDownload.cs b/BackgroundServices/SelectiveAutoUserDownload.cs
index 3ca2c4d..06de92a 100644
--- a/BackgroundServices/SelectiveAutoUserDownload.cs
+++ b/BackgroundServices/SelectiveAutoUserDownload.cs
@@ -14,9 +14,9 @@ namespace BirthdayBot.BackgroundServices
///
class SelectiveAutoUserDownload : BackgroundService
{
- private static readonly SemaphoreSlim _updateLock = new SemaphoreSlim(2);
+ private static readonly SemaphoreSlim _updateLock = new(2);
- private readonly HashSet _fetchRequests = new HashSet();
+ private readonly HashSet _fetchRequests = new();
public SelectiveAutoUserDownload(ShardInstance instance) : base(instance) { }
@@ -42,7 +42,7 @@ namespace BirthdayBot.BackgroundServices
if (requests.Contains(guild.Id) || await GuildUserAnyAsync(guild.Id, token).ConfigureAwait(false))
{
await guild.DownloadUsersAsync().ConfigureAwait(false);
- await Task.Delay(500).ConfigureAwait(false);
+ await Task.Delay(500, CancellationToken.None).ConfigureAwait(false);
}
}
}
@@ -51,13 +51,13 @@ namespace BirthdayBot.BackgroundServices
/// Determines if the user database contains any entries corresponding to this guild.
///
/// True if any entries exist.
- private async Task GuildUserAnyAsync(ulong guildId, CancellationToken token)
+ private static async Task GuildUserAnyAsync(ulong guildId, CancellationToken token)
{
try
{
await _updateLock.WaitAsync(token).ConfigureAwait(false);
}
- catch (Exception ex) when (ex is OperationCanceledException || ex is ObjectDisposedException)
+ catch (Exception ex) when (ex is OperationCanceledException or ObjectDisposedException)
{
// Calling thread does not expect the exception that SemaphoreSlim throws...
throw new TaskCanceledException();
@@ -68,7 +68,7 @@ namespace BirthdayBot.BackgroundServices
using var c = db.CreateCommand();
c.CommandText = $"select count(*) from {GuildUserConfiguration.BackingTable} where guild_id = @Gid";
c.Parameters.Add("@Gid", NpgsqlTypes.NpgsqlDbType.Bigint).Value = (long)guildId;
- await c.PrepareAsync().ConfigureAwait(false);
+ await c.PrepareAsync(CancellationToken.None).ConfigureAwait(false);
var r = (long)await c.ExecuteScalarAsync(token).ConfigureAwait(false);
return r != 0;
}
diff --git a/Common.cs b/Common.cs
index 56d54d6..6a49ea0 100644
--- a/Common.cs
+++ b/Common.cs
@@ -14,12 +14,12 @@ namespace BirthdayBot
{
if (ping) return member.Mention;
- string escapeFormattingCharacters(string input)
+ static string escapeFormattingCharacters(string input)
{
var result = new StringBuilder();
foreach (var c in input)
{
- if (c == '\\' || c == '_' || c == '~' || c == '*' || c == '@')
+ if (c is '\\' or '_' or '~' or '*' or '@')
{
result.Append('\\');
}
@@ -36,7 +36,7 @@ namespace BirthdayBot
return $"**{username}**#{member.Discriminator}";
}
- public static readonly Dictionary MonthNames = new Dictionary()
+ public static readonly Dictionary MonthNames = new()
{
{1, "Jan"}, {2, "Feb"}, {3, "Mar"}, {4, "Apr"}, {5, "May"}, {6, "Jun"},
{7, "Jul"}, {8, "Aug"}, {9, "Sep"}, {10, "Oct"}, {11, "Nov"}, {12, "Dec"}
diff --git a/Configuration.cs b/Configuration.cs
index 01f2e4e..882ac46 100644
--- a/Configuration.cs
+++ b/Configuration.cs
@@ -86,7 +86,7 @@ namespace BirthdayBot
string srVal = jc[ShardLenConfKey]?.Value();
if (!string.IsNullOrWhiteSpace(srVal))
{
- Regex srPicker = new Regex(@"(?\d{1,2})[-,]{1}(?\d{1,2})");
+ Regex srPicker = new(@"(?\d{1,2})[-,]{1}(?\d{1,2})");
var m = srPicker.Match(srVal);
if (m.Success)
{
diff --git a/ShardInstance.cs b/ShardInstance.cs
index ecafa1c..c70ad69 100644
--- a/ShardInstance.cs
+++ b/ShardInstance.cs
@@ -108,8 +108,8 @@ namespace BirthdayBot
///
/// Direct access to invoke the background task of updating birthdays in a guild, for use by the testing command.
///
- public Task ForceBirthdayUpdateAsync(SocketGuild guild)
- => _background.BirthdayUpdater.SingleProcessGuildAsync(guild);
+ public static Task ForceBirthdayUpdateAsync(SocketGuild guild)
+ => BirthdayRoleUpdate.SingleProcessGuildAsync(guild);
public void RequestDownloadUsers(ulong guildId) => _background.UserDownloader.RequestDownload(guildId);
@@ -166,7 +166,7 @@ namespace BirthdayBot
///
private async Task Client_MessageReceived(SocketMessage msg)
{
- if (!(msg.Channel is SocketTextChannel channel)) return;
+ if (msg.Channel is not SocketTextChannel channel) return;
if (msg.Author.IsBot || msg.Author.IsWebhook) return;
if (((IMessage)msg).Type != MessageType.Default) return;
var author = (SocketGuildUser)msg.Author;
@@ -178,7 +178,7 @@ namespace BirthdayBot
if (csplit.Length > 0 && csplit[0].StartsWith(CommandPrefix, StringComparison.OrdinalIgnoreCase))
{
// Determine if it's something we're listening for.
- if (!_dispatchCommands.TryGetValue(csplit[0].Substring(CommandPrefix.Length), out CommandHandler command)) return;
+ if (!_dispatchCommands.TryGetValue(csplit[0][CommandPrefix.Length..], out CommandHandler command)) return;
// Load guild information here
var gconf = await GuildConfiguration.LoadAsync(channel.Guild.Id, false);
diff --git a/ShardManager.cs b/ShardManager.cs
index f3cc415..c5596f6 100644
--- a/ShardManager.cs
+++ b/ShardManager.cs
@@ -39,7 +39,7 @@ namespace BirthdayBot
/// Amount of time without a completed background service run before a shard instance
/// is considered "dead" and tasked to be removed.
///
- private static readonly TimeSpan DeadShardThreshold = new TimeSpan(0, 20, 0);
+ private static readonly TimeSpan DeadShardThreshold = new(0, 20, 0);
///
/// A dictionary with shard IDs as its keys and shard instances as its values.
@@ -132,7 +132,6 @@ namespace BirthdayBot
LogLevel = LogSeverity.Info,
DefaultRetryMode = RetryMode.RetryRatelimit,
MessageCacheSize = 0, // not needed at all
- ExclusiveBulkDelete = true, // not relevant, but this is configured to skip the warning
GatewayIntents = GatewayIntents.Guilds | GatewayIntents.GuildMembers | GatewayIntents.GuildMessages
};
var newClient = new DiscordSocketClient(clientConf);
diff --git a/UserInterface/CommandDocumentation.cs b/UserInterface/CommandDocumentation.cs
index d7dbb83..27ba3c7 100644
--- a/UserInterface/CommandDocumentation.cs
+++ b/UserInterface/CommandDocumentation.cs
@@ -15,9 +15,9 @@ namespace BirthdayBot.UserInterface
{
var cmds = new List();
foreach (var item in commands) cmds.Add(CommandsCommon.CommandPrefix + item);
- if (cmds.Count == 0) throw new ArgumentException(nameof(commands));
+ if (cmds.Count == 0) throw new ArgumentException(null, nameof(commands));
Commands = cmds.ToArray();
- Usage = usage ?? throw new ArgumentException(nameof(usage));
+ Usage = usage ?? throw new ArgumentException(null, nameof(usage));
Examples = examples;
}
diff --git a/UserInterface/CommandsCommon.cs b/UserInterface/CommandsCommon.cs
index 048e489..9bca783 100644
--- a/UserInterface/CommandsCommon.cs
+++ b/UserInterface/CommandsCommon.cs
@@ -59,7 +59,7 @@ namespace BirthdayBot.UserInterface
///
/// Checks given time zone input. Returns a valid string for use with NodaTime.
///
- protected string ParseTimeZone(string tzinput)
+ protected static string ParseTimeZone(string tzinput)
{
string tz = null;
if (tzinput != null)
@@ -80,16 +80,14 @@ namespace BirthdayBot.UserInterface
/// Given user input where a user-like parameter is expected, attempts to resolve to an ID value.
/// Input must be a mention or explicit ID. No name resolution is done here.
///
- protected bool TryGetUserId(string input, out ulong result)
+ protected static bool TryGetUserId(string input, out ulong result)
{
string doParse;
var m = UserMention.Match(input);
if (m.Success) doParse = m.Groups[1].Value;
else doParse = input;
- ulong resultVal;
- if (ulong.TryParse(doParse, out resultVal))
- {
+ if (ulong.TryParse(doParse, out ulong resultVal)) {
result = resultVal;
return true;
}
diff --git a/UserInterface/HelpInfoCommands.cs b/UserInterface/HelpInfoCommands.cs
index f85f28b..d026927 100644
--- a/UserInterface/HelpInfoCommands.cs
+++ b/UserInterface/HelpInfoCommands.cs
@@ -33,7 +33,7 @@ namespace BirthdayBot.UserInterface
("invite", CmdInfo)
};
- private (Embed, Embed) BuildHelpEmbeds()
+ private static (Embed, Embed) BuildHelpEmbeds()
{
var cpfx = $"●`{CommandPrefix}";
diff --git a/UserInterface/ListingCommands.cs b/UserInterface/ListingCommands.cs
index 713abaf..0861569 100644
--- a/UserInterface/ListingCommands.cs
+++ b/UserInterface/ListingCommands.cs
@@ -27,12 +27,12 @@ namespace BirthdayBot.UserInterface
#region Documentation
public static readonly CommandDocumentation DocList =
- new CommandDocumentation(new string[] { "list" }, "Exports all birthdays to a file."
+ new(new string[] { "list" }, "Exports all birthdays to a file."
+ " Accepts `csv` as an optional parameter.", null);
public static readonly CommandDocumentation DocUpcoming =
- new CommandDocumentation(new string[] { "recent", "upcoming" }, "Lists recent and upcoming birthdays.", null);
+ new(new string[] { "recent", "upcoming" }, "Lists recent and upcoming birthdays.", null);
public static readonly CommandDocumentation DocWhen =
- new CommandDocumentation(new string[] { "when" }, "Displays the given user's birthday information.", null);
+ new(new string[] { "when" }, "Displays the given user's birthday information.", null);
#endregion
private async Task CmdWhen(ShardInstance instance, GuildConfiguration gconf,
@@ -202,7 +202,7 @@ namespace BirthdayBot.UserInterface
search += 1;
if (search > 366) search = 1; // wrap to beginning of year
- if (results.Count() == 0) continue; // back out early
+ if (!results.Any()) continue; // back out early
resultCount += results.Count();
// Build sorted name list
@@ -245,7 +245,7 @@ namespace BirthdayBot.UserInterface
/// Fetches all guild birthdays and places them into an easily usable structure.
/// Users currently not in the guild are not included in the result.
///
- private async Task> GetSortedUsersAsync(SocketGuild guild)
+ private static async Task> GetSortedUsersAsync(SocketGuild guild)
{
using var db = await Database.OpenConnectionAsync();
using var c = db.CreateCommand();
@@ -323,7 +323,7 @@ namespace BirthdayBot.UserInterface
return result.ToString();
}
- private string CsvEscape(string input)
+ private static string CsvEscape(string input)
{
var result = new StringBuilder();
result.Append('"');
@@ -336,7 +336,7 @@ namespace BirthdayBot.UserInterface
return result.ToString();
}
- private int DateIndex(int month, int day)
+ private static int DateIndex(int month, int day)
{
var dateindex = 0;
// Add month offsets
diff --git a/UserInterface/ManagerCommands.cs b/UserInterface/ManagerCommands.cs
index e910e41..10d0175 100644
--- a/UserInterface/ManagerCommands.cs
+++ b/UserInterface/ManagerCommands.cs
@@ -48,7 +48,7 @@ namespace BirthdayBot.UserInterface
#region Documentation
public static readonly CommandDocumentation DocOverride =
- new CommandDocumentation(new string[] { "override (user ping or ID) (command w/ parameters)" },
+ new(new string[] { "override (user ping or ID) (command w/ parameters)" },
"Perform certain commands on behalf of another user.", null);
#endregion
@@ -426,7 +426,7 @@ namespace BirthdayBot.UserInterface
if (cmdsearch.StartsWith(CommandPrefix))
{
// Strip command prefix to search for the given command.
- cmdsearch = cmdsearch.Substring(CommandPrefix.Length);
+ cmdsearch = cmdsearch[CommandPrefix.Length..];
}
else
{
@@ -472,7 +472,7 @@ namespace BirthdayBot.UserInterface
var guild = reqChannel.Guild;
string result = $"\nServer ID: {guild.Id} | Bot shard ID: {instance.ShardId:00}";
result += $"\nLocally cached members: {guild.DownloadedMemberCount} out of {guild.MemberCount}";
- result += "\n" + await instance.ForceBirthdayUpdateAsync(guild).ConfigureAwait(false);
+ result += "\n" + await ShardInstance.ForceBirthdayUpdateAsync(guild).ConfigureAwait(false);
await reqChannel.SendMessageAsync(result).ConfigureAwait(false);
}
catch (Exception ex)
@@ -485,9 +485,9 @@ namespace BirthdayBot.UserInterface
#region Common/helper methods
private const string RoleInputError = ":x: Unable to determine the given role.";
- private static readonly Regex RoleMention = new Regex(@"<@?&(?\d+)>", RegexOptions.Compiled);
+ private static readonly Regex RoleMention = new(@"<@?&(?\d+)>", RegexOptions.Compiled);
- private SocketRole FindUserInputRole(string inputStr, SocketGuild guild)
+ private static SocketRole FindUserInputRole(string inputStr, SocketGuild guild)
{
// Resembles a role mention? Strip it to the pure number
var input = inputStr;
diff --git a/UserInterface/UserCommands.cs b/UserInterface/UserCommands.cs
index 2e244cf..e3d62be 100644
--- a/UserInterface/UserCommands.cs
+++ b/UserInterface/UserCommands.cs
@@ -23,8 +23,8 @@ namespace BirthdayBot.UserInterface
const string FormatError = ":x: Unrecognized date format. The following formats are accepted, as examples: "
+ "`15-jan`, `jan-15`, `15 jan`, `jan 15`, `15 January`, `January 15`.";
- private static readonly Regex DateParse1 = new Regex(@"^(?\d{1,2})[ -](?[A-Za-z]+)$", RegexOptions.Compiled);
- private static readonly Regex DateParse2 = new Regex(@"^(?[A-Za-z]+)[ -](?\d{1,2})$", RegexOptions.Compiled);
+ private static readonly Regex DateParse1 = new(@"^(?\d{1,2})[ -](?[A-Za-z]+)$", RegexOptions.Compiled);
+ private static readonly Regex DateParse2 = new(@"^(?[A-Za-z]+)[ -](?\d{1,2})$", RegexOptions.Compiled);
///
/// Parses a date input.
@@ -33,7 +33,7 @@ namespace BirthdayBot.UserInterface
///
/// Thrown for any parsing issue. Reason is expected to be sent to Discord as-is.
///
- private (int, int) ParseDate(string dateInput)
+ private static (int, int) ParseDate(string dateInput)
{
var m = DateParse1.Match(dateInput);
if (!m.Success)
@@ -71,60 +71,35 @@ namespace BirthdayBot.UserInterface
///
/// Thrown on error. Send out to Discord as-is.
///
- private (int, int) GetMonth(string input)
+ private static (int, int) GetMonth(string input)
{
- switch (input.ToLower())
- {
- case "jan":
- case "january":
- return (1, 31);
- case "feb":
- case "february":
- return (2, 29);
- case "mar":
- case "march":
- return (3, 31);
- case "apr":
- case "april":
- return (4, 30);
- case "may":
- return (5, 31);
- case "jun":
- case "june":
- return (6, 30);
- case "jul":
- case "july":
- return (7, 31);
- case "aug":
- case "august":
- return (8, 31);
- case "sep":
- case "september":
- return (9, 30);
- case "oct":
- case "october":
- return (10, 31);
- case "nov":
- case "november":
- return (11, 30);
- case "dec":
- case "december":
- return (12, 31);
- default:
- throw new FormatException($":x: Can't determine month name `{input}`. Check your spelling and try again.");
- }
+ return input.ToLower() switch {
+ "jan" or "january" => (1, 31),
+ "feb" or "february" => (2, 29),
+ "mar" or "march" => (3, 31),
+ "apr" or "april" => (4, 30),
+ "may" => (5, 31),
+ "jun" or "june" => (6, 30),
+ "jul" or "july" => (7, 31),
+ "aug" or "august" => (8, 31),
+ "sep" or "september" => (9, 30),
+ "oct" or "october" => (10, 31),
+ "nov" or "november" => (11, 30),
+ "dec" or "december" => (12, 31),
+ _ => throw new FormatException($":x: Can't determine month name `{input}`. Check your spelling and try again."),
+ };
}
#endregion
#region Documentation
public static readonly CommandDocumentation DocSet =
- new CommandDocumentation(new string[] { "set (date)" }, "Registers your birth month and day.",
+ new(new string[] { "set (date)" }, "Registers your birth month and day.",
$"`{CommandPrefix}set jan-31`, `{CommandPrefix}set 15 may`.");
public static readonly CommandDocumentation DocZone =
- new CommandDocumentation(new string[] { "zone (zone)" }, "Sets your local time zone. "
+ new(new string[] { "zone (zone)" }, "Sets your local time zone. "
+ $"See also `{CommandPrefix}help-tzdata`.", null);
public static readonly CommandDocumentation DocRemove =
- new CommandDocumentation(new string[] { "remove" }, "Removes your birthday information from this bot.", null);
+ new(new string[] { "remove" }, "Removes your birthday information from this bot.", null);
#endregion
private async Task CmdSet(ShardInstance instance, GuildConfiguration gconf,