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

Incorrect timezone conversion for 'date' frontmatter #1615

Open
linusrachlis opened this issue Nov 24, 2024 · 1 comment · May be fixed by #1646
Open

Incorrect timezone conversion for 'date' frontmatter #1615

linusrachlis opened this issue Nov 24, 2024 · 1 comment · May be fixed by #1646
Labels
bug Something isn't working

Comments

@linusrachlis
Copy link

linusrachlis commented Nov 24, 2024

Describe the bug
If you specify the date frontmatter value in ISO format (e.g. 2024-11-16) with no time (the default format for Obsidian 'date' file property), the JS Date() constructor in coerceDate (link) interprets that as midnight UTC on the day given, whereas most other formats get interpreted in the local timezone.

When the time zone offset is absent, date-only forms are interpreted as a UTC time and date-time forms are interpreted as a local time. The interpretation as a UTC time is due to a historical spec error that was not consistent with ISO 8601 but could not be changed due to web compatibility.
-- MDN

The result for me (eastern timezone, GMT-5/-4) is that if I specify a date file prop in Obsidian, the resulting page built by Quartz shows the date as the previous day to the one I specified.

To Reproduce
Steps to reproduce the behavior:

  1. Have your system time set at a negative GMT offset.
  2. Make a page under content/ with an ISO format date in the frontmatter, e.g. date: 2024-11-16
  3. npx quartz build --serve
  4. Look at the built page: it shows "Nov 15, 2024"

Expected behavior
If the frontmatter date is specified with no time component, it should show as the same day in the built page.

Screenshots and Source
Screenshot 2024-11-24 at 11 09 19 AM
Screenshot 2024-11-24 at 11 09 44 AM

Desktop (please complete the following information):

  • Quartz Version: 4.4.0
  • node Version: v22.9.0
  • npm version: 10.8.3
  • OS: MacOS 15.1 (24B83)
  • Browser: Firefox 132.0.2 (aarch64)

Additional context

Here's a demo of the basic problem:

❯ node
Welcome to Node.js v22.9.0.
Type ".help" for more information.
> (new Date('2024-11-16')).toLocaleDateString()
'2024-11-15'
> (new Date('2024-11-16 00:00')).toLocaleDateString()
'2024-11-16'
> (new Date('Nov 16, 2024')).toLocaleDateString()
'2024-11-16'

Here is a draft PR illustrating the fix I'm using in my own version: #1614

⚠️ However, I don't think this is actually a good solution for Quartz itself, because (a) it's hacky, and (b) I'm not confident that the interpretation of strings by the Date constructor is guaranteed to be consistent for all platforms.

A better fix might involve adding a datetime library to the project, but I'm new to Quartz so I don't have a very valuable opinion here.

Hope this was helpful, and thanks so much for working on this great project ❤️

@linusrachlis linusrachlis added the bug Something isn't working label Nov 24, 2024
@baodrate
Copy link
Contributor

I think this also reveals a need for two things:

  • setting a timezone at the application level
    • currently, if an offset isn't sepciied in the timestamp, the system local timezone is used (in certain cases, as illuminated by this issue)
    • setting the system timezone is workable but unergonomic, and harder to document along with the vault. and semantically, the timezone of the machine generating the site is not equal tot he timezone of the site contents
  • persistence of timezone/offset information in the timestamps. javascript's built-in Date type doesn't store timezone information. the string it gets correctly parsed but all Date are UTC.

I think including a datetime library (like Luxon) is the way to go. benefits are:

  • more "correct"/obvious behavior (particularly Date's poor API as highlighted by this issue)
  • more consistent with Obsidian's behavior (obsidian uses Moment.js, which is succeeded by Luxon)
  • more consistent with the user's data

baodrate added a commit to baodrate/quartz that referenced this issue Dec 11, 2024
Use Luxon to parse date/datetime strings.

This avoids the `Date.parse`'s inconsistency between date-only (assumed
UTC) and datetime (assumed local timezone) strings. (closes jackyzha0#1615)

It also allows the date string's timezone to be carried along with the
DateTime object, producing more friendly and semantically-correct
timestamps.
baodrate added a commit to baodrate/quartz that referenced this issue Dec 11, 2024
Use Luxon to parse date/datetime strings.

This avoids the `Date.parse`'s inconsistency between date-only (assumed
UTC) and datetime (assumed local timezone) strings. (closes jackyzha0#1615)

It also allows the date string's timezone to be carried along with the
DateTime object, producing more friendly and semantically-correct
timestamps.
@baodrate baodrate linked a pull request Dec 11, 2024 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants