Convert time to the timezones for mentioned users.
About Abbot
Abbot is a programmable bot that turns your team chat into a shared command center. We handle all the boilerplate of building and running these conmmands so that you can focus on making tools that help you ship faster.
We built Abbot because we saw the power of this style of work (called ChatOps), when we worked at GitHub. ChatOps made it possible for GitHub to work productively without meetings, while globally distributed. We think it’s a pretty great way to work, so we made it easy to use in Slack, Discord, and Microsoft Teams.
You can read more about Abbot here, check out our blog, or take a look at some of the other cool packages available as a one-click install from Abbot’s Package Directory.
README
The tz
skill is a convenient way to coordinate users in multiple timezones. For example, say you want to know the current time for you and your colleagues @paulnakata and @costello.
@abbot tz me @paulnakata @costello
will show a table of the current time in each mentioned user’s timezone.
User | Time | TimeZone
---------- | ---------- | -------------------
haacked | 1:11:24 PM | America/Los_Angeles
paulnakata | 4:11:24 PM | America/New_York
costello | 7:11:24 PM | Europe/Madrid
Fantastic, but suppose you want to schedule a meeting at 2pm.
@abbot tz 2pm me @paulnakata @costello
This shows a table showing how 2pm for the first mentioned user maps to each mentioned user.
User | Time | TimeZone
---------- | ---------- | -------------------
haacked | 2:00:00 PM | America/Los_Angeles
paulnakata | 4:00:00 PM | America/New_York
costello | 7:00:00 PM | Europe/Madrid
Later on, you want to be fair and schedule a meeting at 2:30pm for @costello.
@abbot tz 2:30pm @costello @paulnakata me
User | Time | TimeZone
---------- | ---------- | -------------------
costello | 7:30:00 PM | Europe/Madrid
paulnakata | 4:30:00 PM | America/New_York
haacked | 2:30:00 PM | America/Los_Angeles
Note that this only works for Slack at the time being because Discord does not provide timezone information for users.
Usage
@abbot tz
replies with the current time in Abbot’s timezone
@abbot tz me
replies with the current time in your timezone.
@abbot tz {time} @user1 @user2
replies with the in each of the user’s timezones. It uses the first mention’s timezone as the basis for the time.
For example: @abbot tz 2pm me @somebody @another
will show 2pm in my timezone converted to the timezones of @somebody and @another.
@abbot tz 2pm @somebody me
will show 2pm in @somebody’s timezone converted to my timezone.
Code
Package URL: /packages/aseriousbiz/tz
Usage:
`@abbot tz` _replies with the current time in Abbot’s timezone_
`@abbot tz me` _replies with the current time in your timezone._
`@abbot tz {time} @user1 @user2` _replies with the {time} in each of the user’s timezones. It uses the first mention’s timezone as the basis for the time._
For example: `@abbot tz 2pm me @somebody @another` will show 2pm in my timezone converted to the timezones of @somebody and @another.
`@abbot tz 2pm @somebody me` will show 2pm in @somebody’s timezone converted to my timezone.
*/
if (Bot.Arguments is { Count: 0 }) {
await Bot.ReplyAsync($”Hello, it is `{GetLocalTime(Bot.TimeZone)}` in my timezone. Try `{Bot} help tz` to learn more about what I can do with timezones.”);
return;
}
if (Bot.From.TimeZone is null) {
await Bot.ReplyAsync($”I do not know your timezone. You can tell me using `{Bot} my tz is {{tz}}` (where tz is the TZ database name in https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) or by telling me your location, `@abbot my location is {{zip, city, or address}}`”);
return;
}
var time = Bot.Arguments.First();
// If no target time is specified, use the current time for the user or Abbot
// If we do not know the user’s timezone.
var targetTime = time.ToLocalTime() is LocalTime localTime
? localTime
: Bot.From.GetLocalTime();
var mentions = GetOrderedNormalizedMentions();
if (mentions is { Count: 0 }) {
await Bot.ReplyAsync($”Mention some users to see this time in their timezones.”);
return;
}
var timeTable = GetTimeData(mentions, targetTime.Value);
await Bot.ReplyTableAsync(timeTable);
return;
IEnumerable<UserTimeZone> GetTimeData(IList<IChatUser> mentions, LocalTime localTime) {
// Use the timezone for the first mention.
var sourceTz = mentions.First().TimeZone;
foreach (var mention in mentions) {
var mentionTz = mention.TimeZone;
if (mentionTz is null) {
yield return new UserTimeZone(mention.Name);
}
else {
var time = localTime.ToTimeZone(sourceTz, mentionTz).TimeOfDay;
yield return new UserTimeZone(mention.Name, mentionTz.Id, time.ToString());
}
}
}
public class UserTimeZone {
public UserTimeZone(string user) : this (user, “(unknown)”, “(unknown)”) {
}
public UserTimeZone(string user, string timezone, string time) {
User = user;
TimeZone = timezone;
Time = time;
}
public string User { get; }
public string Time { get; }
public string TimeZone { get; }
}
static string GetLocalTime(DateTimeZone tz) {
if (tz is null) {
return null;
}
var now = SystemClock.Instance.GetCurrentInstant();
return $”{now.InZone(tz):MMM dd, uuuu h:mm:ss tt o<G>} {tz}”;
}
IList<IChatUser> GetOrderedNormalizedMentions() {
return Bot.Arguments.Select(arg => arg is IMentionArgument mention
? mention.Mentioned
: arg.Value is “me”
? Bot.From
: null)
.Where(user => user is not null)
.ToList();
}
static Instant GetCurrentInstant(){
return SystemClock.Instance.GetCurrentInstant();
}