Liquid filter by date (Jekyll) - jekyll

I'm trying to filter posts by specific dates in Jekyll. For example, I want to filer all posts posts today, in the past 30 days and everything before that.
However I'm running into a couple of issues:
How can I get the current date, starting at 00:01AM
How do I get the current date, and subtract 30 days
How can I use where_exp to filter by this date
Currently I tried to do something like this, but this converts the date into a string, and can't be used in the where_exp:
{% capture thirty_days_ago %}{{'now' | date: '%s' | minus: 2592000 }}{% endcapture %}
{% assign last_30_days_posts = site.posts | where_exp:"post", "post.posted_on > thirty_days_ago" %}
Liquid error (line 22): comparison of Time with String failed in index.html
I could do a simple check when looping over the posts, but would prefer using a filter before this.
{% capture thirty_days_ago %}{{'now' | date: '%s' | minus: 2592000 }}{% endcapture %}
{% for post in site.posts %}
{% capture post_date %}{{ post.posted_on | date: '%s' | plus: 0 }}{% endcapture %}
{% if job_date > thirty_days_ago %}
{% include components/job.html job=job %}
{% endif %}
{% endfor %}

For anyone looking at a solution; I ended up writing a custom filter:
def last_month_filter(posts)
now = DateTime.now
today = DateTime.new(now.year, now.month, now.day, 0, 0, 0, now.zone)
target = today - 30
posts.select do |post|
postedOn = post.data['posted_on'].to_datetime
if postedOn < today && postedOn > target
post
end
end
end
Usage:
{% assign last_30_days = site.posts | last_month_filter | sort:"posted_on" | reverse %}

Related

i want different between current year and given year in jekyll

i am want get different of number in years:
For example : 2021-2010 = 11
So i am doing similar as my code:
{{assign currentYear = 'now' | date: "%Y"}}{{ assign AllYears = currentYear | minus: 2010 }}
But its show only -2010.
So please help me.
Maybe something like this?
(not tested)
{% assign currentYear = 'now' | date: "%Y" | plus:0 %}
{% assign AllYears = currentYear | minus: 2010 %}
{{ AllYears }}

In Jekyll, how to show "posts from last week"

I'm not sure to get the liquid syntax to help me pull posts that were published during the same week as the build date. Is that possible?
There are simpler ways to get a list of recent posts, but this approach would be useful for my project. I've tried several things I found by searching but no joy yet.
Before even giving this answer a second thought, consider the fact that, at the very least the first part of this answer doesn't really work, because jekyll is a static site generator and therefore the shown posts are relative to the last build date, which may not be the same as current date.
The second part of the answer goes a bit deeper into the idea of actually generating a list of "recent posts", rather than "posts from last week".
To basically explain the code in words: First we get current year and current week, then we loop through every post and compare current year and current week to the week and year of the post. If they match, the post is shown.
Show — Build Week:
{% assign currentYear = site.time | date: "%Y" %}
{% assign currentWeek = site.time | date: "%W" %}
{%- for post in site.posts -%}
{% assign postYear = post.date | date: "%Y" %}
{% assign postWeek = post.date | date: "%W" %}
{%- if currentYear == postYear and currentWeek == postWeek -%}
{{ post.title }}
{%- endif -%}
{%- endfor -%}
Show — Build Day and 6 Days Prior:
{% assign currentYear = site.time | date: "%Y" %}
{% assign currentDay = site.time | date: "%j" | plus: 0 %}
{% assign currentDay_minus_week = site.time | date: "%j" | minus: 7 %}
{%- for post in site.posts -%}
{% assign postYear = post.date | date: "%Y" %}
{% assign postDay = post.date | date: "%j" | plus: 0 %}
{%- if currentYear == postYear and postDay > currentDay_minus_week and postDay <= currentDay -%}
{{ post.title }}
{%- endif -%}
{%- endfor -%}
In an effort to sort of salvage this answer, though it already kind of veered off course.... I wrote this code with similar logic, but this time it gets the year and week of the latest post and shows all posts posted that year and that week.
This would be bulletproof in terms of showing something even if you keep building the site without making new posts. But it also just shows only one post, if your last post is the only post posted that week, which may be a bit dumb...
On the other hand, the simplest method for showing "recent posts" is probably just using the limit and limit recent posts to like last 5 posts or something like that: {%- for post in site.posts limit: 5 -%}
Show — Latest Post Week:
{% assign latestPost_year = site.posts.first.date | date: "%Y" %}
{% assign latestPost_week = site.posts.first.date | date: "%W" %}
{%- for post in site.posts -%}
{% assign postYear = post.date | date: "%Y" %}
{% assign postWeek = post.date | date: "%W" %}
{%- if latestPost_year == postYear and latestPost_week == postWeek -%}
{{ post.title }}
{%- endif -%}
{%- endfor -%}
Show — Latest Post Day and 6 Days Prior
{% assign latestPost_year = site.posts.first.date | date: "%Y" %}
{% assign latestPost_day = site.posts.first.date | date: "%j" | plus: 0 %}
{% assign latestPost_day_minus_week = site.posts.first.date | date: "%j" | minus: 7 %}
{%- for post in site.posts -%}
{% assign postYear = post.date | date: "%Y" %}
{% assign postDay = post.date | date: "%j" | plus: 0 %}
{%- if latestPost_year == postYear and postDay > latestPost_day_minus_week and postDay <= latestPost_day -%}
{{ post.title }}
{%- endif -%}
{%- endfor -%}
The above solution works, but doesn't span years.
So I utilized the concepts and came up with a simpler and more flexible solution for filtering for a timeframe (which can be any variable time span of seconds, hours, days, weeks, or months). My solution has fewer variables, and less logic.
Liquid date/time uses unix timestamp (%s = seconds since 1970). So I kept the timeframe in seconds and do the conversion for the length of time. 86400 = 1 day, 604800 = 1 wk, 2678400 = 31 days, ... and so on.
The code also assumes your posts use last_modified_at in your post frontmatter. You could substitute for post.date if you're not.
Simple Solution
List posts within last week
{% assign timeframe = 604800 %}
{% for post in site.posts %}
{% assign post_in_seconds = post.last_modified_at | date: "%s" | plus: 0 %}
{% assign recent_posts = "now" | date: "%s" | minus: timeframe %}
{% if post_in_seconds > recent_posts %}
{{ post.title }}
{% endif %}
{% endfor %}
Alternative
List posts within timeframe and flag new or modified
This code will list all posts to within a limit and flag an posts as new or modified in timeframe. Length of list is limited to maxposts. Note: css class is designed to utilize Bootstrap, remove/edit to your liking.
timeframe 2419200 = seconds in 4 weeks
maxposts = 10
label_FOOBAR just clean way to handle html with liquid
Example Results with new/modified flags & dates
Code
{% assign timeframe = 2419200 %}
{% assign maxposts = 10 %}
{% assign date_format = site.minima.date_format | default: "%m/%d" %}
<ul class="post-list text-muted list-unstyled">
{% for post in site.posts limit: maxposts %}
{% assign post_in_seconds = post.last_modified_at | date: "%s" | plus: 0 %}
{% assign recent_posts = "now" | date: "%s" | minus: timeframe %}
{% assign post_updated = post.last_modified_at | date: date_format %}
{% capture post_date %}<small>{{ post.date | date: date_format }}</small>{% endcapture %}
{% if post_in_seconds > recent_posts %}
{% capture label_new %}<span class="label label-primary">new</span>{% endcapture %}
{% if post.last_modified_at > post.date %}
{% assign label_new = '' %}{% comment %}Clear NEW if modified{% endcomment %}
{% capture label_updated %}<span class="label label-info">Updated <span class="badge">{{ post_updated }}</span></span>{% endcapture %}
{% endif %}
{% endif %}
<li>
<h4>{{ post_date }}
<a class="post-link" href="{{ post.url | relative_url }}">
{{ post.title | escape }}</a> {{ label_new }}{{ label_updated }}
</h4>
</li>
{% assign post_date = '' %}
{% assign label_updated = '' %}
{% endfor %}
</ul>
You never know when Jekyll builds, so Jekyll should output a big(ger) list of posts. You can use the code of Joonas for this. Then you should use javascript to hide the non-relevant posts (those older than one week).
This can easily be done by adding a custom attribute to your list, like this:
<li date="{{ post.date }}">{{ post.title }}</li>
Use jQuery (or vanilla js) to hide old posts:
// loop through all list items with a date
$('li[date]').each(function(){
// create a postDate in a date object
var postDate = new Date($(this).attr('date'));
// create an object with the date of one week ago
var oneWeekAgo = new Date();
oneWeekAgo.setDate(oneWeekAgo.getDate() - 7);
// compare dates and hide old posts
if(postDate<oneWeekAgo) $(this).hide();
});

Can you assign date to a variable in jekyll?

This is what I'm currently attempting, however it does not process...
{% assign current_month = {{ site.time | date: '%m' }} %}
Remove extra brackets :
{% assign current_month = site.time | date: '%m' %}
How did you use the variable?
{% assign current_month = {{ site.time | date: '%m' }} %}
{{ current_month }}
Will out put the current month.

How do I add a parameter dynamically to jekyll-timeago plugin?

This seems like a really trivial problem, but I can't seem to make it work.
I'm trying to add jekyll-timeago plugin to jekyll. In the example docs, it says that if I wanted to add a parameter, I can do this:
{{ page.date | timeago: '2020-1-1' }}
But what if my parameter is a variable? Here is my code:
{% if exp.durationEnd == 'Present' %}
{% assign endDate = site.time %}
{% else %}
{% assign endDate = exp.durationEnd %}
{% endif %}
<div>{{ exp.durationStart }} – {{ exp.durationEnd }} ( {{ exp.durationStart | timeago: '{{ endDate }}' }} ) </div>
I can't seem to make it work. Extra emphasis on:
{{ exp.durationStart | timeago: '{{ endDate }}' }}
The code results in:
2 years and 8 months' }} with that extra ' }} which I think is wrong.
I have tried various expressions like the following but to no avail:
{{ exp.durationStart | timeago: endDate }}
{{ exp.durationStart | timeago: '{% endDate %}' }}
{% assign endDate = timeago exp.durationStart site.time %}
nvm.. I got it.
{{ exp.durationStart }} – {{ exp.durationEnd }} ( {{ exp.durationStart | timeago : endDate }} )

Jekyll: Looping with expired Dates

So I'm trying to show the latest 5 upcoming events. I'm pulling everything form a data file. But I noticed that when an event expires and remains in the data file, that the homepage is showing 5 minus the amount of expired events.
For example, if there was 1 event that was expired the homepage would only show 4 of the upcoming events, instead of skipping the expired event and looping. Can anyone help? Thanks!
{% assign eventPost = site.data.events | sort: 'date' %}
{% for event in eventPost limit:5 %}
{% assign curDate = site.time | date: '%Y-%m-%d' %}
{% assign postStartDate = event.date | date: '%Y-%m-%d' %}
{% if postStartDate >= curDate %}
<div class="content--block">
<div class="event--info">
<p class="content--date">{{ event.date | date: '%B %-d, %Y' }}</p>
<h3 class="content--title">{{ event.title }}</h3>
{% if event.time %}
<p class="content--location"><strong>{{ event.location }}</strong> at <strong>{{ event.time }}</strong></p>
{% else %}
<p class="content--location"><strong>{{ event.location }}</strong></p>
{% endif %}
{% if event.subheader %}
<p class="content--description">{{ event.subheader }}</p>
{% endif %}
</div>
{% if event.button == true %}
<button class="outline">Attend</button>
{% endif %}
</div>
{% endif %}
{% endfor %}
{% for event in eventPost limit:5 %} instructs liquid to create a temporary array with 5 first eventPost elements. Your loop is definitely looping over 5 elements and no more.
Use a counter instead. Note, I've sniped code in the print loop for brevity.
{% assign eventPost = site.data.events | sort: 'date' %}
{% assign eventsNumber = 5 %}
{% assign printedEvents = 0 %}
{% for event in eventPost %}
{% assign curDate = site.time | date: '%Y-%m-%d' %}
{% assign postStartDate = event.date | date: '%Y-%m-%d' %}
{% if (postStartDate >= curDate) and (printedEvents < eventsNumber) %}
{% assign printedEvents = printedEvents | plus: 1 %}
<p>{{ event.date | date: '%B %-d, %Y' }} - {{ event.title }}</p>
{% endif %}
{% endfor %}
You then just have to change the eventsNumber to change number of printed events.