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

new: LiquidOptions.dateFormat to override default date format #587

Merged
merged 1 commit into from
Feb 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
99 changes: 44 additions & 55 deletions docs/source/filters/date.md
Original file line number Diff line number Diff line change
@@ -1,77 +1,66 @@
---
title: date
---

{% since %}v1.9.1{% endsince %}

Converts a timestamp into another date format. LiquidJS tries to be conformant with Shopify/Liquid which is using Ruby's core [Time#strftime(string)](http://www.ruby-doc.org/core/Time.html#method-i-strftime). The input is firstly converted to `Date` object via [new Date()][newDate].

Input
# Format
* Converts a timestamp into another date format
* LiquidJS tries to be conformant with Shopify/Liquid which is using Ruby's core [Time#strftime(string)](http://www.ruby-doc.org/core/Time.html#method-i-strftime)
* Refer [format flags](https://ruby-doc.org/core/strftime_formatting_rdoc.html)
* Not all options are supported though - refer [differences here](/tutorials/differences.html#Differences)
* The input is firstly converted to `Date` object via [new Date()][jsDate]
* Date format can be provided individually as a filter option
* If not provided, then `%A, %B %-e, %Y at %-l:%M %P %z` format will be used as default format
* Override this using [`dateFormat`](/api/interfaces/liquid_options_.liquidoptions.html#Optional-dateFormat) LiquidJS option, to set your preferred default format for all date filters

### Examples
```liquid
{{ article.published_at | date: "%a, %b %d, %y" }}
```
{{ article.published_at | date: '%a, %b %d, %y' }} => Fri, Jul 17, 15
{{ "now" | date: "%Y-%m-%d %H:%M" }} => 2020-03-25 15:57

Output
```text
Fri, Jul 17, 15
// equivalent to setting options.dateFormat = %d%q of %b %Y at %I:%M %P %Z
{{ '1990-12-31T23:30:28Z' | date: '%d%q of %b %Y at %I:%M %P %Z', -330 }} => 01st of Jan 1991 at 05:00 am +0530;
```

{% note info TimeZone %}
Date will be converted to local time before output. To avoid that, you can set `timezoneOffset` LiquidJS option to `0`, its default value is your local timezone offset which can be obtained by `new Date().getTimezoneOffset()`.
{% endnote %}

And you can set a timezone for each individual `date` filter via the second parameter:

Input
# TimeZone
* By default, dates will be converted to local timezone before output
* You can override that by,
* setting a timezone for each individual `date` filter via the second parameter
* using the [`timezoneOffset`](/api/interfaces/liquid_options_.liquidoptions.html#Optional-timezoneOffset) LiquidJS option
* Its default value is your local timezone offset which can be obtained by `new Date().getTimezoneOffset()`
* Offset can be set as,
* minutes: `-360` means `'+06:00'` and `360` means `'-06:00'`
* timeZone ID: `Asia/Colombo` or `America/New_York`
* Use minutes for better performance with repeated processing of templates with many dates like, converting template for each email recipient
* Refer [here](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) for TZ database values

### Examples
```liquid
{{ "1990-12-31T23:00:00Z" | date: "%Y-%m-%dT%H:%M:%S", 360}} // equivalent to setting `options.timezoneOffset` to `360`.
{{ "1990-12-31T23:00:00Z" | date: "%Y-%m-%dT%H:%M:%S", "Asia/Colombo" }}
// equivalent to setting `options.timezoneOffset` to `360`
{{ "1990-12-31T23:00:00Z" | date: "%Y-%m-%dT%H:%M:%S", 360 }} => 1990-12-31T17:00:00
{{ "1990-12-31T23:00:00Z" | date: "%Y-%m-%dT%H:%M:%S", "Asia/Colombo" }} => 1991-01-01T04:30:00
```

Output
```liquid
1990-12-31T17:00:00
1991-01-01T04:30:00
```

Input
```liquid
{{ article.published_at | date: "%Y" }}
```
# Input
* `date` works on strings if they contain well-formatted dates
* Note that LiquidJS is using [JavaScript Date][jsDate] to parse the input string, that means [IETF-compliant RFC 2822 timestamps](https://datatracker.ietf.org/doc/html/rfc2822#page-14) and strings in [a version of ISO8601](https://www.ecma-international.org/ecma-262/11.0/#sec-date.parse) are supported.

Output
```text
2015
```

`date` works on strings if they contain well-formatted dates:

Input
### Examples
```liquid
{{ "March 14, 2016" | date: "%b %d, %y" }}
```

Output
```text
Mar 14, 16
{{ "1990-12-31T23:00:00Z" | date: "%Y-%m-%dT%H:%M:%S", 360 }} => 1990-12-31T17:00:00
{{ "March 14, 2016" | date: "%b %d, %y" }} => Mar 14, 16
```

{% note info Timestamp Strings %}
Note that LiquidJS is using JavaScript [Date][newDate] to parse the input string, that means [IETF-compliant RFC 2822 timestamps](https://datatracker.ietf.org/doc/html/rfc2822#page-14) and strings in [a version of ISO8601](https://www.ecma-international.org/ecma-262/11.0/#sec-date.parse) are supported.
{% endnote %}

To get the current time, pass the special word `"now"` (or `"today"`) to `date`:
# Current Date
* To get the current time, pass the special word `"now"` or `"today"` as input
* Note that the value will be the current time of when the page was last generated from the template, not when the page is presented to a user if caching or static site generation is involved

Input
### Example
```liquid
This page was last updated at {{ "now" | date: "%Y-%m-%d %H:%M" }}.
```

Output
```text
This page was last updated at 2020-03-25 15:57.
Last updated on: {{ "now" | date: "%Y-%m-%d %H:%M" }} => Last updated on: 2020-03-25 15:57
Last updated on: {{ "today" | date: "%Y-%m-%d %H:%M" }} => Last updated on: 2020-03-25 15:57
```

{% note info now %}Note that the value will be the current time of when the page was last generated from the template, not when the page is presented to a user if caching or static site generation is involved.{% endnote %}

[newDate]: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Date
[jsDate]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date
2 changes: 2 additions & 0 deletions docs/source/tutorials/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ it defaults to false. For example, when set to true, a blank string would evalu

**preserveTimezones** is a boolean effects only literal timestamps. When set to `true`, all literal timestamps will remain the same when output. This is a parser option, so Date objects passed to LiquidJS as data will not be affected. Note that `preserveTimezones` has a higher priority than `timezoneOffset`.

**dateFormat** is used to specify a default format to output dates. `%A, %B %-e, %Y at %-l:%M %P %z` will be used if not specified. For example, set `dateFormat: %Y-%m-%dT%H:%M:%S:%LZ` to output all dates in [JavaScript Date.toJson()][https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toJSON] format.

## Trimming

**greedy**, **trimOutputLeft**, **trimOutputRight**, **trimTagLeft**, **trimTagRight** options are used to eliminate extra newlines and indents in templates around Liquid Constructs. See [Whitespace Control][wc] for details.
Expand Down
1 change: 1 addition & 0 deletions docs/source/zh-cn/tutorials/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ LiquidJS 把这个选项默认值设为 <code>true</code> 以兼容于 shopify/l

**preserveTimezones** 是一个布尔值,只影响时间戳字面量。当设置为 `true` 时,所有字面量的时间戳字符串会在输出时保持原状,即不论输入时采取怎样的时区,输出时仍然采用那一时区(和 Shopify Liquid 的行为一致)。注意这是一个解析器参数,渲染时传入的数据中的日期的输出不会受此参数影响。注意 `preserveTimezones` 比 `timezoneOffset` 的优先级更高。

**dateFormat** 用于指定输出日期的默认格式. `%A, %B %-e, %Y at %-l:%M %P %z` 如果未指定,将使用. 例如,设置 `dateFormat: %Y-%m-%dT%H:%M:%S:%LZ` 以输出 [JavaSrcipt Date.toJson()][https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Date/toJSON] 格式.

## 换行和缩进

Expand Down
2 changes: 1 addition & 1 deletion src/filters/date.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export function date (this: FilterImpl, v: string | Date, format?: string, timez
let date: LiquidDate
v = toValue(v)
format = toValue(format)
if (isNil(format)) format = DEFAULT_FMT
if (isNil(format)) format = opts.dateFormat ?? DEFAULT_FMT
else format = stringify(format)
if (v === 'now' || v === 'today') {
date = new Date()
Expand Down
2 changes: 2 additions & 0 deletions src/liquid-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ export interface LiquidOptions {
lenientIf?: boolean;
/** JavaScript timezone name or timezoneOffset for `date` filter, default to local time. That means if you're in Australia (UTC+10), it'll default to `-600` or `Australia/Lindeman` */
timezoneOffset?: number | string;
/** Default date format to use if the date filter doesn't include a format. Defaults to `%A, %B %-e, %Y at %-l:%M %P %z`. */
dateFormat?: string;
/** Strip blank characters (including ` `, `\t`, and `\r`) from the right of tags (`{% %}`) until `\n` (inclusive). Defaults to `false`. */
trimTagRight?: boolean;
/** Similar to `trimTagRight`, whereas the `\n` is exclusive. Defaults to `false`. See Whitespace Control for details. */
Expand Down
18 changes: 18 additions & 0 deletions test/integration/filters/date.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,22 @@ describe('filters/date', function () {
return test('{{ "1990-12-31T23:00:00+02:30" | date: "%Y-%m-%dT%H:%M:%S"}}', '1990-12-31T23:00:00', undefined, opts)
})
})
describe('dateFormat', function () {
const optsWithoutDateFormat: LiquidOptions = { timezoneOffset: 360 } // -06:00
// date.DEFAULT_FMT: '%A, %B %-e, %Y at %-l:%M %P %z'
it('should use default format for date filters without format argument', function () {
return test('{{ "2022-12-08T03:22:18.000Z" | date }}', 'Wednesday, December 7, 2022 at 9:22 pm -0600', undefined, optsWithoutDateFormat)
})
it('should use given date filter format argument and NOT default format', function () {
return test('{{ "1990-12-31T23:00:00Z" | date: "%Y-%m-%dT%H:%M:%S" }}', '1990-12-31T17:00:00', undefined, optsWithoutDateFormat)
})

const optsWithDateFormat: LiquidOptions = { timezoneOffset: -330, dateFormat: '%d%q of %b %Y at %I:%M %P' } // -06:00, 31st of Dec 1990 at 11:00 pm
it('should use configured `options.dateFormat` for date filters without format argument', function () {
return test('{{ "2022-12-08T13:30:18.000Z" | date }}', '08th of Dec 2022 at 07:00 pm', undefined, optsWithDateFormat)
})
it('should use given date filter format argument and NOT `options.dateFormat`', function () {
return test('{{ "1990-12-31T23:00:00Z" | date: "%Y-%m-%dT%H:%M:%S" }}', '1991-01-01T04:30:00', undefined, optsWithDateFormat)
})
})
})