Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support epoch timestamp for date filter #67

Closed
pirsquare opened this issue Aug 19, 2022 · 3 comments
Closed

Support epoch timestamp for date filter #67

pirsquare opened this issue Aug 19, 2022 · 3 comments
Labels
incompatibility Behavioural differences between Python and Ruby Liquid

Comments

@pirsquare
Copy link

Currently date filter won't work for epoch timestamp. In other libraries, epoch timestamp works.
https://liquidjs.com/playground.html

{% assign created_timestamp = "1645173284" -%}
{{ created_timestamp | date: "%d %b %Y" }}

Will render

18 Feb 2022

We can add a minor update to date filter to support epoch timestamp

try:
    dat = datetime.datetime.fromtimestamp(int(dat), datetime.timezone.utc)
except:
    pass

Full function update

@with_environment
@liquid_filter
@functools.lru_cache(maxsize=10)
def date(
    dat: Union[datetime.datetime, str], fmt: str, *, environment: Environment
) -> str:
    """Formats a datetime according the the given format string."""
    if is_undefined(dat):
        return ""

    if is_undefined(fmt):
        return str(dat)

    # try if it's epoch timestamp
    try:
        dat = datetime.datetime.fromtimestamp(int(dat), datetime.timezone.utc)
    except:
        pass

    if isinstance(dat, str):
        if dat in ("now", "today"):
            dat = datetime.datetime.now()
        else:
            dat = parser.parse(dat)

    if not isinstance(dat, (datetime.datetime, datetime.date)):
        raise FilterArgumentError(
            f"date expected datetime.datetime, found {type(dat).__name__}"
        )

    rv = dat.strftime(fmt)

    if environment.autoescape and isinstance(fmt, Markup):
        return Markup(rv)
    return 
@jg-rp jg-rp added the incompatibility Behavioural differences between Python and Ruby Liquid label Aug 19, 2022
@jg-rp
Copy link
Owner

jg-rp commented Aug 19, 2022

Hi @pirsquare,

Thank you. The date filter in the reference implementation of Liquid supports timestamps too.

This will be fixed in the next release. Until then, you can register the new date implementation, or an implementation of your own, with an Environment like this.

import datetime
from typing import Union
from dateutil import parser

from liquid import Environment
from liquid import Markup
from liquid import is_undefined

from liquid.filter import liquid_filter
from liquid.filter import with_environment

from liquid.exceptions import FilterArgumentError


@with_environment
@liquid_filter
def date(
    dat: Union[datetime.datetime, str, int],
    fmt: str,
    *,
    environment: Environment,
) -> str:
    """Formats a datetime according the the given format string."""
    if is_undefined(dat):
        return ""

    if is_undefined(fmt):
        return str(dat)

    if isinstance(dat, str):
        if dat in ("now", "today"):
            dat = datetime.datetime.now()
        elif dat.isdigit():
            # The reference implementation does not support string
            # representations of negative integers either.
            dat = datetime.datetime.fromtimestamp(int(dat))
        else:
            try:
                dat = parser.parse(dat)
            except parser.ParserError:
                # Input is returned unchanged. This is consistent
                # with the reference implementation.
                return str(dat)
    elif isinstance(dat, int):
        try:
            dat = datetime.datetime.fromtimestamp(dat)
        except (OverflowError, OSError):
            # Testing on Windows shows that it can't handle some
            # negative integers.
            return str(dat)

    if not isinstance(dat, (datetime.datetime, datetime.date)):
        raise FilterArgumentError(
            f"date expected datetime.datetime, found {type(dat).__name__}"
        )

    rv = dat.strftime(fmt)

    if environment.autoescape and isinstance(fmt, Markup):
        return Markup(rv)
    return rv


# Example of replacing the built-in `date` filter
env = Environment()
env.add_filter("date", date)

t = env.from_string("{{ '1152098955' | date: '%m/%d/%Y' }}")
print(t.render())

@pirsquare
Copy link
Author

Yes I actually did that, thankfully you had a section on it to replace existing filter. Great library and thank you for your work!

@jg-rp
Copy link
Owner

jg-rp commented Aug 23, 2022

Fixed in version 1.4.3, now released.

@jg-rp jg-rp closed this as completed Aug 23, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
incompatibility Behavioural differences between Python and Ruby Liquid
Projects
None yet
Development

No branches or pull requests

2 participants