Coder Social home page Coder Social logo

fedecalendino / alfred-world-clock Goto Github PK

View Code? Open in Web Editor NEW
9.0 1.0 4.0 23.86 MB

Alfred Workflow to check time in multiple timezones ๐ŸŒ๏ธ

Home Page: https://alfred.app/workflows/fedecalendino/world-clock/

License: MIT License

Python 92.71% Shell 7.29%
alfred alfred-workflow workflow

alfred-world-clock's Issues

Suggestions: Adding the Python code directly

The current way of sharing the workflow is atypical. It ships with a Python distribution which is ARM-only and significantly increases the size of the workflow. Plus itโ€™s unsigned, so userโ€™s canโ€™t inspect the code and will get a warning from macOS that it is from an unidentified developer.

This means fewer users will have access to it or try it.

You can use /usr/bin/python3 directly, which is a shim on macOS but will install Python 3 when first called. A macOS GUI dialog guides users through the process.

Also, note that due to not having a Title in the Script Filter, it wonโ€™t show up in the list of results as users type part of the name.

Added calculation + display utc functionality....

I like your Alfred Word Clock and added some functionality.

import sys
from datetime import timedelta, datetime
from uuid import uuid4

import pytz as tz
from pyflow import Workflow

import data
import formatters

#added function to be able to type: 
#now 1 (add 1 hour)
#now -1 (subtract 1 hour)
# and more options... 

def add_time(arg):
    if arg[0] == '-':
        is_negative = True
        arg = arg[1:]
    else:
        is_negative = False

    if len(arg) == 0 or (len(arg.strip()) == 1 and arg.startswith('+')):
        return 0

    if arg.endswith(':'):
        arg = arg[:-1]

    arg = arg.split(':')

    if len(arg) == 3:
        hr, minute, sec = arg
        total_seconds = int(hr) * 3600 + int(minute) * 60 + int(sec)
    elif len(arg) == 2:
        hr, minute = arg
        total_seconds = int(hr) * 3600 + int(minute) * 60
    elif len(arg) == 1:
        hr = arg[0]
        total_seconds = int(hr) * 3600

    if is_negative:
        total_seconds = -total_seconds

    return total_seconds


def get_home(workflow):
    home_tz = workflow.env["HOME"][3:].replace("__", "/")

    home_now = (
        datetime.utcnow()
        .replace(tzinfo=tz.utc)
        .astimezone(
            tz=tz.timezone(home_tz),
        )
    )

    return home_tz, home_now


def get_timezones(workflow, home_tz):
    timezones = set(
        map(
            lambda item: item[0][3:].replace("__", "/"),
            filter(
                lambda item: item[0].startswith("TZ_") and item[1] == "1",
                workflow.env.items(),
            ),
        )
    )

    timezones.add(home_tz)

    return {
        timezone: datetime.utcnow()
        .replace(tzinfo=tz.utc)
        .astimezone(tz=tz.timezone(timezone))
        for timezone in timezones
    }


def get_formatter(workflow):
    timestamp_format = workflow.env.get("TIMESTAMP_FORMAT", "FORMAT_DEFAULT")
    return formatters.FORMATTERS[timestamp_format]


def get_icon(timezone, now, home_tz):
    if timezone == home_tz:
        return "img/icons/home.png"

    if timezone == "UTC":
        return "img/icons/utc.png"

    utc_offset = now.utcoffset()
    utc_offset_hours = round(utc_offset.days * 24 + utc_offset.seconds / 60 / 60)
    return f"img/icons/{utc_offset_hours}.png"

#I also wanted the UTC +/- added to the output:
def get_utc(timezone, now, home_tz):
    # if timezone == home_tz:
    #     return "img/icons/home.png"

    # if timezone == "UTC":
    #     return "img/icons/utc.png"

    utc_offset = now.utcoffset()
    utc_offset_hours = round(utc_offset.days * 24 + utc_offset.seconds / 60 / 60)
    
    if utc_offset_hours == 0:
        return ""
    
    if utc_offset_hours > 0:
        return f" - UTC +{utc_offset_hours}"
    
    return f" - UTC {utc_offset_hours}"


def get_home_offset_str(timezone, home_tz, now, home_now) -> str:
    if timezone == home_tz:
        return ""
    
    now_tmp = now.replace(tzinfo=None)
    home_now_tmp = home_now.replace(tzinfo=None)

    if home_now_tmp > now_tmp:
        home_offset = home_now_tmp - now_tmp
        seconds = home_offset.seconds + 1
        text = "behind"
    else:
        home_offset = home_now_tmp - now_tmp
        seconds = 24 * 60 * 60 - home_offset.seconds + 1
        text = "ahead of"

    return "ยท [{hours:02}:{minutes:02} hs {text} home ๐Ÿ ]".format(
        hours=seconds // 3600,
        minutes=(seconds % 3600) // 60,
        text=text,
    )


def get_name_replacements(workflow):
    sep = "//"

    name_replacements = {}

    for line in workflow.env.get("NAME_REPLACEMENTS", "").split("\n"):
        if not line:
            continue

        if sep not in line:
            raise ValueError(
                f"name replacement '{line}' is missing the '{sep}' separator."
            )

        parts = line.split(sep)

        if len(parts) != 2:
            raise ValueError(
                f"name replacement '{line}' should have the format `old {sep} new`."
            )

        if "" in parts:
            raise ValueError(
                f"name replacement '{line}' should have the format `old {sep} new`."
            )

        old, new = parts
        name_replacements[old.strip()] = new.strip()

    return name_replacements


def main(workflow):

    total_seconds = 0
    input = ''
    if len(sys.argv) > 1:
        arg = sys.argv[1]
        input = ' ' + sys.argv[1]
        total_seconds = add_time(arg)

    home_tz, home_now = get_home(workflow)
    timezones = get_timezones(workflow, home_tz)
    formatter = get_formatter(workflow)

    name_replacements = get_name_replacements(workflow)

    sorter = lambda pair: pair[1].isoformat()

    for timezone, now in sorted(timezones.items(), key=sorter):
        location = timezone.split("/")[-1].replace("_", " ")
        location = name_replacements.get(location, location)
        
        home_offset_str = get_home_offset_str(timezone, home_tz, now, home_now) + get_utc(timezone, now, home_tz)

        #here the arg is added to the now...
        now += timedelta(seconds=total_seconds)

        workflow.new_item(
            title=formatter(now) + input,
            subtitle="{flag} {location} {home_offset}".format(
                flag=data.flags.get(timezone, "๐ŸŒ"),
                location=location,
                home_offset=home_offset_str,
            ),
            arg=formatter(now) + get_utc(timezone, now, home_tz),
            copytext=formatter(now),
            valid=True,
            uid=str(uuid4()),
        ).set_icon_file(
            path=get_icon(timezone, now, home_tz),
        ).set_alt_mod(
            subtitle="Copy ISO format (with microseconds)",
            arg=formatters.iso8601(now),
        ).set_cmd_mod(
            subtitle="Copy ISO format (without microseconds)",
            arg=formatters.iso8601_without_microseconds(now),
        )

if __name__ == "__main__":
    wf = Workflow()
    wf.run(main)
    wf.send_feedback()
    sys.exit()


In Alfred I changed:
image

Time format options

Hi,

Would it be possible to use the computer's preferred date/time format option for the date/time display. Right now I have my computer set to use AM/PM and not 24-hour time, but the display is always in 24 hour time.

Thanks,

Allan

TZ missing

What am I missing? I found no TZ for China or India. I was expecting Beijing and Delhi as a minimum.

Build instructions?

It would be helpful to have some build instructions.

As a very experienced python user, but a newbie to poetry and a newbie to Alfred, I wasn't able to figure out how to get the build working.

As-is, cloning the repo and running ./build.sh fails because it is looking for a .venv (which doesn't exist on my machine). Maybe there is some poetry magic that needs to be run first to set up the virtual environment, but I haven't used poetry before (and I usually use conda instead of venv, so I don't know my way around venv very well either).

Thanks!

Unable to see results in Alfred 5

Hello @fedecalendino

I have installed and configured alfred-world-clock per instructions, but when I launch via the keyword in Alfred 5 it briefly shows World Clock - Calculating times... at the top of the results list but then quickly disappears without producing any results. Any idea how I can fix this?

I haven't modified anything and downloaded directly into Alfred via the Gallery.

A great workflow and I'm keen to see it in action!

Thanks

Add ability for AM/PM to be lowercase

Id like to have the am/pm lowercase

i tried to change it to %P to make it lowercase in the formatters but it seems to not work.

Is this possible?

Feature Request: Friendly name for home.

I was looking through the code a bit, and was wondering if there would be an easy way to add a space in the config for setting a "Friendly name" for home. I find when i type "now" it always takes me a second to remember that my home and the city i have as home in this tool are different.

If you have any suggestions where to start implementing this I could shape up a PR. I've been looking for a reason to get reacquainted with Alfred workflows now that all the cool config features have been added.

Feature request: Home timezone for offset value

I work for different timezones one feature I find useful is to know how much ahead or behind I am.

It would be great if we can set a "Home" timezone so, on top of the information you already provide you can give the offset (i.e. 5h behind, 2h ahead, etc.).

Thanks, great workflow.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.