Netlify-cms: Datetime widget incorrectly parses dates without times

Created on 21 Apr 2020  路  11Comments  路  Source: netlify/netlify-cms

I have a field that I would like to contain just a date (with no specific time). I saw that the date widget is deprecated, so I reached for the datetime widget. When I configure the datetime widget with sensible options for a date-only field, dates are stored properly in the saved markdown, but when I load those dates in the UI, I see the date before.

I think this is happening because the DateTime component from the react-datetime library is using local timezones. It loads the date as the start of day UTC and then converts to the local timezone, which is going to be the previous day in any timezone with a negative UTC offset, including all of the Americas.

Is there a supported way to have a date-only field in Netlify CMS, or is this a bug?

I see that the react-datetime API has a utc option, which may be helpful here.

Reproduction steps

  1. Click the "Deploy to Netlify" button for Hugo Site Starter on the Start with a Template page in the docs.
  2. Update the configuration for the date field on a post to store just a date.
-       - {label: "Publish Date", name: "date", widget: "datetime"}
+       - {label: "Publish Date", name: "date", widget: "datetime", format: "YYYY-MM-DD", timeFormat: false}
  1. Create and save a new post through the CMS with a Publish Date of 2020-04-20. Note that this will be persisted correctly as 2020-04-20 in the generated markdown.
  2. Refresh the page, see that the CMS UI has loaded the Publish Date as 2020-04-19.
good first issue bug

All 11 comments

@erezrokah can i work on it ?

I started digging into this a little bit. I think if we want the <DateTime> component to automatically use UTC for date-only formats, we'd need some way to identify when format doesn't contain any time elements. I'm not sure the best way to do that, given that there are so many ways to define formats with moment.js tokens.

I'm curious what sort of appetite we'd have for allowing the datetime widget to accept an optional pickerUtc option. It would default to false, but when it's true, we'd instantiate the <DateTime> component with utc: true. I don't love the idea of adding a new option, but it seems more explicit and resilient than trying to do some magic with the format option.

What do you think?

This will require some digging into, comparing the implementation of the two widgets and making sure we don't break existing behaviour.
With that said @MohamedBechir thank you for suggesting. I've assigned you to the issue, please share your thoughts/findings here as @nholden had a good suggestion.
I think this boils down to "what should we do when the persisted value doesn't contain timezone information?"

I think this boils down to "what should we do when the persisted value doesn't contain timezone information?"

In the context of the datetime widget UI, I think what we may be concerned with is "what should we do when the persisted value doesn't contain time."

From my understanding, the <DateTime> component used in the datetime widget UI will only use your local timezone or UTC (when we pass in the utc: true option). It will translate times persisted in other timezones to your local timezone or UTC, but it won't display the persisted timezone.

馃憢 Hi, @MohamedBechir! Have you started digging into this one yet? I'm happy to try opening a PR sometime this week if you don't have the chance.

Hi @nholden, I've assigned you to that issue, thanks! @MohamedBechir we have plenty of other possible contributions to be made, so let me know if you have something in mind.

I have been investigating another datetime related issue but I thought it was worth sharing it with you.

De-serialization is delegated to https://www.npmjs.com/package/yaml. It generates a Date in memory.

I tried to update the in-memory value in the widget but it set the entry as dirty (it triggers a DRAFT_CHANGE_FIELD action).

My context:

I have

name: Cool product
start: 2019-03-07 # in YAML this is not a string, this is a timestamp

with a

fields:
- label: Nom
  name: title
  widget: string
- label: Start
  name: start
  widget: datetime
  format: YYYY-MM-DD
  dateFormat: YYYY-MM-DD
  timeFormat: false
  default: ''

When I update the string the date get persisted as 2019-03-07T00:00:00.000Z because that value is never touched.

Maybe registerWidgetValueSerializer should be used to ensure that dates also get touched and appropriately serialized.

Thanks for all the work on this, we're experiencing this bug and it's setting some important dates off unexpectedly for authors.

Do you have a workaround that's working for you @nholden ?

For me, this seems to be working:

label: "Publish Date"
name: "date"
widget: "datetime"
timeFormat: false
dateFormat: "YYYY-MM-DD"
format: "LLL"

Authors just see a date input, the format is saved as 00:00 time, with no zone. The output is the same date as expected, essentially as floating time / no zone.

Update

Apologies, I got confused here. I've followed your implementation @nholden and it works for us in a +1100 time zone.

Hi, is this the correct issue to follow if I'm trying to shorten the dates the CMS outputs to just year, month and date? (date: 2019-08-31)

@raniesantos I would recommend you #3702. There, I shared a hack to get the output you want.

Thanks for sharing, @guillett! As I've dug into the datetime widget and the underlying <DateTime> picker component, I've been reminded that time is really complicated. 馃槄

I think it was a good call to open up the separate https://github.com/netlify/netlify-cms/issues/3702 issue for what you described. If you have any specific questions as you dig in, feel free to @ me, and I'd be happy to take a look and share anything relevant that I've learned.

In the meantime, I just opened https://github.com/netlify/netlify-cms/pull/3721 to address the specific issue I described in the original description.

Was this page helpful?
0 / 5 - 0 ratings